I'm working on a form that's in a tsx component, and i wanna handle the form submit on server and send a email to the user using resend, the resend instance requires a secret key from env. it tired putting it on action but it says actions require output mood to be set to "server" but i don want the page to be server rendered i want the page to be statictly rendered and just make the form submission server handles
#prerender every page expect for api route / action
4 messages · Page 1 of 1 (latest)
Hi @pliant sigil. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Great news — you don't need output: 'server' for your entire site to handle form submissions on the server. You can keep your pages statically rendered and only opt specific API routes into on-demand rendering.
The Approach: API Route with prerender = false
Create a POST API endpoint (e.g., src/pages/api/send-email.ts) and export export const prerender = false from it. This makes only that route server-rendered on demand, while the rest of your site remains static. [On-demand rendering]
Note: You still need a server adapter installed in your project for any on-demand rendering to work, even if most pages are static.
1. Create the API Route
// src/pages/api/send-email.ts
export const prerender = false; // Only this route is server-rendered
import type { APIRoute } from "astro";
export const POST: APIRoute = async ({ request }) => {
const data = await request.formData();
const name = data.get("name");
const email = data.get("email");
const message = data.get("message");
// Validate the data
if (!name || !email || !message) {
return new Response(
JSON.stringify({ message: "Missing required fields" }),
{ status: 400 }
);
}
// Use your secret key from env here (server-side only, safe!)
// const resend = new Resend(import.meta.env.RESEND_API_KEY);
// await resend.emails.send({ ... });
return new Response(
JSON.stringify({ message: "Email sent successfully!" }),
{ status: 200 }
);
};
2. Create Your TSX Form Component
Your form component intercepts the submit event and POSTs to the API route using fetch:
// src/components/ContactForm.tsx
import { useState } from "react";
import type { FormEvent } from "react";
export default function ContactForm() {
const [responseMessage, setResponseMessage] = useState("");
async function submit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
const response = await fetch("/api/send-email", {
method: "POST",
body: formData,
});
const data = await response.json();
if (data.message) {
setResponseMessage(data.message);
}
}
return (
<form onSubmit={submit}>
<label htmlFor="name">Name
<input type="text" id="name" name="name" required />
</label>
<label htmlFor="email">Email
<input type="email" id="email" name="email" required />
</label>
<label htmlFor="message">Message
<textarea id="message" name="message" required />
</label>
<button>Send</button>
{responseMessage && <p>{responseMessage}</p>}
</form>
);
}
Summary
- Your pages remain fully static (
output: 'static', the default). - Only the API route at
/api/send-emailis server-rendered by addingexport const prerender = false. - Your Resend secret key stays safely on the server inside the API route.
- You still need a server adapter installed for the on-demand route to work.