Self-hosted service
formio/formio avatar
formio/formio

Form.io: a drag-and-drop form builder that ships the API server too

A Form and Data Management Platform for Progressive Web Applications.

2,320 stars766 forksJavaScriptOSL-3.0

At a glance

What is it?
The repository behind form.io bundles a visual form designer, the JSON schema it emits, and an Express and MongoDB server that turns every form into a REST resource, so the data layer is not a separate project you assemble later.
Who is it for?
Form.io is the right pick when the form is the product, meaning the shape of the data arrives through a designer rather than a migration script, and the same repository has to serve it. The repository is not archived and the last push was on 2026-09-28, though it publishes no GitHub releases, so version tracking happens through the npm package, currently 4.10.0.
Can I use it commercially?
Yes, with conditions. OSL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Bringing the stack up with docker-compose and the CHANGEME login

The README calls Docker the fastest way to run this locally, and the compose file backs that up. Two services come up together: a `mongo` image holding a named volume at `/data/db`, and the `formio` service built from the Dockerfile in the repository root, linked to the database and published on port 3001.

bash
docker-compose up -d

If you have an older image lying around, the README tells you to force a rebuild with a `--build` flag, which matters because the Dockerfile copies `src/`, `config/`, the root JavaScript files and `default-template.json` into the image rather than installing from a registry.

bash
docker-compose up -d --build

The compose file seeds the root account from two environment variables, `ROOT_EMAIL: [email protected]` and `ROOT_PASSWORD: CHANGEME`, and points the server at the database with a single `NODE_CONFIG` value. Once the log stream settles you open `http://localhost:3001` and log in with the pair above. The README then spends six lines on changing that password, which is a fair signal about how the first-run credential is meant to be treated.

The manual path wants Node 22, a build step, and a mongod you started yourself

The Node route is documented separately and is less forgiving. You need Node.js and MongoDB installed, and unlike the compose path the database is not managed for you: the README asks you to confirm `mongod` is running in your terminal before going further, with Homebrew suggested on a Mac.

bash
brew install mongodb-community

Then three scripts, in order. Install dependencies, build the client application, start the server.

bash
yarn
yarn build
yarn start

What `yarn build` actually does is visible in `package.json`. It is not a bundling of one app. It chains three webpack targets: `build:vm`, `build:vm:nextgen` and `build:vm:nextgen-evaluator`, each pointing at a separate config file under `src/vm/`. Form.io evaluates form logic server-side, and these bundles are the evaluators that make a JSON-defined form decide what it renders. The version that ships this is 4.10.0, and the package declares `node >=22.0.0` as its engine floor.

For day-to-day work the README points at a nodemon script rather than restarting the process by hand, which exists as `start:dev` in `package.json`.

bash
npm run start:dev

One repository holds the portal, the server and the form runtime

The top-level tree explains the split better than any description could. `portal/` is the admin interface, a separate application with its own `package.json`, `tsconfig.json` and `webpack.config.mjs`, built by its own `npm run build` inside the Dockerfile before the server image is finished. `src/` is the engine, `config/` holds runtime configuration, `test/` holds the mocha suite, and the roots `index.js`, `main.js`, `server.js` and `install.js` are the entry points.

Two version fields in `package.json` describe what the output actually is: `schema: 3.1.4` and `templateVersion: 2.0.0`. The first is the version of the form JSON contract the server reads, the second the version of the prebuilt template a fresh install starts from. That `default-template.json` file in the tree is the thing those two numbers point at.

The runtime dependencies tell you what you are actually deploying: `express` for the HTTP layer, `bcryptjs` for password hashing, `body-parser`, `cors`, `config`, and the two first-party packages `@formio/core` and `@formio/js` for the component and renderer definitions. The client-side renderer is not bundled into this repository, it arrives as a dependency, which is why a form can be embedded in an Angular, React or Vue application rather than only in the portal.

Pino logging with header redaction and an off-by-default structured flag

The logging section is the most carefully specified part of the README, which tells you something about how this codebase is maintained. Structured logging is built on Pino and lives in `src/util/logger`, exporting two things: an application logger and an HTTP request logger. The level comes from the `LOG_LEVEL` environment variable and defaults to `info`.

javascript
app.use(httpLogger);

`httpLogger` traces each request and attaches a request-scoped logger as `req.log`. The README is precise about mount order, which is the sort of detail that usually gets left out: it goes before any other middleware but after `app.set('query parser', ...)`, because Express 4 locks the query parser on the first `app.use()`. If you mount the router into your own Express app without the middleware, the router attaches the logger itself.

The redaction list is worth knowing before you log anything yourself. The `x-token`, `x-admin-key`, `x-jwt-token`, `x-remote-token`, `x-file-token`, `authorization` and `cookie` request headers are stripped, as are the `token`, `x-jwt-token` and `x-remote-token` query parameters in both `req.query` and the URL. Errors are serialized down to four fields. The README's advice follows directly: log identifiers, not records, because redaction cannot see a value you interpolate into a string.

