Server Adapters
TypoKit is not an HTTP server. It is a typed application framework that compiles your route contracts, validators, and middleware into a portable route table — then delegates actual HTTP handling to a server adapter.
This separation means you can swap HTTP frameworks without changing a single handler, middleware, or contract.
The Ownership Boundary
Section titled “The Ownership Boundary”Understanding what TypoKit owns versus what the adapter owns is key to using the system effectively.
| Concern | Owner | Details |
|---|---|---|
| Request validation | TypoKit | Compiled Typia validators run on every request |
| Response serialization | TypoKit | fast-json-stringify for typed output |
| Typed middleware pipeline | TypoKit | defineMiddleware with context type-narrowing |
| Context creation | TypoKit | ctx.log, ctx.fail(), ctx.user, ctx.requestId |
| Error handling | TypoKit | AppError → structured ErrorResponse |
| Request lifecycle tracing | TypoKit | OpenTelemetry spans per request |
| Debug sidecar integration | TypoKit | Dev-mode diagnostics |
| Compiled route table | TypoKit | Portable radix-tree data structure |
| HTTP parsing & connections | Adapter | Keep-alive, chunked encoding, etc. |
| Route registration | Adapter | Translates compiled route table → framework-native routes |
| Platform-specific optimizations | Adapter | Bun.serve(), Deno.serve(), etc. |
| Framework-native middleware | Adapter | Fastify plugins, Hono middleware, Express middleware |
Request Processing Order
Section titled “Request Processing Order”Every request flows through the same pipeline regardless of which adapter you choose:
Incoming HTTP Request │┌────────▼─────────────┐│ Server Adapter ││ ││ 1. HTTP parsing ││ 2. Framework-native ││ middleware (CORS, ││ compression, etc) ││ 3. Normalize request ││ → TypoKitRequest │└────────┬─────────────┘ │┌────────▼─────────────┐│ TypoKit Core ││ ││ 4. Typed middleware ││ chain (sorted by ││ priority) ││ 5. Request ││ validation ││ 6. Handler execution ││ 7. Response ││ serialization ││ 8. Error handling ││ 9. OTel span close │└────────┬─────────────┘ │┌────────▼─────────────┐│ Server Adapter ││ ││ 10. Write HTTP ││ response │└──────────────────────┘The ServerAdapter Interface
Section titled “The ServerAdapter Interface”Every adapter implements this interface from @typokit/core:
export interface ServerAdapter { name: string;
// Translate compiled route table into framework-native routes registerRoutes( routeTable: CompiledRouteTable, handlerMap: HandlerMap, middlewareChain: MiddlewareChain, validatorMap?: ValidatorMap, serializerMap?: SerializerMap, ): void;
// Start the HTTP server listen(port: number): Promise<ServerHandle>;
// Convert framework-native request → TypoKitRequest normalizeRequest(raw: unknown): TypoKitRequest;
// Convert TypoKitResponse → framework-native response writeResponse(raw: unknown, response: TypoKitResponse): void;
// Escape hatch for framework-native plugins/server instance getNativeServer?(): unknown;}The registerRoutes method receives the compiled route table — a portable radix-tree data structure — and translates it into whatever the underlying framework needs. The normalizeRequest and writeResponse methods handle the conversion between framework-specific types and TypoKit’s normalized types.
Available Adapters
Section titled “Available Adapters”Native Server (@typokit/server-native)
Section titled “Native Server (@typokit/server-native)”The default adapter. Zero external dependencies. Uses the compiled radix tree directly for O(k) route lookup where k is the number of path segments.
import { createApp } from '@typokit/core';import { NativeAdapter } from '@typokit/server-native';
const app = createApp({ adapter: new NativeAdapter(),});
app.register(userRoutes);app.register(postRoutes);
await app.listen(3000);Best for: New projects, simple APIs, maximum performance, minimal dependency footprint.
Fastify (@typokit/server-fastify)
Section titled “Fastify (@typokit/server-fastify)”Integrates with an existing or new Fastify instance. Walks the compiled route table and registers each route with Fastify’s own router, then hands off to TypoKit’s pipeline for validation and handling.
import { createApp } from '@typokit/core';import { FastifyAdapter } from '@typokit/server-fastify';import Fastify from 'fastify';
const fastify = Fastify({ logger: true });
// Use Fastify plugins as usualawait fastify.register(import('@fastify/cors'), { origin: '*' });await fastify.register(import('@fastify/compress'));
const app = createApp({ adapter: new FastifyAdapter(fastify),});
app.register(userRoutes);await app.listen(3000);Best for: Teams already using Fastify, or needing Fastify’s plugin ecosystem.
Hono (@typokit/server-hono)
Section titled “Hono (@typokit/server-hono)”Runs anywhere Hono runs — Node.js, Bun, Deno, and Cloudflare Workers.
import { createApp } from '@typokit/core';import { HonoAdapter } from '@typokit/server-hono';import { Hono } from 'hono';import { cors } from 'hono/cors';
const hono = new Hono();hono.use('*', cors());
const app = createApp({ adapter: new HonoAdapter(hono),});
app.register(userRoutes);await app.listen(3000);Best for: Multi-runtime deployments, edge computing, Cloudflare Workers.
Express (@typokit/server-express)
Section titled “Express (@typokit/server-express)”Migration path for teams moving from Express to TypoKit.
import { createApp } from '@typokit/core';import { ExpressAdapter } from '@typokit/server-express';import express from 'express';import cors from 'cors';
const expressApp = express();expressApp.use(cors());expressApp.use(express.json());
const app = createApp({ adapter: new ExpressAdapter(expressApp),});
app.register(userRoutes);await app.listen(3000);Best for: Incremental migration from Express, teams with existing Express middleware they need to keep.
When to Use Native vs Bring-Your-Own
Section titled “When to Use Native vs Bring-Your-Own”Use the native adapter when:
- Starting a new project from scratch
- You want the smallest possible dependency tree
- You don’t need framework-specific plugins
- Maximum performance matters (direct radix-tree lookup, no framework overhead)
Use a framework adapter when:
- You have an existing codebase using that framework
- You need framework-specific plugins (e.g., Fastify’s schema-based serialization, Express session middleware)
- You’re incrementally adopting TypoKit — mount TypoKit routes alongside existing framework routes
- Your deployment target requires it (e.g., Hono for Cloudflare Workers)
Platform Adapters: A Separate Axis
Section titled “Platform Adapters: A Separate Axis”Platform adapters and server adapters are orthogonal concerns. Platform adapters handle JavaScript runtime differences (Node.js, Bun, Deno). Server adapters handle HTTP framework choice. You choose both independently.
Compatibility Matrix
Section titled “Compatibility Matrix”| Node.js | Bun | Deno | |
|---|---|---|---|
| TypoKit Native | ✅ | ✅ | ✅ |
| Fastify | ✅ | ✅ (compat) | ❌ |
| Hono | ✅ | ✅ | ✅ |
| Express | ✅ | ✅ (compat) | ❌ |
Platform adapter packages:
@typokit/platform-node— Uses Node.jshttp/http2modules@typokit/platform-bun— UsesBun.serve()for maximum Bun performance@typokit/platform-deno— UsesDeno.serve()for native Deno support
Configuring the Platform
Section titled “Configuring the Platform”import { createApp } from '@typokit/core';import { NativeAdapter } from '@typokit/server-native';import { BunPlatform } from '@typokit/platform-bun';
const app = createApp({ adapter: new NativeAdapter(), platform: new BunPlatform(),});
await app.listen(3000);When no platform is specified, TypoKit auto-detects the current runtime.
The getNativeServer() Escape Hatch
Section titled “The getNativeServer() Escape Hatch”All adapters provide an optional getNativeServer() method that returns the underlying framework instance. Use this when you need direct access to framework-specific APIs:
const app = createApp({ adapter: new FastifyAdapter(fastify),});
// Access the raw Fastify instanceconst nativeFastify = app.adapter.getNativeServer();nativeFastify.addHook('onClose', async () => { await db.close();});Next Steps
Section titled “Next Steps”- Building a Custom Server Adapter — Step-by-step guide to implementing the
ServerAdapterinterface - Middleware and Context — How typed middleware integrates with the adapter pipeline
- Error Handling — How errors flow through the adapter layer
- Building Your First API — End-to-end tutorial using the native adapter