Open Form

open-form.config.ts

Project-wide configuration with defineConfig.

The project config lives at the workspace root. Every key is optional. Unlike a form's config, it never reaches the browser, so it's the place for webhook URLs and anything else that shouldn't be public.

open-form.config.ts
import { defineConfig } from '@open-form-build/core';

export default defineConfig({
  locale: 'zh-TW',
  timeZone: 'Asia/Taipei',
});

open-form init writes this file with timeZone set to your computer's time zone. It loads as ESM whether or not your package.json is "type": "module", so it also works at the root of an existing app.

process.env in this file reads the server's environment. Every open-form command except init first loads .env from the workspace root when there is one; variables already set in the environment win. In a Next.js app, Next.js loads .env itself.

Schema

Prop

Type

protection takes the same keys as a form's protection, merged key by key.

Checked at load

An unknown locale or an invalid timeZone fails loudly: open-form dev, build, check and the other commands that read this file stop with the error. Saved while open-form dev runs, a broken config is reported and the server keeps the previous one until you fix it. webhooks and embed.origins are checked when the server sets up the API; see Webhooks and Embed.

Common recipes

Deadlines in your time zone

Set timeZone once so opensAt: '2026-10-01' and closesAt: '2026-10-31' mean those days where you are, on any server:

export default defineConfig({ timeZone: 'Asia/Taipei' });

Send responses to Slack, Zapier or your API

const responsesUrl = process.env.RESPONSES_WEBHOOK_URL;

export default defineConfig({
  webhooks: responsesUrl ? [{ url: responsesUrl, forms: ['meetup'] }] : [],
});

Each new response is POSTed as submission.created. Set OPEN_FORM_WEBHOOK_SECRET to sign deliveries in the Standard Webhooks format. URLs must use https:// (http:// only for localhost, 127.0.0.1, [::1] and *.localhost). Keep the URL in an environment variable; it is read when the server starts, not copied into the build. Leave the entry out when the variable is unset, as above: a missing URL is refused like any other invalid one, so open-form start won't start, and under open-form dev or in a Next.js route every API request fails. See Webhooks.

Embed forms on another site

export default defineConfig({ embed: { origins: ['https://blog.example.com'] } });

Origins are scheme and host only — https://example.com, no path. This allows framing /f/<id> and calling the public form routes from that site; the admin API never opens to other origins. See Embed.

Behind a reverse proxy

export default defineConfig({ trustProxy: 1 });

Without it, every visitor seems to come from the proxy's address, so rate limits and sign-in attempts are counted for everyone together: one person can use up a form's rate limit or lock everyone out of Studio sign-in. Forms work either way, HTTPS included. Set it only when proxies you control sit in front of the server. open-form start also reads OPEN_FORM_TRUST_PROXY (true, false or a number) when the config doesn't set it. The Next.js route defaults to 1 instead, since it expects Vercel or a reverse proxy in front.

Keep the database on a volume

export default defineConfig({ storage: { path: '/data/open-form.db' } });

Or leave the config alone and set OPEN_FORM_DB=/data/open-form.db on the server. See Storage.

Remote IDE or tunnel during development

Cloud workspaces and tunnels reach the dev server through another hostname, which the dev server blocks. Allow it — a leading dot matches every subdomain:

export default defineConfig({ allowedHosts: ['.my-workspace.example.com'] });

Without OPEN_FORM_ADMIN_PASSWORD, Studio answers only direct requests from your machine and refuses the rest, with a hint in the terminal to set it. A raw TCP tunnel (ssh -R) or a proxy that adds no X-Forwarded-For can still make a remote request look local, so set a password whenever Studio is reachable through a tunnel or proxy; see open-form dev. With it set, everyone signs in, on your own machine too.

On this page