@routegraph/cli
v1.1.0
Published
The routegraph CLI: init, dev, build, validate, generate-client, export-docs.
Downloads
34
Readme
@routegraph/cli
The routegraph command-line tool: scaffold projects, run a dev server with hot reload and docs, validate routes, generate a typed client, and export docs/OpenAPI.
Installation
pnpm add -D @routegraph/cli # local, recommended — scripts call `routegraph ...` via package.json
npx @routegraph/cli init # or run one-off without installingCommands
routegraph init
Interactive project scaffold. Skip prompts with --yes to use defaults (Express, port 3000, all features, pnpm).
routegraph init [--name <name>] [--adapter <name>] [--dir <path>] [--yes]| Flag | Default | Notes |
|---|---|---|
| --name | my-api | Also used as the scaffolded package.json name |
| --adapter | express | express \| hono \| fastify \| elysia \| koa |
| --dir | ./<name> | Target directory |
| --yes | off | Skip all prompts, scaffold with defaults immediately |
The interactive wizard (when --yes is not passed) asks: project name → framework (with a one-line hint per option) → port → features (API Docs / Hot Reload / OpenAPI / Typed Client, multi-select) → package manager (pnpm/npm/bun) → a summary box → a final "Create project?" confirmation. In a non-TTY environment (CI, pipes), every prompt falls back to logging its default answer instead of blocking.
Scaffolds: routes/{_shared/db.ts, health/GET.ts, users/GET.ts, users/POST.ts, users/[id]/GET.ts, users/[id]/DELETE.ts}, middleware/logger.ts, an adapter-specific index.ts, package.json, and a tsconfig.json that extends @routegraph/core/tsconfig.json.
routegraph dev
routegraph dev [--dir ./routes] [--adapter express] [--port 3000] [--host localhost] [--docs|--no-docs] [--no-watch]Loads your routes, dynamically imports the chosen adapter + framework from your project's own node_modules, starts a server, and (by default) starts @routegraph/watcher and mounts the docs UI. Prints a startup banner:
◈ RouteGraph Dev Server
API → http://localhost:3000/api
Docs → http://localhost:3000/_routegraph
Adapter express
Routes 9 registered
Watch enabled
Press Ctrl+C to stop
GET /
GET /health
...followed by a compact list of every registered route. On a hot-reload event, prints a timestamped diff line per changed/added/removed file:
[14:32:07] ↻ routes/users/GET.ts changed — reloaded in 3ms
[14:32:19] + routes/users/[id]/posts/GET.ts addedDocs UI auto-mounting works out of the box for express, fastify, and koa. For hono and elysia, --docs currently logs a warning and skips mounting — wire createDocsMiddleware manually (see @routegraph/docs's README). The fastify/elysia adapter loading itself is also currently broken via this command — see the init note above; use the manual server-setup pattern from examples/with-express/index.fastify.ts / index.elysia.ts for those two frameworks in the meantime.
Port already in use: exits with code 1 and a friendly Port <n> is already in use. Try --port <n+1> message rather than an unhandled EADDRINUSE stack trace.
routegraph build
routegraph build [--dir ./routes] [--out ./dist] [--docs-out ./dist/docs] [--skip-docs] [--skip-types] [--skip-validate] [--ci]Pipeline, in order: validate routes → tsc --noEmit (via npx tsc) → generate <out>/routemap.ts (skippable with --skip-types) → export static docs to <docs-out> + <out>/openapi.json (skippable with --skip-docs). Any step failing stops the build and returns exit code 1; a validation or typecheck failure prints the specific issues before exiting.
✓ RouteGraph Build Complete
✓ Validate 9 routes validated (12ms)
✓ TypeScript TypeScript — no errors (1840ms)
✓ RouteMap RouteMap generated → dist/routemap.ts (8ms)
✓ Docs Docs exported → dist/docs/index.html (14.2 KB) (22ms)
✓ OpenAPI OpenAPI spec → dist/openapi.json (6ms)
Build time: 1.89s--ci strips ANSI color codes and disables spinner animation (forces the same plain output every command already falls back to automatically when stdout isn't a TTY).
routegraph routes
routegraph routes [--dir ./routes] [--base <url>] [--json] [--filter <METHOD>] [--tag <tag>] [--sort path|method|tag] [--watch]Prints a table (Method | Path | Description) plus a method-count bar chart. --json prints Array<{ method, path, description, tags, deprecated }> instead (and disables --watch's re-render loop). --watch re-renders on every route file change until Ctrl+C.
routegraph validate
routegraph validate [--dir ./routes] [--strict] [--fix]Imports every route file and checks: is there a default export, and is it a function? Is the config export (if present) an object? --strict additionally requires every route to have a config export. Exits 1 if any route has issues; prints a fix hint under each failing route where one applies (e.g. export default async function handler(req, res) { ... }). --fix is currently a stub — it prints "Auto-fix coming soon" and makes no changes.
routegraph generate-client
routegraph generate-client [--dir ./routes] [--out ./routemap.ts] [--watch]Writes the AppRouteMap type file consumed by @routegraph/client's createClient<AppRouteMap>(). Prints a preview box of the first 10 lines of the generated file, plus the exact import line to use. --watch regenerates on every route change until Ctrl+C.
routegraph export-docs
routegraph export-docs [--dir ./routes] [--out <path>] [--base <url>] [--format ui|openapi]--format ui (default): static docs site via @routegraph/docs's exportDocs(), written to --out (default ./docs-dist). --format openapi: an OpenAPI 3.1.0 JSON document via graph.toOpenAPISpec(), written to --out (default ./openapi.json). --base (default http://localhost:3000) only affects the ui format's Try It Out panel default base URL.
Non-TTY / CI behavior
Every interactive element (spinners, the init wizard's prompts, box-drawn banners and tables) detects whether stdout/stdin is a TTY and automatically falls back to plain, single-line, colorless output when it isn't — no flag required for CI/pipes to get clean logs. routegraph build --ci forces that same plain mode even in an interactive terminal, for consistent CI log capture regardless of how the job happens to be invoked.
How route files load without a separate build step
The CLI registers a node:module loader hook at startup (register() with a data: URL module) that uses Node's built-in stripTypeScriptTypes() (Node 22.13+/23+) to strip TypeScript syntax from your route files on the fly as they're import()-ed, plus a resolve hook that retries a literal .js specifier as .ts (route files import siblings with a .js extension per NodeNext convention, even though the files on disk are .ts). This means CLI commands that load your routes (dev, validate, routes, build, generate-client, export-docs) work directly against your .ts source with no tsx/ts-node dependency of their own — though the example app's dev:manual-style scripts do use tsx for running an index.ts entry point directly, outside the CLI.
