Skip to main content

Router

Router is a globally available class that provides Express.js-compatible routing for your functions. It lets you define method-specific handlers and middleware, with full support for path parameters and wildcards, powered by path-to-regexp.

A Router instance is itself a function, so it can be used directly as your function's export:

const router = new Router();

router.get('/', (req, res) => {
res.json({ message: 'Hello, world!' });
});

module.exports = router;

Creating a Router

const router = new Router();

No arguments are needed. Router is available as a global — no require() call is necessary.

HTTP Method Handlers

Register handlers for specific HTTP methods and paths.

router.get(path, ...handlers)
router.post(path, ...handlers)
router.put(path, ...handlers)
router.patch(path, ...handlers)
router.delete(path, ...handlers)
router.options(path, ...handlers)
router.head(path, ...handlers)
router.all(path, ...handlers) // matches any HTTP method

Example

const router = new Router();

router.get('/users', (req, res) => {
res.json({ users: [] });
});

router.post('/users', (req, res) => {
const { name } = req.body;
res.status(201).json({ id: 1, name });
});

router.delete('/users/:id', (req, res) => {
res.status(204).end();
});

module.exports = router;

Path Parameters

Use :name syntax to capture segments from the path. Captured values are available on req.params.

router.get('/users/:id', (req, res) => {
res.json({ userId: req.params.id });
});

router.get('/posts/:postId/comments/:commentId', (req, res) => {
res.json({
postId: req.params.postId,
commentId: req.params.commentId,
});
});

Wildcard Matching

Use * to match any remaining path segments.

router.get('/files/*', (req, res) => {
res.json({ path: req.params[0] });
});

Middleware

router.use() registers middleware that runs for all matching requests. Unlike method handlers, use() matches by path prefix — a handler registered for /api will run for /api, /api/users, /api/users/123, etc.

// Run for all requests
router.use((req, res, next) => {
console.log(req.method, req.path);
next();
});

// Run for /api prefix only
router.use('/api', (req, res, next) => {
const token = req.headers['authorization'];
if (!token) return res.status(401).json({ error: 'Unauthorized' });
next();
});

If a middleware does not call next(), the request chain stops there. If it calls next(error), a 500 error is sent.

Chaining

All registration methods return the router instance for chaining.

const router = new Router();

router
.get('/', (req, res) => res.send('Home'))
.get('/about', (req, res) => res.send('About'))
.post('/contact', (req, res) => res.json({ ok: true }));

module.exports = router;

Async Handlers

Handlers can be async functions. Errors thrown inside async handlers are caught and result in a 500 response.

router.get('/data', async (req, res) => {
const data = await fetch('https://api.example.com/data').then(r => r.json());
res.json(data);
});

Multiple Handlers

You can pass multiple handlers to any method. Each must call next() to pass control to the next handler.

function authenticate(req, res, next) {
if (!req.headers['authorization']) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
}

router.get('/protected', authenticate, (req, res) => {
res.json({ secret: 'data' });
});

Fallback (404 Handler)

Register a use() handler at the end of the chain to catch unmatched requests.

router.use((req, res) => {
res.status(404).json({ error: `Cannot ${req.method} ${req.path}` });
});

Without a fallback, the router automatically responds with 404 Cannot METHOD /path.

Complete Example

const router = new Router();

// Logging middleware
router.use((req, res, next) => {
console.log(`${req.method} ${req.path}`);
next();
});

// Routes
router.get('/', (req, res) => {
res.json({ status: 'ok' });
});

router.get('/users/:id', async (req, res) => {
const user = await kv.get(`user:${req.params.id}`);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});

router.post('/users', async (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'name and email are required' });
}
const id = crypto.randomUUID();
await kv.set(`user:${id}`, { id, name, email });
res.status(201).json({ id, name, email });
});

router.delete('/users/:id', async (req, res) => {
await kv.delete(`user:${req.params.id}`);
res.status(204).end();
});

// 404 fallback
router.use((req, res) => {
res.status(404).json({ error: 'Not found' });
});

module.exports = router;

Reference

MethodSignatureDescription
get(path, ...handlers)Handle GET requests
post(path, ...handlers)Handle POST requests
put(path, ...handlers)Handle PUT requests
patch(path, ...handlers)Handle PATCH requests
delete(path, ...handlers)Handle DELETE requests
options(path, ...handlers)Handle OPTIONS requests
head(path, ...handlers)Handle HEAD requests
all(path, ...handlers)Handle any HTTP method
use([path], ...handlers)Register middleware (prefix match)