⚠️ This docs site and backframe.js are still under construction.

backframe.js does not support commonjs. You must use es modules. However, no extra configuration is required on your part. Just use import instead of require and backframe will handle the rest.

Introduction to backframe.js

Welcome to the backframe.js documentation. This documentation is a work in progress and will be updated as the project progresses. The easiest way to get started is to use the create-bf command line tool to create a new project. Be sure to include the @latest tag to ensure you are using the latest version of the tool.

pnpx create-bf@latest my-project

It can be a bit confusing getting started with backframe as it branded as a framework but also as a tool for creating full backends and it's a bit of both. The core is just a framework built on top of express and getting started with this is pretty straight forward. The tooling and plugin ecosystem is a bit more complex and is designed to help you create a full backend with a database, api, and admin interface. The tooling is optional and you can use the framework without it.

Getting Started

After running the command, you will be prompted for a few values as well as how you would like to proceed with the CLI. Select Create a minimal starter app as the rest of the options are disabled for now. For better DX, select typescript as your language of choice. This will create a new project with the following structure:

├── src
   ├── routes
      └── hello.ts
   └── server.ts
├── bin
   └── serve.mjs
├── bf.config.ts
└── package.json

Running the server

To run the server, you can use the dev script automatically created in your package.json. This will start the server and watch for changes. The server will automatically restart when changes are detected (no nodemon required).

pnpm dev

If you have the @backframe/cli installed globally, you can also run the serve command from the root of your project.

bf serve

Creating a route

Routes are created in the src/routes directory. The CLI will create a hello.ts route for you. This route will respond to a GET request to /hello and return a simple hello world message.

import { createHandler } from "@backframe/rest";
export const GET = createHandler({
  action(ctx) {
    return "Hello World!!!";

The createHandler helper function is what you will use to create your routes. It takes a single argument which is an object with the following properties:

  • action - The function that will be called when the route is hit. This function can return a value or a promise. If a promise is returned, the server will wait for the promise to resolve before sending the response.
  • middleware - An array of middleware functions that will be called before the action. These functions can return a value or a promise. The middleware functions will be called in the order they are defined and have access to the ctx object which contains the request and response objects. They have to call ctx.next() to continue to the next middleware or the action.
  • input (optional) - A zod schema that will be used to validate the request body. If the request body is invalid, a 400 error will be returned with the validation errors.
  • output (optional) - A zod schema that will be used to validate the response body. If the response body is invalid, a 500 error will be returned with the validation errors.

Here's an example of a route that uses middleware and input/output validation.

import { createHandler, z } from "@backframe/rest";
export const POST = createHandler({
  input: z.object({
    name: z.string(),
    email: z.string().email(),
    password: z.string().min(8),
  output: z.object({
    id: z.string(),
    name: z.string(),
    email: z.string().email(),
  middleware: [
    function (ctx) {
  action(ctx) {
    // TODO: save to db
    const savedUser = {
      id: "123",
      name: ctx.input.name,
      email: ctx.input.email,
    return savedUser;