RouteGraph v1.0.0 is out. It's stable, it's typed, it's not going to rewrite your framework of choice into a decorator soup. → Try it in 90 seconds
v1.0.0 — stable, MIT, no roadmap vaporware

Your folder structure
is your API.

Drop a file, get a route. RouteGraph turns a routes/ directory into a fully validated, self-documenting REST API — on Express, Hono, Fastify, Elysia, or Koa, unchanged. No router file. No boilerplate you wrote at 2am and never touched again.

10
independent packages
5
framework adapters
0
runtime deps in core
1
file you edit to switch frameworks
routes/users/users/[id]/GET/usersPOST/usersGET/users/:idDELETE/users/:id
~/my-api
$ npx @routegraph/cli init --name my-api --yes
◈ scaffolding my-api (express, port 3000)…
✓ routes/ ✓ package.json ✓ tsconfig.json
$ cd my-api && pnpm install && pnpm dev
◈ RouteGraph Dev Server
API → http://localhost:3000/api
Docs → http://localhost:3000/_routegraph
Routes 5 registered · Watch enabled

You’ve written this router by hand before

router.get('/users', listUsers)
router.get('/users/:id', getUser)
router.post('/users', createUser)
router.delete('/users/:id', deleteUser)
router.get('/users/:id/posts', listUserPosts)
// …repeat for every resource, keep it in sync with the handlers,
// keep the docs in sync with the validation, keep the validation
// in sync with whatever the frontend actually sends this week.

Every new endpoint means touching a file that has nothing to do with the endpoint. RouteGraph deletes that file.

How it resolves

Drop a file

routes/users/[id]/GET.ts

It’s a route

export const config = {
  request: { params: z.object({ id: z.string() }) },
  response: { 200: UserSchema }
} satisfies RouteConfig
 
export default async (req, res) => {
  res.status(200).json(findUser(req.params.id))
}

It runs on whatever you’re using today

ExpressHonoFastifyElysiaKoa

Same routes. Same middleware. Same types. One line changes — your server’s entry point.


Everything a router should have shipped with


Not a framework. A routing layer.

RouteGraph doesn’t want to replace Express, Hono, Fastify, Elysia, or Koa — it wants to stop you from writing the part of them that was never interesting. No decorators. No dependency-injection container. No modules that exist to hold other modules. Just files, functions, and a RouteGraph that walks your routes/ directory once at startup and hands the result to whichever adapter you picked.