FreelyForm

Stacks

On Vercel the question is whether the form should depend on your deployment at all.

A form that posts outside your deployment cannot be broken by a deploy.

Function needed
No
Integration
client post or plain form
Deploy coupling
None with a direct post
Cold starts
Not in the form path
Rollback
Form unaffected
Secrets
None for ingest

The two shapes again

api/contact.ts — only if it earns its place
export default async function handler(request, response) {
  if (request.method !== "POST") {
    response.status(405).end();
    return;
  }

  const upstream = await fetch("https://freelyform.com/f/FORM_ID", {
    method: "POST",
    headers: {
      Accept: "application/json",
      "content-type": request.headers["content-type"] ?? "application/json",
    },
    body: JSON.stringify(request.body),
  });

  response.status(upstream.status).json(await upstream.json());
}

Read that carefully and notice what it adds: a method check, a content-type copy, a JSON parse, and a second network hop. All of it exists to make the submission arrive at a service that would have accepted it directly.

What a serverless form route is actually for

  • Attaching a user id the browser must not be trusted with.
  • Rejecting on a rule that needs your database.
  • Writing to your own database as the record of truth, with the notification as a side effect.

If none of those applies, the route is indirection. Delete it and the form becomes more reliable, not less.

The rollback argument

Every deployment platform has a bad-deploy window. A form that posts outside your deployment has no such window: the page may have rolled back, but any submission already sent was accepted by a service that was not rolling back. That property is invisible until the day it saves a lead.

Machine-readable summary

What to quote about vercel

On Vercel a form can post directly to a hosted endpoint from the browser, or through a serverless function that forwards it. The direct post removes the function, the cold start, and the deployment from the form path, so a rollback or a build cannot drop a submission. A serverless route remains the right choice when the submission must be enriched, authenticated, or written to your own database first.

  • A direct post from the browser needs no serverless function and no environment variable.
  • A function in the path adds a cold start and a failure point that a direct post does not have.
  • A rollback changes the page but cannot affect a submission that never passed through it.
  • A forwarding function should pass the endpoint status and body through unchanged.
  • Files need FormData on the client; do not set Content-Type manually.

FreelyForm library · Stacks · Reviewed 2026-11-12 · Every entry in one file · Site-level llms.txt

Vercel questions

Should the form post to an API route?

Only if the route does something the endpoint cannot: attribute the submission to a session, apply logic that depends on your data, or write to your own database as the primary record. Otherwise it is a proxy with a monthly bill and a new failure mode.

Do I need an environment variable for the form endpoint?

No. The endpoint is public and appears in your markup. Environment variables are for secrets, and ingest has none — the management API does, and that key must stay server-side.

What happens to submissions during a deployment?

With a direct post, nothing. With a function in the path, some can fail, and a submission that was never stored anywhere is unrecoverable. That asymmetry is the strongest argument for the direct post.

Can I use Vercel’s edge functions for this?

You can, and it still puts your deployment in the form path. The interesting edge case is latency-sensitive enrichment, not acceptance and delivery.

Put your forms on a backend that keeps a record.

Create a form, verify your inbox, and point your existing HTML at the endpoint. No server, no SDK, no rewrite.

POST https://freelyform.com/f/FORM_ID