Skip to content
Get started

Routing

Routes are registered on an app or a router with a method, a path pattern, and a handler. Matching is exact-first: static segments beat params, params beat wildcards.

PatternMatchesparams
/health/health only{}
/users/:id/users/42{id:'42'}
/teams/:team/members/:id/teams/core/members/7{team:'core',id:'7'}
/assets/*/assets/img/logo.svg{'*':'img/logo.svg'}

Params are always strings; validate and convert in the handler.

Every handler and middleware receives one Context:

FieldTypeDescription
requestRequestThe standard web request — headers, body, method, URL
paramsRecord<string, string>Values captured by the path pattern
queryURLSearchParamsParsed query string
envRecord<string, string>Project secrets and variables
cacheCacheThe regional edge cache
traceTraceThe active tracespan(), set(), id
waitUntil(p: Promise<unknown>) => voidKeep background work alive after the response is sent
api.post('/webhooks/stripe', async ({ request, env, waitUntil }) => {
const event = await verifyStripe(request, env.STRIPE_KEY);
waitUntil(processEvent(event)); // respond now, process after
return Response.json({ received: true });
});

Handlers return a standard Response. Response.json() covers most cases; streams work unchanged:

api.get('/export', async () => {
const stream = buildCsvStream();
return new Response(stream, {
headers: { 'content-type': 'text/csv' },
});
});

vega.router() groups routes so large APIs split cleanly across files. Routers accept the same methods and middleware as an app:

api/routes/users.ts
import { vega } from '@vega/sdk';
export const users = vega.router();
users.get('/', async ({ query, cache }) => {
const page = Number(query.get('page') ?? 1);
const list = await cache.swr(`users:page:${page}`, () => db.users.list(page));
return Response.json(list);
});
users.get('/:id', async ({ params }) =>
Response.json(await db.users.find(params.id)),
);
api/index.ts
import { users } from './routes/users';
api.mount('/v1/users', users);
// GET /v1/users → users.get('/')
// GET /v1/users/42 → users.get('/:id')

Middleware registered with users.use() runs only for routes inside that router, after any app-level middleware.