# OpenForm: a TypeForm-style form builder, with Supabase doing the heavy lifting

> OpenForm is a self-hostable open-source alternative to TypeForm, built around the one-question-at-a-time form experience, with a builder, a response dashboard and thirteen question types. The architecture is worth understanding before you install it, because the interesting decisions are which services it delegates to: Supabase for the database and for authentication, and optionally Cloudflare R2 for file uploads, with Next.js 16 and shadcn/ui on the front.

**dabit3/openform** — Open Source TypeForm Clone

- Repository: https://github.com/dabit3/openform
- Stars: 526 · Forks: 120
- Language: TypeScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/dabit3-openform

## What it is

OpenForm is a beautiful, open-source TypeForm alternative, for creating engaging forms with a one-question-at-a-time experience.

The one-question-at-a-time part is the defining characteristic of the form type it is imitating, and it is a design decision with real consequences. Instead of showing a long form and reporting validation errors at the end, each question appears on its own screen and the respondent advances through them one at a time. That is easier to complete on a phone, and it is also why the project leans on Framer Motion for the transitions and on keyboard navigation.

The feature list has six entries. Six beautiful themes, named Midnight, Ocean, Sunset, Forest, Lavender and Minimal. Keyboard navigation, with Enter, arrow keys and the scroll wheel. Mobile-first forms with a responsive form-taking experience. Secure authentication through Google OAuth and Magic Link. A response dashboard where you can view, search, filter and export to CSV. And thirteen question types.

The primary language is TypeScript, the licence is MIT, the default branch is main, and the last push was on 2026-10-02 with the project not archived. The repository publishes no GitHub releases, and the package version in the manifest is 0.1.0 with the package marked private, which is consistent with a template that you deploy yourself rather than consume from a registry.

The licence statement in the README is worth noting for what it grants: MIT License, feel free to use this for any project.

The question types cover the range you would expect from a form builder, and the list reads as the schema of a question rather than a set of widget names. Short text and long text for free input. Dropdown and checkboxes for choices, one and many. Email and phone and number and date, each with its own input and validation. A rating as star rating from 1 to 5, and an opinion scale as a numeric scale from 1 to 10. A yes/no binary choice. File upload for images and PDFs. And a website URL field with validation.

The two rating types being distinct is a small but telling detail. A star rating and a numeric opinion scale are visually and semantically different answers, and a form builder that treats them as the same type with a different rendering gets the data model wrong.

## The stack, and what it delegates

The tech stack list is short and the second line is the one to stop on.

The framework is Next.js 16 with the App Router. The database is Supabase, which is PostgreSQL. The auth is Supabase Auth with Google OAuth and Magic Link. The styling is Tailwind CSS with shadcn/ui. The animations are Framer Motion. And file storage is Cloudflare R2, listed as optional.

So there is no server-side code of its own beyond Next.js route handlers. The database is a hosted Supabase project, the authentication is handled by Supabase, and the file storage is an S3-compatible bucket in Cloudflare's R2 service, with the AWS SDK for S3 as the client. That makes the application a front end plus a thin API layer over services you sign up for separately, and the setup instructions reflect that: you create a Supabase project, run a schema file in its SQL editor, and configure the providers.

The dependency list shows the same shape. There is the Supabase JavaScript client and the Supabase SSR package for cookie-based sessions in the App Router, a long tail of individual Radix UI packages, one per component, since shadcn/ui copies the component source into your project rather than shipping a library. Next, React 19, Framer Motion, lucide-react for icons, next-themes for the theme switching, class-variance-authority and clsx for the shadcn styling pattern, and @hookform/resolvers at about 5.2 for form validation, which shifts validation into a schema-driven layer instead.

The version numbers are worth a glance. Next at 16.1.1 and React at 19.2.3 are both current, and the Framer Motion and Radix pins are recent. The @hookform/resolvers dependency is the one to watch, because it is the piece that decides how validation errors behave, and a form builder that gets that wrong produces a form that accepts bad input.

