Getting started
Scaffold a workspace, have your coding agent write a form, preview it in Studio and collect your first response in a few minutes.
Open Form needs Node.js 22.13 or later. It stores responses with Node's
built-in node:sqlite, so there is nothing else to install.
Install
npm create open-form@latest my-forms
cd my-forms
npm run devThe scaffolder creates a workspace (abridged — see open-form init for the full tree):
my-forms/
├── forms/ # one folder per form, with its own theme/ once it has one
│ └── contact/index.tsx # a starter form
├── themes/ # reference themes for new forms (just a README at first)
├── .agents/skills/ # bundled agent skills
├── open-form.config.ts # project config, with your time zone
├── AGENTS.md # agent rules (CLAUDE.md links to it)
└── package.jsonThe dev script starts the dev server with Studio at
http://localhost:3000/studio. Every form is live at /f/<id> and hot
reloads as its file changes.
Forms import from @open-form-build/core, the package the workspace depends
on, and its CLI is open-form.
Commands in these docs come in npm, pnpm, yarn and bun tabs, matching the
ones in your workspace's README; pick yours once and every page follows. In
running text, open-form <command> means the CLI run through your package
manager: npx open-form, pnpm exec open-form, yarn open-form or
bunx open-form.
Author with an agent
Open the workspace in any agent-aware editor — Claude Code, Codex, Cursor, Gemini CLI, OpenCode, Windsurf, Zed. From the agent prompt:
/create-form registration for a developer meetup. Ask for name, email, role
and experience. If they're a student, ask for their school. 100 seats.The skill asks what it needs, proposes three visual directions for your
audience, then writes forms/<id>/index.tsx and checks it with
open-form check. See create-form.
Prefer to write it yourself? Start from a stub:
npx open-form create meetupPreview and iterate
Open the form in Studio (/studio/<id>):
- Preview it at desktop, tablet and mobile widths. The step buttons jump to any page, including conditional ones; When closed shows each closed screen.
- Switch to Edit, select any element and change its text in place, or leave a comment for your agent.
- Run
/apply-commentsin your agent. It applies each note in the source and removes the marker.
See Studio and Edit mode & comments.
Give it a look
Each form owns its look in forms/<id>/theme/, imported by the form and passed
to <Form theme>:
import theme from './theme/index.ts';
export default function Meetup() {
return <Form theme={theme}>…</Form>;
}A form from open-form create starts with an empty theme/index.ts, the plain
base look. Start one from a starter's tokens instead with --theme:
npx open-form create meetup --theme terminalThe starters are classic, editorial, terminal, brutalist and
conversational. They're references: /create-form reads the chosen one and
writes the rest of the form's look, taking only what that form uses. The look
is the form's to change, by hand, through your agent, or with Adjust in
Studio's preview, and only that form changes with it. For a look of your own,
ask your agent for one with /create-theme: it lands in themes/ as a
reference for new forms. See Themes.
Collect responses
Submissions from the preview are real: they are stored in
.open-form/open-form.db (or Postgres, if you set it
up) and appear under the form's Responses tab, where
you can search, open, delete and export them.
npx open-form responses export meetup -o responses.xlsxBuild and deploy
npm run build
OPEN_FORM_ADMIN_PASSWORD='a long passphrase you choose' npm startopen-form start serves the forms, the API and SQLite from one Node process.
With SQLite it needs a persistent disk for .open-form/ — a VPS,
Docker, or Railway / Fly.io with
a volume; with Postgres it doesn't. Studio is only available in production when
OPEN_FORM_ADMIN_PASSWORD is set, or read-only for everyone with
studio.public. See Production,
deploy the whole project to Vercel with Postgres, or mount
the API inside an existing app with Next.js.