
Security News
upm Launches as a Fast, Tiny Package Manager Written in TypeScript
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.
Routup is a minimalistic, runtime-agnostic HTTP routing framework for Node.js, Bun, Deno, Cloudflare Workers, and Service Workers.
Handlers return values directly — routup converts them to Web Response objects automatically, with built-in support for ETags, content negotiation, per-handler timeouts, and cooperative cancellation via AbortSignal.
Table of Contents
npm install routup --save
Request / Response for portabilityBlobs, or Response directlyevent.next()LinearRouter (default), TrieRouter, or SmartRouter (auto-selects); opt-in LRU lookup cacheAbortSignal cooperative cancellationReadableStream responses and createEventStream() for server-sent eventssendFile() with ETag, range, and MIME detection(req, res, next) handlers via fromNodeHandler()To read the docs, visit https://routup.dev
Handlers receive an event and return a value. Routup converts the return value to a Web Response automatically.
Shorthand
import { App, defineCoreHandler, defineErrorHandler, serve } from 'routup';
const app = new App();
app.get('/', defineCoreHandler(() => 'Hello, World!'));
app.get('/greet/:name', defineCoreHandler((event) => `Hello, ${event.params.name}!`));
app.use(defineErrorHandler((error) => ({ error: error.message })));
serve(app, { port: 3000 });
Verbose
import { App, defineCoreHandler, serve } from 'routup';
const app = new App();
app.use(defineCoreHandler({
path: '/',
method: 'GET',
fn: () => 'Hello, World!',
}));
app.use(defineCoreHandler({
path: '/greet/:name',
method: 'GET',
fn: (event) => `Hello, ${event.params.name}!`,
}));
serve(app, { port: 3000 });
| Return type | Response |
|---|---|
string | text/plain |
object / array | application/json |
Response | Passed through as-is |
ReadableStream | Streamed to client |
Blob | Sent with blob's content type |
null | Empty response (status from event.response) |
Middleware calls event.next() to continue the pipeline:
app.use(defineCoreHandler(async (event) => {
console.log(`${event.method} ${event.path}`);
return event.next();
}));
The route table is pluggable via the router option. The default LinearRouter is best for small apps; swap to TrieRouter for radix-trie matching on apps with many routes, or SmartRouter to auto-select between the two based on the registered route shape at first lookup. Each router accepts an optional cache for memoizing lookups — opt-in via LruCache (or any ICache implementation); pass null to disable.
import { App, TrieRouter, LruCache, defineCoreHandler } from 'routup';
const app = new App({
router: new TrieRouter({ cache: new LruCache() }), // omit `cache` for no memoization
});
Configure a global timeout for the whole pipeline, a default per-handler timeout, or both. When a deadline fires, event.signal is aborted so handlers can cooperatively cancel signal-aware work; if nothing recovers in time, routup returns 408 Request Timeout.
const app = new App({
timeout: 30_000, // entire request
handlerTimeout: 5_000, // default per handler; handlers can narrow further
});
app.get('/fetch', defineCoreHandler(async (event) => {
const res = await fetch('https://api.example.com', { signal: event.signal });
return res.json();
}));
Routup runs on Node.js, Bun, Deno, and Cloudflare Workers. In most cases, import from routup:
import { App, defineCoreHandler, serve } from 'routup';
const app = new App();
app.get('/', defineCoreHandler(() => 'Hello, World!'));
serve(app, { port: 3000 });
For runtime-specific APIs (e.g. toNodeHandler), use the corresponding entrypoint like routup/node.
Scaffold a new project from any starter in routup/templates with degit:
npx degit routup/templates/node-api my-app
| Template | Runtime | Highlights |
|---|---|---|
| node-api | Node.js >=22 | JSON API with @routup/body |
| cloudflare-worker | Cloudflare Workers | Configured with wrangler |
| bun-decorators | Bun | Class-based routing via @routup/decorators |
Routup is minimalistic by design. Plugins extend the framework with additional functionality.
| Name | Description |
|---|---|
| assets | Serve static files from a directory |
| basic | Bundle of body, cookie, and query plugins |
| body | Read and parse the request body |
| cookie | Read and parse request cookies |
| cors | Cross-Origin Resource Sharing (CORS) middleware |
| decorators | Class, method, and parameter decorators |
| i18n | Translation and internationalization |
| logger | HTTP request logger with morgan-compatible tokens and presets |
| prometheus | Collect and serve Prometheus metrics |
| query | Parse URL query strings |
| rate-limit | Rate limit incoming requests |
| rate-limit-redis | Redis adapter for rate-limit |
| swagger-ui | Mount swagger-ui-dist on any path |
How routup stacks up against other popular Node.js routing frameworks. This is a best-effort summary; check each project's docs for the full picture.
| routup | Hono | Express | Fastify | |
|---|---|---|---|---|
| Runtimes | Node, Bun, Deno, Cloudflare, Service Worker | Node, Bun, Deno, Cloudflare, Lambda, Vercel | Node | Node |
Web-standard Request / Response | ✅ | ✅ | ❌ | ❌ |
| Return-based handlers | ✅ | ✅ | ❌ | ❌ |
| TypeScript-first | ✅ | ✅ | community types | ✅ |
| Tree-shakeable helpers | ✅ | ✅ | ❌ | ❌ |
Onion middleware (next()) | ✅ | ✅ | linear next() | lifecycle hooks |
| Pluggable router (linear / trie) | ✅ linear, trie, or auto-select | trie only | linear only | radix only |
| Built-in ETag + 304 | ✅ | ❌ | via plugin | via plugin |
Per-handler timeout + AbortSignal | ✅ | ❌ | ❌ | server-level |
| Class-based routes (decorators) | ✅ via plugin | ❌ | ❌ | ❌ |
| Express middleware bridge | ✅ fromNodeHandler | ❌ | n/a | limited |
| Schema validation built-in | ❌ | ❌ | ❌ | ✅ |
Before starting to work on a pull request, it is important to review the guidelines for contributing and the code of conduct. These guidelines will help to ensure that contributions are made effectively and are accepted.
Made with 💚
Published under MIT License.
FAQs
Routup is a minimalistic http based routing framework.
The npm package routup receives a total of 1,374 weekly downloads. As such, routup popularity was classified as popular.
We found that routup demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.