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.
Top comments (0)