Six themes are defined in the project structure under lib/themes.ts, and lib/questions.ts holds the question type definitions, which tells you the two things that are data rather than code: the question types and the themes. Everything else in the components directory is the interface built on top of those two files.

## Setting it up, and the Supabase steps that are not optional

The prerequisites are Node.js 18 or newer, a Supabase account, and optionally a Cloudflare account for file uploads.

Then the clone and install:

```bash
git clone https://github.com/yourusername/openform.git
cd openform
npm install
```

The URL in that command is a placeholder, yourusername, which tells you the README expects you to fork first rather than clone the original.

The Supabase setup is four steps and they are the part that requires you to leave the README and use other documentation. You create a new project at supabase.com. You run the database schema in the SQL editor, by copying the contents of supabase/schema.sql and pasting it in. Then you configure authentication, enabling Google OAuth under Authentication, then Providers, then Google, adding your Google OAuth credentials, which you get from Google Cloud Console, and setting the redirect URI to the Supabase callback path. Then you configure the URLs, setting the Site URL to the local development address and adding the local auth callback URL as a redirect URL. And finally you get your API keys from Settings, then API, copying the Project URL and the anon public key.

That is the shape of the project. The schema is a file you paste into a web editor rather than a migration you run, which is convenient for a first setup and which you will want to replace with a migration tool if you keep the project.

Then the environment variables, which are the public Supabase credentials:

```env
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
```

And the development server:

```bash
npm run dev
```

The README then describes the file upload setup as optional, and it is a second set of credentials for Cloudflare R2: the account id, an access key id, a secret access key, the bucket name and a public URL. The bucket name in the example is openform-uploads, and the public URL is the r2.dev domain, which is the public development endpoint rather than a custom domain.

Deployment is documented for Vercel as recommended, in four steps: push the code to GitHub, import the repository in Vercel, add the environment variables in the Vercel dashboard, and deploy. And there is a warning at the end that is easy to miss and expensive to miss, to update the Supabase URL configuration with your production URL.

## The project structure, and what it reveals

The structure listing is the best single view of how the application is put together, and it is worth reading line by line.

The app/ directory uses the App Router's route group convention. There is an (auth) group for the login pages, and a (dashboard) group for the protected pages, which itself contains dashboard for the forms list, forms for the form builder and responses, and settings for user settings. Then there is an api/ directory for API routes, an auth/ directory for the auth callback, and f/[slug]/ for the public form pages.

The bracketed group names are the Next.js convention for a layout that applies to a set of routes without affecting the URL, so the dashboard group has its own layout and the public form pages at f/[slug] sit outside it. The form-taking route is a single dynamic segment, which is what makes a form shareable by slug with no lookup table, since the slug is the form's identity in the URL.

The components/ directory is organised by feature rather than by type. There is a dashboard/ directory, a form-builder/ directory, a form-player/ directory, a responses/ directory and a ui/ directory for the shadcn/ui components. The separation between form-builder and form-player is the important one, because those are two different applications sharing a question type definition: the builder renders a question to edit it, and the player renders it to answer it.

The lib/ directory holds the Supabase clients, database.types.ts for the generated TypeScript types, questions.ts for the question type definitions, and themes.ts for the theme configurations. And supabase/schema.sql is the database schema.

Two things outside the structure listing are worth noticing. There is a middleware.ts at the repository root, which is where Next.js session handling and route protection live, and it pairs with the Supabase SSR package in the dependencies. And there is a components.json at the root, which is the shadcn/ui configuration file, which is what lets the shadcn CLI know where to put components and how to configure them.

The repository also has a SPEC.md and a CLAUDE.md, and the CLAUDE.md is a working file for coding assistants rather than documentation for users, which is a reasonable thing to find in a repository built this way.

## How to evaluate it, and what to check first

There are four things to consider, and the first is that this is a template as much as a product.

The version is 0.1.0, the package is marked private, the clone command has a placeholder URL, and the environment variables are documented as values you fill in. Nothing here is configured out of the box, and that is not a criticism, because an application that stores form responses needs a database and an auth provider, and there is no sensible default for either.

