Back to Blog
EnglishApril 19, 2026

Next.js Form Handling Without API Routes (2026 Guide)

nextjs formnext.js form handlingform backendreact form

Quick summary

Handle form submissions in Next.js without writing a single API route. Use a form backend to receive, store, and forward every submission with zero backend code.

Every Next.js tutorial tells you the same thing: create an API route at app/api/contact/route.ts, validate the request, connect a database, set up email, handle errors. That works — but it is a lot of boilerplate for something as common as a contact form.

This guide shows you how to handle forms in Next.js without writing any API routes at all.

Why Skip API Routes?

API routes are powerful when you own the logic. But for contact forms, lead capture, and surveys, the logic is always the same: receive data, store it, send a notification. A dedicated form backend handles all of that for you — with spam filtering, a submission dashboard, and integrations included.

Method 1: HTML Form Action (Simplest)

The fastest path — no JavaScript required. Just set your form's action to your Flowqen endpoint:

// app/contact/page.tsx
export default function ContactPage() {
  return (
    <form
      action="https://flowqen.com/api/f/YOUR_FORM_ID"
      method="POST"
    >
      <input name="name" type="text" required placeholder="Name" />
      <input name="email" type="email" required placeholder="Email" />
      <textarea name="message" required placeholder="Message" />
      <input type="hidden" name="_redirect" value="https://yoursite.com/thanks" />
      <input type="text" name="_gotcha" style={{ display: 'none' }} />
      <button type="submit">Send</button>
    </form>
  );
}

Method 2: Client Component with fetch (No Reload)

For a smoother experience, use a "use client" component with fetch:

"use client";
import { useState } from "react";

export default function ContactForm() {
  const [status, setStatus] = useState<"idle" | "sending" | "done">("idle");

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus("sending");
    const data = new FormData(e.currentTarget);
    await fetch("https://flowqen.com/api/f/YOUR_FORM_ID", {
      method: "POST",
      body: data,
      headers: { Accept: "application/json" },
    });
    setStatus("done");
  }

  if (status === "done") {
    return <p>Thanks! We'll get back to you soon.</p>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" type="text" required placeholder="Name" />
      <input name="email" type="email" required placeholder="Email" />
      <textarea name="message" required placeholder="Message" />
      <button type="submit" disabled={status === "sending"}>
        {status === "sending" ? "Sending…" : "Send"}</button>
    </form>
  );
}

Method 3: Next.js Server Actions + Flowqen

If you want to keep everything server-side but still skip writing storage and email logic, combine Server Actions with a Flowqen forwarding call:

// app/contact/actions.ts
"use server";

export async function submitContact(formData: FormData) {
  await fetch("https://flowqen.com/api/f/YOUR_FORM_ID", {
    method: "POST",
    body: formData,
    headers: { Accept: "application/json" },
  });
}
// app/contact/page.tsx
import { submitContact } from "./actions";

export default function ContactPage() {
  return (
    <form action={submitContact}>
      <input name="name" type="text" required />
      <input name="email" type="email" required />
      <textarea name="message" required />
      <button type="submit">Send</button>
    </form>
  );
}

What You Get Without API Routes

  • Spam filtering (honeypot + optional Turnstile)
  • Email notifications on every submission
  • Submission dashboard to search and export leads
  • Integrations: Slack, Discord, Google Sheets, Notion, webhooks
  • Auto-reply emails to the submitter
  • File upload support

Common Questions

FAQ

Is this approach production-safe?

Yes. Flowqen handles rate limiting, spam filtering, and storage. It is used in production across thousands of sites.

Can I still validate on the server side?

Yes — use Zod or your own logic in a Server Action before forwarding to Flowqen, or rely on Flowqen's required-field validation.

What about CORS?

Flowqen's endpoint accepts cross-origin requests from any domain by default, so client-side fetch works without configuration.

Or skip all this and use FlowQen — 2 lines of code, done.

Read next

Related guides to help you implement better forms and improve conversions.

Ready to add forms to your website?

Get started with Flowqen for free. No credit card required.

Create your free account