Tirne — from Old English “structure, strength” — structure over boilerplate. A minimal, type-safe web framework for Multi Runtime, with edge-native performance and first-class control of side effects."
Explore the full guide to Tirne — a Bun & Edge-native web framework built for speed, structure, and zero boilerplate.
⚡ Sub-millisecond APIs. First-class control of side effects.
👉 Star Tirne on GitHub
Tirne is a declarative, type-safe framework for Bun — designed to make side effects explicit and performance predictable.
Choose your environment:
- Bun
- Cloudflare Workers
This command sets up a ready-to-run Tirne project in seconds.
📣 Love minimal tools that get out of your way? Star the main Tirne repo: https://github.com/Tirne-ts/Tirne
A zero-boilerplate project, tailored for your runtime:
- index.ts with a working router and a / endpoint
- Runtime config files (bunfig.toml, wrangler.toml)
- package.json with minimal scripts and dependencies
Example output:
Tirne is built on 5 core principles: E
- Structure as code — Routes, middleware, and logic are configuration, not behavior. Code is a manifest, not a script.
- Errors are values — TirneErrors carry type, status, and intent. They are thrown, but not hidden.
- Composition over convention — Middleware is composed explicitly, and order is part of the contract.
- Types shape behavior — The structure and safety of your API are defined by its types, not docs.
- Designed for the edge — Built for Bun, optimized for fetch, born in the millisecond age.
- ✅ Structure-first routing — Define your entire API as a single declarative structure
- ✅ Composable middleware — Explicit compose() flow, no decorators or global scope
- ✅ Structured errors — Throw TirneError with type, status, and visibility
- ✅ Built-in response helpers — json(), html(), text(), error() etc... — clean and consistent
- ✅ Edge-native execution — Instant cold start & sub-ms response on Bun, Workers, and Deno
- ✅ No boilerplate — No CLI, no config, no directory rules. Just pure code.
- ✅ Type-safe by design — Routes, handlers, errors, all shaped by TypeScript
All tests were performed using Bun v1.1.0 on an M2 Pro chip (macOS), simulating edge runtime conditions.
❄️ Cold Start | 0.02 ms | 🧊 Essentially unmeasurable — perfect for edge/fetch-based runtimes |
⚡️ First Request | 0.79 ms | 🚀 Beats the 1ms barrier. Ideal for latency-critical APIs |
🔁 Requests/sec | 90,489 rps | 🔥 Comparable to Hono, surpasses Express by 10x+ |
📉 Avg Latency | 0.96 ms | ⚡ Sub-millisecond under load — suitable for interactive apps |
📦 Throughput | 10.9 MB/sec | 📈 Handles large JSON payloads with ease |
🎯 Total Requests | 905,000 in 10s | 💪 Battle-tested for real-world load |
✨ Tirne was designed for edge-first, zero-warmup environments — and these numbers prove it.
A backend should be transparent, fast, and designed like architecture — not like magic. Tirne is built on five modern principles:
-
Structure is the source of truth
APIs are defined as code, not behavior. No decorators, no conventions — just configuration you can read. -
Errors are data, not chaos
Exceptions carry type, status, and visibility. You don’t catch them — you design them. -
Composition is everything
Middleware is composed explicitly. No global state, no stack traces from hell. -
Built for the edge, shaped by types
Tirne runs instantly on Bun, Workers, and Deno. And your types shape what runs — not your docs. -
No bootstraps, no boilerplate, no BS
One file. No CLI. No hidden magic. What you write is what you deploy.
Philosophy | Structure and Side Effect Control | Simplicity and Familiarity | Type-maximalism and Decorator DSL |
Routing | Declarative Route[] structure | Chain-style app.get("/foo") | Macro-enhanced handler declarations |
Middleware | Explicit compose([...]), scoped per route | Global app.use() and nested routers | Plugin + lifecycle hooks + decorators |
Error Model | TirneError: structured error with metadata | throw or return c.text() | set.status() with plugin-driven handling |
Type Safety | Type-driven config and handlers (Route<T>) | Medium (context-specific typing) | Extremely strong, but tightly coupled to tools |
Response API | json(), error() as pure return values | c.json(), c.text() methods | set.response() side-effectful injections |
Extensibility | Middleware and composition primitives | Plugins with shared context | Plugins + Macros + Decorators |
Dependencies | 🟢 Zero external runtime deps | 🟡 Lightweight | 🔴 Heavy: valibot, macros, SWC, etc. |
Runtime Support | ✅ Bun / Workers | ✅ Bun / Node / Workers/ Deno | ❌ Bun-only, limited to SWC macro pipelines |
Ideal Users | API designers, type-aware minimalists, edge devs | Express/Deno users wanting familiar DX | TS power users who love macros & decorators |
Tirne is not just minimal — it's architectural. It gives you full control over structure, type, and execution without opinionated tooling or hidden behaviors.
To use in Workers :
Tirne is ideal for:
-
⚡️ Need edge-speed APIs — Sub-millisecond response times on Bun, Workers, and Deno.
-
📦 Want type-driven reliability — APIs shaped by types, not runtime guesswork.
-
🌐 Deploy on modern runtimes — Runs fetch-first, works anywhere: Bun, Node, Workers, Deno.
-
🧪 Design with side effects in mind — Control cookies, headers, and auth with intention.
🚀 If you’re tired of magic, macros, and monoliths — try Tirne.
👉 ⭐️ Star on GitHub to join the movement.
Apache 2.0