AI builder // v0

Wire your v0 form to email in one step

v0 by Vercel is superb at generating shadcn/ui forms. Because those forms are usually dropped into Next.js, you have two clean options: a client-side fetch, or a one-function Server Action that forwards to the endpoint. Either way you skip building and securing a route handler.

The short answer

v0 produces the form component but no backend, so submissions have nowhere to go. Point the form at a MakeTheForm endpoint, or use a tiny Server Action that forwards to it, and each submission is spam-filtered, emailed to you, and saved in a searchable inbox with no route handler to build.

The minimal integration

v0 output lands in Next.js. This Server Action forwards the submission to your endpoint: no /api route, no database. A plain client-side fetch works too if the form is a client component.

Next.js
// app/contact/actions.ts
'use server';

export async function submitContact(prevState, formData) {
  const response = await fetch('https://mtform.co/f/your-form-key', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(Object.fromEntries(formData)),
  });

  const result = await response.json();

  if (!response.ok) {
    return { ok: false, message: result.error?.message ?? 'Unable to send your message.' };
  }

  return { ok: true, message: 'Thanks. We got your message.' };
}

// app/contact/page.tsx
'use client';
import { useActionState } from 'react';
import { submitContact } from './actions';

export default function ContactPage() {
  const [state, action, pending] = useActionState(submitContact, null);

  return (
    <form action={action}>
      <input name="name" placeholder="Name" required />
      <input type="email" name="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />
      <input name="_mtf_honeypot" tabIndex={-1} autoComplete="off" aria-hidden="true"
             style={{ position: 'absolute', left: '-9999px' }} />

      <button type="submit" disabled={pending}>{pending ? 'Sending…' : 'Send'}</button>
      {state && <p role={state.ok ? 'status' : 'alert'}>{state.message}</p>}
    </form>
  );
}

A Server Action: no API route needed. Returns a serializable result the form renders inline.

Step by step

  1. 01

    Create the endpoint

    Create a MakeTheForm form to get your endpoint URL and inbox.

  2. 02

    Generate in v0, then wire it

    Keep your v0-generated form and paste the prompt above. It adds a Server Action (or fetch) that forwards to your endpoint.

  3. 03

    Verify and ship

    Verify the recipient once, deploy to Vercel, and submit to confirm the inbox and email delivery.

Copy this prompt into your AI builder

Paste it as-is. It pins the exact endpoint, spam field, and success/error behavior so the agent wires the form correctly instead of inventing a backend or leaking a key.

AI builder prompt
Wire the contact form in this v0 / Next.js project to this MakeTheForm endpoint:

https://mtform.co/f/your-form-key

Requirements:
- Prefer a Server Action that forwards the fields to the endpoint via fetch as JSON. Do NOT create a database or a custom /api route beyond the action itself.
- Keep the existing shadcn/ui markup and styling. Only add submit wiring.
- Disable the submit button while pending (useActionState / pending state).
- Treat any HTTP 2xx as success: show an inline success message and reset the form.
- On error, surface the JSON response’s error.message and keep the user’s input.
- Include a hidden honeypot input named exactly "_mtf_honeypot" (position:absolute;left:-9999px, tabIndex={-1}, autoComplete="off", aria-hidden="true"). Never display:none, never required.
- The endpoint URL is public and safe in client code. Do NOT invent or request an API key.

Common pitfalls

Building a full /api route + Resend

v0 will offer to add a route handler and an email SDK. That’s a mail integration and a deliverability reputation to manage. Forwarding from a one-line Server Action to the endpoint avoids all of it.

Client component vs Server Action mismatch

If the form is a client component, a Server Action still works when imported, but a plain fetch is simpler. Don’t mix a "use server" action into a "use client" file directly, import it.

Troubleshooting

Troubleshooting by error code
SymptomWhat is happeningFix
action not firingThe form uses onSubmit instead of the Server Action’s action prop.Bind the action to <form action={...}> or call the action from your submit handler.
422A required field configured on the form wasn’t sent.Check the field names match your form config; the JSON error lists the offending field.

Frequently asked questions

Does v0 handle form submissions?

v0 generates the form UI (usually shadcn/ui) but not a backend. To actually receive submissions you either add server code or point the form at a hosted endpoint: the endpoint handles email, spam, and storage for you.

Should I use a Server Action or a client fetch?

Either works. A Server Action keeps the endpoint call server-side and pairs well with useActionState for pending UI; a client fetch is the least code. Both forward to the same endpoint.

Do I need a database for a v0 form?

No. The endpoint stores each submission in a searchable, exportable inbox, so a contact or lead form needs no database of your own.

Ship this form for real

Create an endpoint, paste it in, and watch the first submission land in your inbox, in under three minutes.

Create free endpoint