DEV Community

Cover image for How to Add a Working Contact Form to Next.js Without an API Route

How to Add a Working Contact Form to Next.js Without an API Route

How to Add a Working Contact Form to Next.js Without an API Route with onsubmit.dev (form backend)

If you need a contact form in Next.js, you don't necessarily need to build an API route, deploy a serverless function, configure SMTP, or maintain a database. With onsubmit.dev (form backend), the nextjs-onsubmit package can handle the submission endpoint for you while your app stays focused on the frontend.

The usual Next.js approach

A contact form often starts with some simple JSX:

export default function ContactForm() {
  return (
    <form>
      <input type="text" name="name" placeholder="Your name" />
      <input type="email" name="email" placeholder="you@example.com" />
      <textarea name="message" placeholder="Your message" />
      <button type="submit">Send</button>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

But this doesn't actually send the data anywhere.

One option is to add an API endpoint:

app/
  api/
    contact/
      route.ts
Enter fullscreen mode Exit fullscreen mode

Then you need to parse and validate requests, send an email or Slack notification, handle errors, and potentially add spam protection.

For a simple contact form, that's quite a bit of backend code.

Install nextjs-onsubmit

Instead, install the Next.js package for onsubmit.dev (form backend):

npm install nextjs-onsubmit
Enter fullscreen mode Exit fullscreen mode

The package lets your form submit to a hosted form backend instead of an API route in your own Next.js application.

That means you don't need:

/api/contact
Enter fullscreen mode Exit fullscreen mode

or:

app/api/contact/route.ts
Enter fullscreen mode Exit fullscreen mode

And there's no serverless function to maintain.

Create the contact form

Here's a minimal example:

import { OnSubmitForm } from "nextjs-onsubmit";

export default function ContactForm() {
  return (
    <OnSubmitForm formId="YOUR_FORM_ID" successMessage="Thanks! We'll be in touch.">
      <input
        type="text"
        name="name"
        placeholder="Your name"
        required
      />

      <input
        type="email"
        name="email"
        placeholder="you@example.com"
        required
      />

      <textarea
        name="message"
        placeholder="How can we help?"
        required
      />

      <button type="submit">Send message</button>
    </OnSubmitForm>
  );
}
Enter fullscreen mode Exit fullscreen mode

The important part here is that every value you want included in the submission has a name.

For example:

<input name="email" type="email" />
Enter fullscreen mode Exit fullscreen mode

produces an email field, while:

<textarea name="message" />
Enter fullscreen mode Exit fullscreen mode

produces a message field.

You can therefore add fields without designing a request payload:

<OnSubmitForm formId="YOUR_FORM_ID" successMessage="Thanks! We'll be in touch.">
  <input name="name" required />
  <input name="email" type="email" required />

  <select name="topic">
    <option value="sales">Sales</option>
    <option value="support">Support</option>
    <option value="other">Other</option>
  </select>

  <textarea name="message" required />

  <button type="submit">Submit</button>
</OnSubmitForm>
Enter fullscreen mode Exit fullscreen mode

No Next.js API route required

The useful difference is what you don't have to write.

There's no route handler like this:

export async function POST(request: Request) {
  const body = await request.json();

  // validate input
  // configure email provider
  // send email
  // handle provider failure
  // return response
}
Enter fullscreen mode Exit fullscreen mode

Your Next.js project can remain a frontend application, while onsubmit.dev (form backend) receives and processes the form submission externally.

This is especially handy for sites where forms are infrastructure rather than core application logic: portfolios, landing pages, documentation sites, waitlists, and marketing sites are good examples.

Send submissions to email or Slack

After connecting/configuring your form with the service, submissions can be delivered to the destination you actually monitor.

For email, a submission containing:

name: Ada
email: ada@example.com
topic: sales
message: I'd like to learn more.
Enter fullscreen mode Exit fullscreen mode

can arrive in your inbox without your Next.js application having to integrate with an email API.

If your team works in Slack, you can configure Slack delivery instead, so new form submissions appear in the appropriate channel.

In either case, your frontend remains essentially the same:

Visitor
   ↓
Next.js form
   ↓
Hosted form backend
   ↓
Email / Slack
Enter fullscreen mode Exit fullscreen mode

That separation also means email or Slack credentials don't need to live in client-side code.

Add normal HTML validation

You can still use native browser validation:

<OnSubmitForm formId="YOUR_FORM_ID" successMessage="Thanks! We'll be in touch.">
  <input
    name="name"
    type="text"
    minLength={2}
    required
  />

  <input
    name="email"
    type="email"
    required
  />

  <textarea
    name="message"
    minLength={10}
    maxLength={2000}
    required
  />

  <button type="submit">Send</button>
</OnSubmitForm>
Enter fullscreen mode Exit fullscreen mode

This gives users immediate feedback for common problems while avoiding a custom API endpoint just to receive the successful submission.

For security-sensitive or business-critical applications, remember that client-side validation alone should never be treated as authoritative validation.

When this pattern makes sense

A hosted form backend is a good fit when the purpose of the form is simply to get information from a visitor into email, Slack, or another workflow.

If submissions instead need to trigger application-specific authorization, database transactions, billing operations, or other sensitive business logic, implementing the relevant server-side code yourself will usually make more sense.

For straightforward contact forms, though, removing an otherwise single-purpose API route can make a Next.js project considerably simpler.

That's the idea behind onsubmit.dev (form backend): accept Next.js form submissions without turning a basic contact form into another backend service to build and maintain.

Top comments (0)