Getting Started

Outer is a batteries-included TypeScript backend framework built on Kysely, oRPC, and Better Auth, with PGlite as the recommended zero-infra default database. It exposes a builder-chain API that produces a fetch-compatible HTTP handler.

Create a server

npx giget@latest gh:ilhajs/outer/templates/minimal my-outer-app
cd my-outer-app
npm install
npm run dev

The builder chain

import { Outer, schema } from "@outerjs/server";
import { pglite } from "@outerjs/server/pglite";

const v1_0 = schema("1.0.0")
  .table("user", (t) => ({
    id: t.text().primaryKey(),
    email: t.text().unique(),
    name: t.text(),
  }))
  .build();

const server = new Outer({ name: "My API", baseUrl: "http://localhost:3000", db: pglite() })
  .schema(v1_0)
  .auth({ secret: process.env.AUTH_SECRET! })
  .middleware(async ({ context, next }) => {
    const session = await context.auth.api.getSession({ headers: context.headers });
    return next({ context: { user: session?.user } });
  })
  .procedure("user.me", (base) => base.handler(({ context }) => context.user))
  .build();

await server.migrator.migrateToLatest();
serve({ fetch: (req) => server.handle(req) });

Order matters: .schema().middleware().procedure().build(). .auth() and .openapi() can appear anywhere in the chain.

Project structure

my-outer-app/
├── src/
│   ├── schema.ts   # schema("1.0.0")...build() versions
│   └── index.ts    # new Outer(...).schema(...).auth(...).procedure(...).build()
└── package.json

Where to next

  • Schema & Migrations — define tables, relations, and auto-generated CRUD with .resource()
  • Auth & Permissions — enable Better Auth and read the session in procedures
  • Procedures & Context — register custom procedures, raw routes, and query with the Sola ORM
  • Realtime — stream updates over SSE with oRPC's event iterators
  • Deployment — the pglite() default, custom dialects, and embedding in a host framework