Quickstart
You’ll have a validated, documented, hot-reloading REST API before your coffee finishes brewing. Realistically before it’s done pouring.
Prerequisites: Node.js 18+, and a package manager. We show pnpm
below because that’s what the monorepo itself uses — npm and bun work
identically.
Option A — the CLI does it for you
routegraph init runs an interactive wizard by default — project name,
adapter, port, features, package manager. Pass --yes to skip straight to
the defaults (Express, port 3000, every feature, pnpm).
Option B — wire it up yourself
Install
pnpm add @routegraph/core @routegraph/express zod
pnpm add -D @routegraph/cli @routegraph/watcher @routegraph/docsThere is no unscoped routegraph package — always install @routegraph/core
plus the adapter for your framework. zod is a peer dependency everywhere.
Write your first route
import { z } from 'zod'
import type { RouteConfig, RouteHandler } from '@routegraph/core'
export const config = {
description: 'Get a single user by their ID',
tags: ['users'],
request: {
params: z.object({ id: z.string() }),
},
response: {
200: z.object({ id: z.string(), name: z.string(), email: z.string().email() }),
404: z.object({ error: z.string() }),
},
} satisfies RouteConfig
const handler: RouteHandler<typeof config> = async (req, res) => {
// req.params.id is typed as `string` — inferred from `config.request.params`
const user = findUserById(req.params.id)
if (!user) return res.status(404).json({ error: 'User not found' })
res.status(200).json(user)
}
export default handlerconfig is optional. export default handler alone is a valid,
unvalidated route — add schemas whenever you’re ready for validation,
inferred types, and free docs.
Boot it
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)Call it
curl http://localhost:3000/api/users/1Then open http://localhost:3000/_routegraph — every route you just wrote,
rendered into a searchable, try-it-out UI. You didn’t write a line of docs.
What you get, immediately
GET /health | scaffolded for you, always green |
| Validation | 400 on bad input, before your handler runs |
| Docs | live at /_routegraph, generated from the same Zod schemas |
| Types | inferred end to end, no .d.ts to hand-maintain |
| Hot reload | add a route file mid-pnpm dev, it’s live |
That’s the entire quickstart. There is no part two where we admit you also
need a router.config.js.