#prerender every page expect for api route / action

4 messages · Page 1 of 1 (latest)

pliant sigil
#

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

winter gyroBOT
#

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 }
  );
};

[API routes]

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>
  );
}

[Build forms with API routes]

Summary

  • Your pages remain fully static (output: 'static', the default).
  • Only the API route at /api/send-email is server-rendered by adding export 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.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: