Integrations
Five adapters. One contract: take a loaded RouteGraph, hand back something
your framework already knows how to mount. Same routes/ folder underneath
every single one — examples/with-express/ proves it, booting the exact
same routes, middleware, and shared modules from five different entry
points. Pick a framework the way you’d pick a coffee order, not the way
you’d pick a religion.
Runtime coverage
| Adapter | Framework | Runs on | Docs UI auto-mount via routegraph dev |
|---|---|---|---|
@routegraph/express | Express v4/v5 | Node.js | ✓ |
@routegraph/fastify | Fastify v4/v5 | Node.js | ✓ |
@routegraph/koa | Koa v2 | Node.js | ✓ |
@routegraph/hono | Hono v4 | Node.js Bun Deno Workers | manual wiring |
@routegraph/elysia | Elysia | Bun Node (@elysiajs/node) | manual wiring |
Honest gap, not a footnote: routegraph dev mounts the docs UI
automatically for Express, Fastify, and Koa today. Hono and Elysia need one
extra line — see the examples below. It’s on the roadmap to close, not
quietly ignored.
The adapter contract
Every adapter does the same three things:
- Takes your loaded
graphand returns a router/plugin native to that framework. - Normalizes that framework’s request/response into
NormalizedRequest/NormalizedResponsebefore your handler sees them — so your handler code is identical across all five. - Exposes
.rawon both, an escape hatch to the underlying framework object when you need something adapter-specific.
Pick one
import express from 'express'
import { RouteGraph } from '@routegraph/core'
import { createExpressRouter } from '@routegraph/express'
import { createDocsMiddleware } from '@routegraph/docs'
const graph = new RouteGraph({ routesDir: './routes' })
await graph.load()
const app = express()
app.use(express.json())
app.use('/api', createExpressRouter(graph))
app.use('/_routegraph', createDocsMiddleware(graph))
app.listen(3000)The reference adapter. If a bug report only reproduces on one framework, it’s usually not this one.
Switching frameworks, side by side
- import express from 'express'
+ import { Hono } from 'hono'
+ import { serve } from '@hono/node-server'
import { RouteGraph } from '@routegraph/core'
- import { createExpressRouter } from '@routegraph/express'
+ import { createHonoRouter } from '@routegraph/hono'
const graph = new RouteGraph({ routesDir: './routes' })
await graph.load()
- const app = express()
- app.use(express.json())
- app.use('/api', createExpressRouter(graph))
- app.listen(3000)
+ const app = new Hono()
+ app.route('/api', createHonoRouter(graph))
+ serve({ fetch: app.fetch, port: 3000 })Your routes/ folder didn’t change. Not one file. Middleware, Zod
schemas, handler bodies — untouched. Only the server entry point moved.