Create Federation
Initialize the Downcity server-side Federation with the default database and HTTP service.
The server-side runtime class is Federation (also called the Federation in these docs); product clients use the City client to reach it. See Federation and City for the distinction.
Install the packages:
pnpm add @downcity/city drizzle-orm better-sqlite3The database is the only thing you need before boot. On first boot Federation fills DOWNCITY_FEDERATION_ADMIN_SECRET_KEY, DOWNCITY_FEDERATION_TOKEN_SIGNING_KEY, and BETTER_AUTH_SECRET automatically. Provider keys are written later through the Admin API or the fed admin workspace:
OPENAI_API_KEY="..."
OPENAI_BASE_URL="https://api.openai.com/v1"Create Federation:
import { Federation } from "@downcity/city";
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
const sqlite = new Database("./data.sqlite");
sqlite.pragma("journal_mode = WAL");
const db = Object.assign(drizzle(sqlite), {
$client: { exec: (sql: string) => sqlite.exec(sql) },
});
const base = new Federation({ db });The default database is stored at:
./data.sqliteFor local SQLite, better-sqlite3 is the recommended path. For production Postgres, create a Drizzle pg db and pass that db to Federation the same way.
For Cloudflare Workers / D1, pass the D1 Drizzle db:
import { drizzle } from "drizzle-orm/d1";
const db = drizzle(env.DB);
const base = new Federation({ db });Federation initializes itself automatically on the first health(), handleRequest(), table(), or similar runtime call.
If your Federation needs its own business tables, declare them on a Service or service:
import { sqliteTable, text } from "drizzle-orm/sqlite-core";
import { Service } from "@downcity/city";
const notes = sqliteTable("notes", {
id: text("id").primaryKey(),
title: text("title").notNull(),
status: text("status").notNull(),
});
const notesService = new Service({
id: "notes",
tables: { notes },
});
base.use(notesService);
const table = await base.table("notes.notes");
await table.insert({
id: "note_1",
title: "First note",
status: "draft",
});Tables declared by services use the same database connection as Federation. Regular projects do not need manual table creation.
Start the HTTP service:
import { serve } from "@hono/node-server";
await base.health();
serve({ fetch: base.router().fetch, port: 3001, hostname: "127.0.0.1" });This service is the shared Federation used by later cities. Management and business data are handled through your own database and city backend for now.