Structured output is behind the `STRUCTURED_LOGGING` feature flag and is off by default, so a fresh install prints text lines on stderr through the `debug` package. Enabling it changes the destination to stdout as JSON.

code
FORMIO_STRUCTURED_LOGGING=true

Mounting the HTML element instead of hand-building a form

The design decision that separates Form.io from a form library is that the form description is the interface contract. The README says the drag-and-drop builder output can be embedded in Angular.js and React applications through a single `<formio>` HTML element, and the repository topics list `angular`, `angularjs`, `react`, `vue`, `vanilla-js` and `nodejs` in the same breath, which is a fair description of the integration surface.

That choice has a consequence worth being blunt about. Because the server owns the schema, the API is generated from the same JSON, and submissions are stored in MongoDB documents that follow your component layout. If your organisation already has a normalised relational schema and the form is a thin front end over it, Form.io inverts the usual relationship: you would model your table as a form instead of adapting a form to your table.

What you give up in exchange is the wiring. There is no separate submission handler, no validation service, no file storage bucket to configure and no admin UI to build. The admin interface in `portal/` ships with the repository, which is the part a hand-rolled React form stack never gives you at all.

What the README leaves to help.form.io, and what OSL-3.0 means

The README is deliberately a getting-started document. It hands the reader off early: the official documentation link points at the enterprise server deployment page on help.form.io, and a walkthrough video titled 0 to M.E.A.N in 30 minutes covers the application-building path. Everything past installation, meaning upgrades, backups, multi-tenancy and role configuration, lives on that external site rather than in this repository. The repository does carry `SECURITY.md` and `CLAUDE.md`, and CI lives in `.circleci/` with coverage wired through `.nycrc`, but there are no GitHub releases at all, which means the changelog is a file rather than a feed you can watch.

The licence deserves a careful read rather than a glance. The `package.json` and `LICENSE.txt` both say OSL-3.0, the Open Source Licence, which is a copyleft licence with a reciprocity condition aimed at hosted use. That is a different obligation profile from MIT or Apache 2.0, and anyone planning to expose a form portal as a service needs to read the actual licence text with a lawyer rather than take a summary from a README. This is not legal advice, only a note that the licence here is unusual enough to be worth reading before deployment.

The remaining question is who maintains it. The last push was on 2026-09-28 and the repository is not archived, so work is landing, but the absence of tagged releases means there is no supported upgrade path visible from GitHub alone. Pin the npm version you deploy, read the changelog file, and treat help.form.io as a required part of the project rather than optional reading.

Editorial conclusion

Form.io is the right pick when the form is the product, meaning the shape of the data arrives through a designer rather than a migration script, and the same repository has to serve it. The repository is not archived and the last push was on 2026-09-28, though it publishes no GitHub releases, so version tracking happens through the npm package, currently 4.10.0. It is the wrong pick when you want forms to be a thin layer over an existing relational schema, since Form.io owns the schema and hands you MongoDB. Start with the docker-compose path and the [email protected] login, then read the deployment pages on help.form.io before you settle on an OSL-3.0 obligation.

Frequently asked questions

Is Form.io free?

The engine in this repository is open source under the Open Source Licence, version 3.0, and it runs locally with no paid dependency: Docker Compose brings up MongoDB and the server, and the README hands you a root login at [email protected]. A hosted commercial offering exists alongside it, which is what the help.form.io deployment pages cover.

Is there an open-source form builder that can be self-hosted?

Yes, and that is the shape of this repository. Docker Compose is the path the README recommends, and the Node route needs Node 22 or newer plus a MongoDB instance you start yourself. The catch is the licence: OSL-3.0 imposes reciprocity conditions that MIT or Apache 2.0 do not, which matters most if you plan to offer the forms as a hosted service.

Do I need to build anything after installing Form.io?

With Docker, no. `docker-compose up -d` starts the server and the database and the portal is reachable on port 3001 immediately. The manual Node path does require a build step, because `yarn build` compiles three webpack bundles for the server-side form evaluators before `yarn start` will serve anything useful.

What database does Form.io store submissions in?

MongoDB. The Docker Compose file defines a `mongo` service and points the application at it with a `NODE_CONFIG` value containing a `mongodb://mongo:27017/formio` connection string. The manual installation path asks you to confirm `mongod` is running before starting the server.

How do I turn on structured JSON logs?

Set the `FORMIO_STRUCTURED_LOGGING` environment variable to true. The flag is off by default, so an unconfigured install prints text lines on stderr through the `debug` package. With the flag on, output goes to stdout as JSON, unless `FORMIO_LOG_FORMAT` forces a mode or a `DEBUG` variable is present, which selects legacy mode for compatibility with existing monitoring.

Official sources

  1. formio/formio on GitHub
  2. Issues
  3. License: OSL-3.0
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/formio-formio.svg)](https://hysenlabs.com/projects/formio-formio)