Second, the hosted service dependencies. You need a Supabase project, and for file uploads a Cloudflare R2 bucket. That is two accounts before you can run the thing, and the R2 part additionally needs an S3 API token with read and write permissions, which is a slightly unusual thing to have to create for a form builder. The upside is that there is no server of your own to run, and the README is explicit that R2 is optional.

Third, the security posture of the form builder itself. A form builder takes arbitrary input from the public internet and stores it, and the dashboard exposes responses with search, filter and CSV export. The Supabase anon public key is what the browser uses, so the row-level security rules in schema.sql are the thing that decides who can read what. The README says to run the schema as-is, so the security posture is whatever the schema author configured, and you should read it before you put anything sensitive in the forms.

Fourth, the theme and question model. Six themes are defined in a data file and thirteen question types in another, so extending either is a matter of editing data rather than writing components, which is the right structure. The rating and opinion scale being separate types is a hint that the author thought about the data model rather than the visuals, and the same care is needed if you add a type.

What you get is a working, well-organised starting point with a real builder, a real player and a real response dashboard, and the design decisions made for you in the parts that are tedious. The costs are the account setup, the fact that you own the security configuration of a schema you did not write, and the version number that says the project is young enough that the shape of the schema may still change.

## Conclusion

Adopt OpenForm if you want a self-hosted TypeForm-style form builder and are comfortable wiring it to hosted services, because the builder, the player, the response dashboard and thirteen question types are all there and the schema and theme files make extending them a data change rather than a code change. Do not treat it as a ready-to-run product, since the package is private at 0.1.0, the clone command has a placeholder URL and the environment variables are values you supply. Before you commit, read the row-level security rules in supabase/schema.sql rather than running it blind, because the browser talks to the database with the anon public key and that schema is what decides who can read which responses, and set up the Supabase redirect and site URLs for your production domain at the same time as you deploy, since forgetting that is the documented failure and it locks you out of the dashboard.

## FAQ

### What is OpenForm?

It is an MIT licensed open-source TypeForm alternative for creating engaging forms with a one-question-at-a-time experience. It includes a form builder, a public form player, a response dashboard with search, filter and CSV export, six themes and thirteen question types. The primary language is TypeScript and the last push to the repository was on 2026-10-02.

### What is the tech stack of OpenForm?

Next.js 16 with the App Router for the framework, Supabase on PostgreSQL for the database, Supabase Auth with Google OAuth and Magic Link for authentication, Tailwind CSS with shadcn/ui for styling, Framer Motion for animations, and optionally Cloudflare R2 for file storage using the AWS SDK for S3.

### What question types does OpenForm support?

Thirteen: short text, long text, dropdown, checkboxes, email, phone, number, date, a 1 to 5 star rating, a 1 to 10 opinion scale, yes and no, file upload for images and PDFs, and a website URL with validation. The question type definitions live in lib/questions.ts and the theme configurations in lib/themes.ts.

### How do I set up OpenForm?

You need Node.js 18 or newer and a Supabase account. Clone the repository and run npm install, then create a Supabase project, run the contents of supabase/schema.sql in its SQL editor, enable Google OAuth under the authentication providers with your credentials and the Supabase redirect URI, set the site and redirect URLs, and copy the Project URL and anon public key into .env.local. Then run npm run dev and open http://localhost:3000.

### How are file uploads configured in OpenForm?

They are optional and use Cloudflare R2. You create an R2 bucket, create an API token with read and write permissions, and add the account id, access key id, secret access key, bucket name and public URL to .env.local. The example values use a bucket named openform-uploads and a public URL on the r2.dev domain.

## Sources

- [dabit3/openform on GitHub](https://github.com/dabit3/openform)
- [Issues](https://github.com/dabit3/openform/issues)
- [License: MIT](https://github.com/dabit3/openform/blob/main/LICENSE)
- [README](https://github.com/dabit3/openform/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dabit3-openform
