Next.js Forgot to Design APIs. Tirne Didn’t.
Yuki Nishikawa

Yuki Nishikawa @yukinisihikawa

About: 🧠 Indie Dev 🇯🇵 building Bevel.ts. 💡 From idea to app, in one file. 🚀 OSS / MVPs / Builders welcome I am 22-years-old DSL creater.

Location:
Saitama
Joined:
Mar 26, 2025

Next.js Forgot to Design APIs. Tirne Didn’t.

Publish Date: Jun 17
12 3

Struggling to trace side effects in Next.js API Routes?
Tired of global middleware, nested folders, and 300ms cold starts?

Tirne is here to change that. It's not just a framework. It’s a declarative, fetch-native architectural DSL for building edge-first APIs.

Tirne doesn’t just run your code. It structures it.


✨ Core Philosophy

  • Declarative routes: Define your API like a schema, not scattered handlers
  • Explicit side effects: Middleware is opt-in, visible, testable
  • Edge-native speed: Designed for Bun, Workers, and zero-cold-start runtimes
  • Type-aligned logic: Middleware and handlers work seamlessly with types

🛠️ 1. Quick Start

npx create-tirne-app
✔ Choose your target environment: › Bun / Workers
✔ Project folder: … my-tirne-app

cd my-tirne-app
bun install or npm install
npm run dev or wrangler dev
Enter fullscreen mode Exit fullscreen mode

✨ Your API will be available at http://localhost:3000.

Project Structure:

  • index.ts: Entry point using fetch-compatible interface
  • package.json: Preconfigured for Bun or Workers
  • tsconfig.json: Minimal but typed setup

⚡️ 2. Performance Benchmarks

bunx autocannon -c 100 -d 10 <http://localhost:3000/>
Enter fullscreen mode Exit fullscreen mode
Metric Tirne (Bun) Next.js API Routes
❄️ Cold Start 0.02 ms ~300 ms
⚡️ First Request 0.79 ms 20-30 ms
♻️ Requests/sec 90,000+ rps 8,000-10,000 rps
📉 Avg Latency <1ms ~15ms+

🚀 Tirne is 10x faster than Next.js API Routes — and that’s before tuning.


📀 3. Hello Tirne (Structured Example)

import { Server } from "tirne";

const server = new Server([
  { method: "GET", path: "/health", handler: () => new Response("✅ OK") }
]);

export default {
  fetch: (req: Request) => server.fetch(req),
};
Enter fullscreen mode Exit fullscreen mode

▶️ Compare that to a full folder in /pages/api/health.ts and global middleware.


🔒 4. Real Auth, Architected

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", "valid-token", {
        httpOnly: true,
        path: "/",
        maxAge: 3600,
      }));
      return json({ message: "Logged in" }, 200, headers);
    },
    middleware: [],
  },
  {
    method: "GET",
    path: "/private",
    handler: () => json({ message: "Secret" }),
    middleware: [requireAuth],
  },
];

const server = new Server(routes);

export default {
  fetch: (req: Request) => server.fetch(req),
};
Enter fullscreen mode Exit fullscreen mode

✅ Auth isn’t magical. It’s explicit, testable, and architectural.


❗️ 5. Built-In Error Handling

// index.ts
import type { Route } from "tirne";
import { Server, TirneError } from "tirne";

const routes: Route[] = [
  {
    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}`);
    },
  },
];

const server = new Server(routes);

export default {
  fetch: (req: Request) => server.fetch(req),
};
Enter fullscreen mode Exit fullscreen mode
  • TirneError gives you structured error responses
  • Built-in error middleware maps exceptions to HTTP responses
  • No try/catch needed — control flow stays clean and testable

🧼 Clean APIs include clean error boundaries.


🧠 🚀 Build APIs You Can Actually Reason About

If you think API code should be structured, testable, and explicit — not scattered and magical — Tirne was made for you.

👉 ⭐ Star on GitHub — 10× faster than Next. 100× clearer.

No hidden context. No global traps.
Just architecture you can trace, test, and trust.

Star it if you’re done guessing how your middleware works.
We built Tirne because we were, too.

We don’t need bigger frameworks.
We need smaller, sharper ones.

Less framework. More logic.

Comments 3 total

  • Yuki Nishikawa
    Yuki NishikawaJun 17, 2025

    Curious how others are thinking about API error boundaries in 2025.

    Do you still wrap handlers in try/catch manually?
    Or are you also shifting toward structured exceptions + middleware?

    Would love to hear your approach.

  • Admin
    AdminJun 17, 2025

    Hey talented devs! If you’ve ever published on Dev.to, you may be eligible for DEV Contributor rewards. Head over here. instant distribution. – Dev.to Community Support

Add comment