A zero-dependency HTTP framework for Node.js and the Edge.
Volten is a small, fast HTTP framework with two first-class runtimes. Run on Node.js with app.listen(). Deploy to Cloudflare Workers, Bun, or any Web-fetch-compatible runtime with app.createFetch(). The same routes, the same middleware, the same ctx API — zero adapter overhead, zero extra dependencies.
This is not a compatibility shim or a "it might work" footnote. Volten ships a first-class dual-runtime architecture — every route you write runs identically on Node.js and on any Web Fetch-compatible edge runtime, out of the box.
import { App } from "volten";
const app = new App();
app.use((ctx, next) => {
console.log(`${ctx.method} ${ctx.url}`);
next();
});
app.get("/users/:id", (ctx) => {
ctx.json({ userId: ctx.params.id, status: "active" });
});
app.post("/data", async (ctx) => {
const body = await ctx.body();
ctx.json({ received: body });
});
// ─── Node.js ──────────────────────────────────────────────
app.listen(3000);
// ─── Cloudflare Workers / Bun / Deno / any WinterCG runtime
export default { fetch: app.createFetch() };That's the whole file. No separate entry points. No runtime checks. No adapter packages to install. The same app instance handles both — you pick how to expose it.
Volten resolves the Node ↔ Edge gap internally, at the context level. Every incoming request is wrapped in a RequestContext that presents the same unified API regardless of the underlying platform:
| What your handler uses | Node.js under the hood | Edge under the hood |
|---|---|---|
ctx.method / ctx.url / ctx.path |
IncomingMessage |
Web Request |
ctx.headers |
Node header object | Headers → plain object |
await ctx.body() |
Streams the Node socket | Awaits Request.json() / .text() |
ctx.json(data) |
ServerResponse.end() |
Builds a Web Response |
ctx.send(text) |
ServerResponse.end() |
Builds a Web Response |
ctx.status(code) |
res.statusCode |
Edge response status |
ctx.setHeader(k, v) |
res.setHeader() |
Headers.set() |
ctx.cookies |
Parsed from Node headers | Parsed from Web headers |
There is no runtime dispatch in your handler code. The adapter layer is invisible — your logic stays clean and portable.
On Node.js, Volten pre-allocates a pool of NodeRequestContext objects (default: 2 048) and recycles them across requests to eliminate GC pressure. On Edge runtimes, a parallel pool of EdgeRequestContext objects does the same thing, with the same recycling strategy. Neither pool involves the other runtime — there is no cross-runtime tax.
- Zero runtime dependencies — only the Node.js core API (or the Web platform API on edge).
- Dual runtime —
app.listen()for Node,app.createFetch()for Cloudflare Workers / Bun / Deno / WinterCG. - Adaptive Traffic Triage — Event-loop immune routing that automatically drops low-priority requests at the socket level when Node is under stress.
- Trie-based router — dynamic params (
/users/:id) and wildcards. - Middleware chain — global and per-route, with cascading composition. Works identically on both runtimes.
- Native body parsing — JSON, form-urlencoded, text, raw, and streaming multipart.
- Streaming responses — first-class backpressure-aware write/stream API on
ctx. - Cookies and sessions — built-in
ctx.cookieshelpers. - Static file serving — path-traversal-safe file delivery (Node only).
- Error handling — global and custom error handlers with safe fallbacks on both runtimes.
- Context pooling — reusable
RequestContextobjects on both runtimes to reduce allocation overhead.
volten/
└─ 🔒 No nested node_modules
└─ 🔒 No sudden security deprecations
└─ 🔒 100% auditable source code
Volten is public on npm. Install it with any package manager:
pnpm add voltenimport { App } from "volten";
const app = new App();
app.get("/", (ctx) => {
ctx.json({ message: "Welcome to Volten" });
});
app.listen(3000, () => {
console.log("Volten listening on http://localhost:3000");
});import { App } from "volten";
const app = new App();
app.get("/", (ctx) => {
ctx.json({ message: "Welcome to Volten" }); // exact same handler
});
export default { fetch: app.createFetch() };No changes to your routes or middleware. Swap app.listen() for app.createFetch() and you're done.
The examples/ directory contains runnable, self-contained samples:
| # | File | Demonstrates |
|---|---|---|
| 01 | 01-hello-world.js |
Minimal server and route registration |
| 02 | 02-middleware.js |
Global and per-route middleware |
| 03 | 03-json-response.js |
JSON responses with ctx.json |
| 04 | 04-routing-and-wildcards.js |
Dynamic params and wildcards |
| 05 | 05-global-error-handling.js |
Centralized error handling |
| 06 | 06-static-file-serving.js |
Static files via volten.static() |
| 07 | 07-body-parsing.js |
JSON, form, and text body parsing |
| 08 | 08-cookies-and-sessions.js |
Cookie parsing and serialization |
| 09 | 09-stream-responses.js |
Streaming responses with backpressure |
| 10 | 10-cors-and-security.js |
CORS, security headers, and hardening |
- Routing: Implemented as a trie (
RouteTree). Match cost is proportional to path depth, not to the number of registered routes. - Dual context:
NodeRequestContextwraps Node'sIncomingMessage/ServerResponse.EdgeRequestContextwraps the WebRequest/ResponseAPI. Both extend the same baseRequestContext, so every handler runs against an identical interface. - Context pooling: Both context types are pooled (default: 2 048 each) and reset between requests to minimize GC pressure.
- Streaming: On Node, responses use
ServerResponsedirectly with backpressure-awarectx.write/ctx.stream/ctx.end. On Edge, responses are built as a WebResponseobject.
Volten is in active alpha. The core API is functional but may change before a 1.0 release. It is not yet recommended for production workloads.
The strict zero-dependency constraint means every utility — parsers, router, helpers — is implemented in-tree. See CONTRIBUTING.md for the rules and rationale.
Contributions are welcome. Before opening a PR:
- Read
CONTRIBUTING.md— the zero-dependency rule is non-negotiable for production code. - Open an issue for non-trivial features so the design can be discussed first.
- Run
pnpm run buildand verify your changes against theexamples/directory. - Run
pnpm run lintandpnpm run formatbefore submitting.
MIT © VoltenJS
