Federation
The role of the Federation instance, runtime, router, and serve inside @downcity/city.
@downcity/city's Federation is the long-running server container of Downcity (also called the Federation in these docs). It is where the Drizzle db, services, auth, and the shared /v1/* route space come together. Product-side access uses the City client; see Federation and City for the distinction.
What this concept means
A simple way to think about Federation is:
one reusable AI infrastructure runtime process that many products can keep calling over time.
That process owns:
- the Drizzle database connection
- the service registry
- service mounting
- the HTTP route surface
- city, token, and env infrastructure
When this page matters
- you are about to run a real Federation for the first time
- you want to understand why
Federationonly needs a Drizzle db - you want clarity on
router(),handleRequest(), andserve() - you want to mount Federation into Node, Workers, or another HTTP host
Minimal runnable example
import { AIService, Federation } from "@downcity/city";
import { serve } from "@hono/node-server";
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
const sqlite = new Database("./.base/downcity.sqlite");
sqlite.pragma("journal_mode = WAL");
const db = Object.assign(drizzle(sqlite), {
$client: { exec: (sql: string) => sqlite.exec(sql) },
});
const base = new Federation({ db });
const ai = new AIService();
ai.use({
id: "local-echo",
name: "Local Echo",
default: ["text"],
actions: {
text: async (ctx) => ({
id: crypto.randomUUID(),
role: "assistant",
parts: [
{
type: "text",
text: String(ctx.input.prompt ?? ""),
state: "done",
},
],
}),
},
});
base.use(ai);
await base.health();
serve({
fetch: base.router().fetch,
port: 43127,
hostname: "127.0.0.1",
});The important ideas in that example are:
dbdecides which Drizzle database Federation uses.base.use(...)decides which capabilities Federation exposes.base.router()andbase.handleRequest()decide how Federation enters your HTTP layer.
Scenario 1: Federation is the main service
If you want Federation itself to be the main HTTP entry, serve() is the clearest mental model:
import { serve } from "@hono/node-server";
await base.health();
serve({ fetch: base.router().fetch, port: 3001, hostname: "127.0.0.1" });Scenario 2: Federation is mounted into your existing server
If you already have a server framework, handing requests into Federation is often the cleaner pattern:
export default {
async fetch(request: Request) {
return base.handleRequest(request);
},
};Why Federation only takes db
@downcity/city owns the logic that should stay stable across runtimes:
- service lifecycle
- action routes
- token auth
- city / env / store infrastructure
The host runtime only needs to create the database object:
- Node.js can use
drizzle-orm/better-sqlite3or Drizzle pg - Cloudflare Workers can use
drizzle-orm/d1 - Federation writes required runtime env into the built-in
envtable on boot
Default Storage
When a Federation needs to move runtime files into first-party storage, register a default storage backend:
import { Federation, R2Storage } from "@downcity/city";
const base = new Federation({ db });
base.storage(R2Storage({
bucket: env.DOWNCITY_STORAGE,
public_url_prefix: env.DOWNCITY_STORAGE_PUBLIC_URL_PREFIX,
}));Services can then access it through ctx.storage. Built-in AI image jobs use this storage after image_fetch succeeds to move remote file part URLs into your own bucket. If storage fails, the original upstream URL is kept and the image job still succeeds.
Common API surface
new Federation({ db })base.use(...)base.storage(...)base.router()base.handleRequest(request)base.health()base.table(name)
Common misunderstandings
Federation is the runtime, not the whole SDK
Federation is the long-running server runtime. Product-side calling uses the City client; see Client SDK.
Federation is not only an HTTP proxy
It also owns built-in tables, token and env infrastructure, service data layers, and hook lifecycle.
Federation is not one provider
Providers, models, services, and custom services are capabilities mounted into Federation, not the Federation itself.
Read next
- For what actually gets mounted into Federation, read Service and Action
- For hooks and extension points, read Hooks and Service Mounting
- For persistence and tables, read Store and Table
- For lower-level method details, read Federation API