brick.ts
BRICK v0.8.2 / OPEN SOURCE

Build your backend.
Keep your TypeScript.

Small definitions. Production execution.

Your actions, resources, and rules. Compiled into a backend ready to run on Bun.

Building with an AI agent? ↗
DEFINE / COMPILE / RUN ↓

01 / THE DEVELOPER SURFACE

One codebase.
Two ways to run.

Start with direct calls. Expose HTTP when you need it. The same typed definitions power both.

BRICK / APPLICATION WORKBENCH READY TO RUN
src/services/users.ts
import { defineService, t } from "@brickkit/core";

const users = new Map([["usr_42", { id: "usr_42", name: "Ada" }]]);
export const usersService = defineService("users");

export const getUser = usersService.action({
  name: "getUser",
  input: t.Object({ id: t.String() }),
  execute: ({ input, error }) => {
    const user = users.get(input.id);
    if (!user) error.NOT_FOUND("User not found");
    return user;
  },
});
src/main.ts
import { getUser } from "./services/users";

const user = await getUser({ input: { id: "usr_42" } });
console.log(user);

Invoke the same typed action directly in process. These files are the runnable examples/showcase source in this repository.

02 / BUILT TO FIT TOGETHER

A foundation for
what comes next.

A focused set of primitives, built on the TypeScript tools you already know.

03 / RESOURCES

A table becomes an API.
Your rules come with it.

Define a Drizzle table and install the CRUD resource plugin. It supplies CRUD routes, list filters, pagination, and typed hooks. Add custom actions for everything beyond CRUD.

POST/api/comment/queryList
GET/api/comment/:idRead
POST/api/commentCreate
PATCH/api/comment/:idUpdate
DELETE/api/comment/:idDelete
Explore resources
comments/index.ts · runnable source

Actual source from the comments extension. No illustrative APIs.

04 / TYPE SAFETY

One definition.
Fewer places to drift.

TypeBox schemas supply action types and runtime validation. Drizzle tables supply row types and resource shapes. OpenAPI describes the same registered API.

Follow the types

05 / ACCESS CONTROL

Put access rules
next to the work.

Resolve a session into service context, authorize custom actions, and scope resource rows to their owner. Connect Better Auth through its session API or bring your own provider.

Configure sign-in checks for protected CRUD routes. Owner scoping complements those checks.

Configure access control
REQUEST / POLICY PIPELINE
  1. 01

    Context

    Resolve the user and session.

  2. 02

    Authorization

    Check access before execution.

  3. 03

    Ownership

    Scope records to their owner.

Your identity. Your policies.

06 / DATABASES

Drizzle at the foundation.

Keep your SQL, table definitions, and migrations. Brick adds services and resources around them.

SQLite

Start locally with Bun’s native SQLite driver. Use an in-memory database for examples or a file-backed database for persistence.

  • Bun-native driver
  • In-memory or file-backed

PostgreSQL

Connect PostgreSQL with a URL and Drizzle tables. Keep production schema changes in your migration workflow.

  • Postgres.js driver
  • Drizzle table definitions
Read the database guide

07 / EXTENSIONS

Build once.
Bring it along.

Package a table, resource, hooks, and custom actions as a reusable TypeScript module. Import it into a service and register it before building the server.

CommentsAudit trailsResource hooksCustom actions

The comments example is runnable today. Use the same pattern for your own workflows.

Build your first extension
extensions/src/app.ts
import {
  brick,
  defineDatabase,
  defineService,
  syncSchema,
  sqliteTable,
  text,
} from "@brickkit/core";
import { commentsTable, comments } from "./extensions/comments";
const pages = sqliteTable("pages", { id: text("id").primaryKey() });
const database = defineDatabase({ tables: { pages, comments: commentsTable } });
syncSchema(database.tables, database.getDb());
await database
  .getDb()
  .insert(pages)
  .values([{ id: "page-1" }, { id: "page-2" }]);
export const pagesService = defineService("pages", { database });
export const page = pagesService
  .resource({ name: "page", table: pages, id: pages.id })
  .use(comments({ table: commentsTable }));
export const app = brick({ services: [pagesService], requestLogging: false });

Standard imports. Standard TypeScript. Your reusable module.

08 / ENDPOINTS

More than a JSON API.

Use raw endpoints when you need direct control over the request, headers, status, or response body.

HTML surfaces

Render a public page and set its content type in your handler.

Webhook handlers

Read the original request and apply your provider’s signature checks.

Custom responses

Return a Response with your own headers, status, or streaming body.

Explore the endpoint API

09 / TOOLING

Inspect it.
Document it. Compile it.

See what your definitions become. Work with real output, live contracts, and runnable examples.

10 / THE FOUNDATION

Tools you know.
A backend you own.

TypeScriptBunElysiaTypeBoxDrizzle

A backend authoring layer over a familiar runtime and database toolkit.

YOUR NEXT BACKEND STARTS HERE

Write the definitions.
Make something real.