Introduction

Status: alpha (v0.0.1). The API is mostly settled but still subject to change before 0.1.0. Use Ingenium for side projects and internal tools; revisit for production once 1.0 lands.

What is Ingenium?

Ingenium is what happens if you fix Express's three structural problems - linear routing, untyped req/res, and per-request allocation - without forcing developers to learn a new mental model. It's the same shape (app.get, app.use, mountable routers, drop-in middleware), with a typed ctx instead of (req, res, next), and a router/dispatcher built for current-decade Node throughput.

The pitch in one sentence: the shortest path from a working Express app to throughput competitive with Hono and Fastify.

Three core ideas

  • Typed ctx - one pooled, strongly-typed context object replaces (req, res, next). Lazy getters for things like query and body, a state scratch space for per-request data, and full TypeScript types for params, headers, and decorated fields.
  • Return-value reflection - handlers can return a value and Ingenium writes the right response. Object → JSON, string → text/html, Buffer → octet-stream, Readable → stream, undefined → 204. ctx.json(...) still works when you want explicit control.
  • Radix-trie router - O(k) lookup with wildcard backtracking, lazy composition, and a dirty-bit recompose so route registration after listen() Just Works.

Show me the code

import { ingenium } from 'ingenium'

const app = ingenium()

app.use(async (ctx, next) => {
  const start = Date.now()
  await next()
  console.log(`${ctx.method} ${ctx.path} -> ${ctx._statusCode} ${Date.now() - start}ms`)
})

app.get('/', () => 'hello')
app.get('/users/:id', (ctx) => ({ id: ctx.params.id }))
app.post('/echo', async (ctx) => ctx.body.json())

const server = await app.listen(3000)
console.log(`listening on http://localhost:${server.port}`)

That's a full server. No res.send. No body-parser. No app.set('case sensitive routing', true). Return a value and Ingenium reflects it to the wire - object → JSON, string → text/html, Buffer → octet-stream, Readable → stream, undefined → 204. Call ctx.json(...) when you want explicit control over status or headers.

Where to next?