snarl#
a minimal web framework for deno
features#
- tiny core, zero runtime bloat; built entirely on top of deno's stdlib
- flexible type-safe routing with first-class support for path parameters, route groups, and wildcard methods
- chainable context helpers and type-safe request/response handling
- composable middleware stack with built-in support for CORS, logging, security headers, rate limiting
- robust file serving featuring ETag caching,
Rangerequests, and security options (e.g. dotfile protection) - native SSE and WebSockets support
- built-in precompiled jsx/tsx renderer
- multipart file uploads and automatic body parsing
- global error handling and cookie jar management
performance comparison#
frameworks were benchmarked using autocannon. snarl 0.3.0 is set as baseline (1x).
| Scenario | snarl | hono | oak | express |
|---|---|---|---|---|
| plain text | 1.00x 73,554 req/s |
1.36x 100,346 req/s |
0.53x 38,960 req/s |
0.30x 22,398 req/s |
| JSON | 1.00x 73,005 req/s |
0.88x 64,200 req/s |
0.53x 38,842 req/s |
0.26x 18,982 req/s |
| path params | 1.00x 73,062 req/s |
0.80x 58,573 req/s |
0.48x 34,903 req/s |
0.25x 18,190 req/s |
| query params | 1.00x 71,830 req/s |
0.87x 62,502 req/s |
0.43x 30,702 req/s |
0.28x 20,362 req/s |
quick start#
// ... deno.json
{
"imports": {
"@july/snarl": "jsr:@july/snarl"
},
"compilerOptions": {
"jsx": "precompile",
"jsxImportSource": "@july/snarl",
"lib": ["deno.ns", "dom", "dom.iterable"]
}
}
import { createRouter, logger } from "@july/snarl";
const app = createRouter();
app.use(logger());
app.get("/", (ctx) => {
return ctx.html(
"<!DOCTYPE html>" + (
<html>
<head>
<title>example paige</title>
</head>
<body>
<h1>welcom</h1>
<p>i meant page* haiiiii</p>
</body>
</html>
),
);
});
app.get("/users/:id", (ctx) => {
const { id } = ctx.params;
return ctx.json({ user: id });
});
app.post("/users", async (ctx) => {
const body = await ctx.body();
return ctx.created(body);
});
Deno.serve(app.fetch);