API Reference
Complete reference for @outerjs/server — the Outer constructor, every builder method and its config, the schema() builder, and the built server.
new Outer(params)
import { Outer } from "@outerjs/server";
import { pglite } from "@outerjs/server/pglite";
const outer = new Outer({
name: "My App",
baseUrl: "https://api.example.com",
db: pglite(),
cors: { origins: ["https://app.example.com"], credentials: true },
});
| Param | Type | Required | Description |
|---|---|---|---|
name | string | no | Display name. Used as the OpenAPI spec title and shown by the admin API (_admin.meta). |
baseUrl | string | no | Public origin of the server. Used as Better Auth's default baseURL and as the servers[].url (<baseUrl>/rest) in the OpenAPI spec. |
db | { dialect: Dialect; kind: "postgres" | "sqlite" | ... } | yes | A Kysely Dialect plus the dialect family it belongs to. kind drives DDL generation, Better Auth's schema, and DB error mapping, so it must match the dialect. Use pglite() for the zero-infra default; construct the Dialect yourself for network Postgres, D1, etc. |
cors | CorsConfig | no | Cross-origin browser callers allowed to reach /rpc/**, /api/auth/**, and the admin API. Also merged into Better Auth's trustedOrigins when .auth() is used. Without it, no Access-Control-Allow-Origin header is set. |
CorsConfig
| Prop | Type | Default | Description |
|---|---|---|---|
origins | string[] | — | Allowed origins, matched exactly against the request's Origin header. |
credentials | boolean | false | Sets Access-Control-Allow-Credentials: true (needed for cookie-based auth from another origin). |
pglite(config?)
Embedded, zero-infra Postgres from @outerjs/server/pglite. Returns a { dialect, kind: "postgres" } pair to pass as db.
| Prop | Type | Default | Description |
|---|---|---|---|
dataDir | string | <cwd>/.outer/pglite | Data directory, created if missing. Pass a memory:// URL for an in-memory instance (handy for tests). |
Builder methods
Documented order: .schema() → .middleware() → .procedure() → .build(). .auth(), .openapi(), .admin(), .route(), and .resource() can appear anywhere before .build() (.resource() needs a prior .schema() that defines the table).
.schema(schemaResult)
Registers a schema version built with schema(). Every .schema() call becomes one migration step, and the latest version types context.db. Takes a single SchemaResult argument — no options.
.auth(config)
Enables Better Auth and mounts ALL /api/auth/**. Narrows context.auth to non-null.
AuthConfig is Better Auth's full BetterAuthOptions minus database (Outer wires the database itself from your db dialect), with these Outer-specific notes:
| Prop | Type | Required | Description |
|---|---|---|---|
secret | string | yes | Secret used to sign/encrypt sessions, cookies, and tokens. At least 32 random characters in production. |
baseURL | BetterAuthOptions["baseURL"] | no | Defaults to the constructor's baseUrl. Set to override just for auth. Accepts Better Auth's DynamicBaseURLConfig ({ allowedHosts, fallback?, protocol? }) for preview/dynamic domains. |
trustedOrigins | string[] | no | Merged with cors.origins from the constructor — CORS origins are always trusted regardless of call order. |
| ...rest | BetterAuthOptions | no | Everything else Better Auth accepts: emailAndPassword, socialProviders, plugins, session, etc. |
.middleware(mw)
Adds an oRPC middleware to the base context. Whatever the middleware returns via next({ context }) is merged into context for all subsequently defined procedures (and their types).
.procedure(name, cb)
Registers an RPC procedure. Dot notation nests namespaces: "user.me" is served at POST /rpc/user/me. The callback receives the oRPC base builder — chain .input(), .output(), .handler() on it. Names must be unique; the _admin namespace is reserved.
.route(method, path, handler)
Mounts a raw H3 route (webhooks, custom REST endpoints) alongside RPC routes. handler(event, context) receives the H3 event and the same context (with db, auth, ...) as procedures. Registered before /rpc/**, so it wins on overlapping paths.
.resource(name, options?)
Auto-generates typed CRUD procedures (list, get, create, update, delete) for a table defined in the latest .schema(). Throws at build time if the table doesn't exist.
ResourceOptions:
| Prop | Type | Default | Description |
|---|---|---|---|
permissions | ResourcePermissions | all "public" | Per-action rules — see below. |
ownerColumn | string | — | Column storing the creator's user ID. Required when any permission is "owner". When create requires a session and this is set, the current user's ID is auto-injected into inserts. |
listLimit | { default?: number; max?: number; maxSkip?: number } | 50 / 100 / 10000 | Default and max rows per list call; maxSkip caps the offset so deep pagination can't force full scans. |
includable | string[] | [] | Relations callers may include on list/get. Included rows are not checked against the related resource's permissions — only allow relations safe to expose. |
ResourcePermissions — each of list, get, create, update, delete accepts:
| Value | Meaning |
|---|---|
"public" | No restriction (the default). |
"authenticated" | Requires a signed-in session. |
"admin" | Requires the admin role (user.role may be comma-separated). |
"owner" | Requires the signed-in user to own the row (ownerColumn). Not valid for create; on list it scopes results to the caller's rows. |
PermissionFn | Custom check: ({ context, row? }) => boolean | Promise<boolean>. |
.openapi(config?)
Mounts GET /openapi.json and a plain-JSON REST surface under /rest/** matching the spec. Requires the optional peers @orpc/openapi and @orpc/zod.
| Prop | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Pass import.meta.env.DEV or similar to gate the spec to dev/staging only. |
.admin(config?)
Enables the admin API — meta/schema introspection, migration status, and table CRUD — under the reserved _admin namespace (/rpc/_admin/**). Every admin procedure requires a signed-in session with an admin role, so .auth() must also be called or .build() throws.
AdminConfig:
| Prop | Type | Default | Description |
|---|---|---|---|
listLimit | { default?: number; max?: number } | 50 / 200 | Default and max rows per _admin.data.list call. |
roles | string[] | ["admin"] | Roles granted admin access. Match Better Auth's admin plugin adminRoles if you customize it. |
.build()
Finalizes the chain and returns a BuiltOuter. Throws if any resource permission or .admin() requires auth but .auth() was never called.
BuiltOuter
| Member | Description |
|---|---|
handle(request) | Plain Fetch handler (Request => Promise<Response>) — plug into srvx, Bun.serve, Next.js route handlers, etc. |
client(headers?) | In-process router client that skips HTTP entirely — for SSR. Pass the incoming request's Headers (or a function returning them, evaluated per call) so permissions and context.auth see the caller's session. |
migrator | Kysely migrator over the registered schema versions — call await outer.migrator.migrateToLatest() on startup. |
router | The internal oRPC router. Use InferRouter<typeof outer> for type-safe client generation. |
schema() builder
import { schema, timestamps } from "@outerjs/server";
export const v1_0_0 = schema("1.0.0")
.auth()
.table("post", (t) => ({
id: t.serial().primaryKey(),
title: t.text(),
body: t.text().nullable(),
authorId: t.text().references("user", "id"),
meta: t.jsonb().nullable(),
...timestamps(t),
}))
.relation("user", (rel) => rel.hasMany("post", { from: "id", to: "authorId" }))
.build();
schema(version)
Starts a schema version. version is a free-form string (e.g. "1.0.0") shown in the OpenAPI spec and admin API.
.auth()
Registers the Better Auth core tables (user, session, account, verification) with the admin plugin's fields (user.role/banned/banReason/banExpires, session.impersonatedBy) plus their relations. Extend an auth table by re-declaring extra columns via .table("user", ...) after this call — columns merge, yours win on name collisions. Never remove or rename the core auth columns.
.table(name, define)
Defines (or extends — re-declaring merges, later wins) a table. define receives the column builder t:
| Column type | TS type (select) | Notes |
|---|---|---|
t.serial() | number | DB-generated; omitted from create inputs. |
t.text() | string | |
t.varchar() | string | |
t.integer() | number | |
t.boolean() | boolean | |
t.timestamp() | Date | Resource inputs take ISO strings; outputs are Date | string depending on dialect. |
t.jsonb() | unknown | |
t.uuid() | string |
Column modifiers (chainable, each returns the column):
| Modifier | Effect |
|---|---|
.nullable() | Column allows NULL; optional in inserts and typed | null. |
.primaryKey() | Marks the primary key — drives the where type of resource get/update/delete. |
.unique() | Adds a unique constraint. |
.default(expr) | Raw SQL default expression (e.g. "CURRENT_TIMESTAMP", "'user'", "false"). Defaulted columns are omitted from resource create inputs. |
.references(table, column) | Foreign key. |
timestamps(t)
Helper returning createdAt / updatedAt timestamp columns with CURRENT_TIMESTAMP defaults — spread into a .table() column object.
.relation(fromTable, define)
Declares a relation used by context.db.query (Sola) and resource include. define receives a chain with:
| Kind | Signature |
|---|---|
hasMany | rel.hasMany(to, { from, to }) |
hasOne | rel.hasOne(to, { from, to }) |
belongsTo | rel.belongsTo(to, { from, to }) |
manyToMany | rel.manyToMany(to, via, { from, to, pivotFrom, pivotTo }) — via is the pivot table; pivotFrom/pivotTo are the pivot columns referencing each side. |
.build()
Freezes and returns the SchemaResult to pass into .schema().
Type helpers
| Export | Description |
|---|---|
InferRouter<T> | Extracts the oRPC router type from an Outer or BuiltOuter instance — the input to oRPC client creation. |
OuterAdminRouter | { _admin: AdminRouter } — the router shape for a type-safe admin-only client: createClient<OuterAdminRouter>({ baseUrl }). |
InferDB<T> | Maps a schema's tables to Kysely row types. |
AuthTables | The table shape .auth() registers on the schema builder. |
OuterRpcContext<TDB> | The base procedure context: { headers, db, auth? }. context.db is Kysely plus query (Sola) and transact(fn) for transactions. |