Struggling with side effects in Next.js API Routes?
Tired of global middleware, nested folders, and cold starts that feel like winter?
Tirne is not just another framework.
It’s a declarative, type-safe DSL for building edge-first APIs — with fetch-native precision and architectural clarity.
🧠 Tirne doesn’t just run your code. It structures it.
✨ Core Philosophy
- Structure as code — Routes, logic, middleware: all declarative
- Explicit side effects — No magic. Middleware is opt-in, testable
- Edge-native execution — Sub-millisecond cold starts on Bun and Workers
- Types shape behavior — Runtime flows match your TypeScript design
🛠 Quick Start in 30 Seconds
npx create-tirne-app
️ Select target: › Bun / Workers
️ Project folder: › my-tirne-app
cd my-tirne-app
bun install # or npm install
npm run dev # or wrangler dev
🔥 Your first API is live in under a minute — at http://localhost:3000
⚡️ Performance: Benchmarks that Matter
Metric | Tirne (Bun) | Next.js API Routes |
---|---|---|
❄️ Cold Start | 0.02 ms | ~300 ms |
⚡️ First Request | 0.79 ms | 20-30 ms |
🔁 RPS | 90k+ | 8–10k |
📉 Avg Latency | <1 ms | ~15ms |
✨ 10x faster, 100x simpler.
🧱 Hello, Structured APIs
import { Server } from "tirne";
const server = new Server([
{ method: "GET", path: "/health", handler: () => new Response("✅ OK") }
]);
export default {
fetch: (req: Request) => server.fetch(req),
};
Compare that to folders, files, global config, and context spaghetti.
🔐 Real Auth, Without Magic
import { Server, json, setCookie, requireAuth } from "tirne";
import type { Route } from "tirne";
const routes: Route[] = [
{
method: "GET",
path: "/login",
handler: () => {
const headers = new Headers();
headers.append("Set-Cookie", setCookie("auth", "token", {
httpOnly: true,
path: "/",
maxAge: 3600,
}));
return json({ message: "Logged in" }, 200, headers);
},
},
{
method: "GET",
path: "/private",
handler: () => json({ message: "Secret" }),
middleware: [requireAuth],
},
];
✅ Auth should be visible, testable, and architectural — not magical.
❗️ Typed Errors, Clean Boundaries
import { Server, TirneError } from "tirne";
const routes = [
{
method: "GET",
path: "/",
handler: (req) => {
const name = new URL(req.url).searchParams.get("name");
if (!name) {
throw new TirneError("Missing name", {
status: 400,
type: "bad_request",
expose: true,
});
}
return new Response(`Hello, ${name}`);
},
},
];
🪄 API errors are part of the contract — not a side effect.
🧠 Tirne is Built for Developers Who Want Clarity
- No global context
- No hidden decorators
- No nested traps
Just pure, traceable code
Designed for speed. Shaped by types.
Architected like it matters.
⭐️ Try It Now
npx create-tirne-app
- GitHub repo
- tirne.dev
📣 Star Tirne if you’re done guessing what your API does
We don’t need bigger frameworks.
We need smaller, sharper ones.
Less framework. More logic.
Welcome to the architectural era.