Katal

A simple yet powerful web framework for Bun with TypeScript, inspired by Laravel and Express.

License: MIT npm version Bun


Why Katal?

Katal is built from the ground up for the Bun runtime. It embraces the controller-per-route pattern, brings first-class TypeScript support, and ships every feature you need in a modern HTTP API — without forcing you to install a dozen third-party packages.


Feature Overview

Category What you get
HTTP Controller-per-route, route groups, path params, query/body parsing
Middleware Global + named middleware, before / after hooks, short-circuit support
Validation Schema-based field validation, nested objects, custom rules
Auth JWT sign/verify, createAuthMiddleware, optional auth
Authorization Policy-based gate middleware (can:<policy>)
Rate Limiting Sliding-window limiter, pluggable store, response headers
Logging Structured log levels, console + file destinations, custom sinks
Observability Correlation IDs, W3C traceparent propagation, structured access logs
Cache cacheGet/cacheSet/cacheRemember, pluggable CacheStore
Queue In-memory by default, retry/backoff, delayed jobs, scheduler, BYO adapter
Events Typed async/sync event bus (on, once, emit, emitSync)
Health Checks /health, /health/ready, /health/live endpoints out of the box
OpenAPI Auto-generate OpenAPI 3.1 from route + schema definitions
Config Typed config from source objects or environment variables
DI Container IoC container with singleton/transient/instance bindings
Plugins Lifecycle hooks: onRegister, onBoot, onReady, onClose
Service Providers Laravel-style register() / boot() composition
Testing Kit AppFactory, RequestClient, FakeClock, createTestToken

Installation

bun add katal

Katal requires Bun ≥ 1.0. It has no production dependencies beyond Bun itself.


Quick Start

import { Application, Controller } from "katal";
import type { RequestContext } from "katal";

// 1. Create the app
const app = new Application({ port: 3000 });
const router = app.getRouter();

// 2. Define a controller
class HelloController extends Controller {
  async handle(ctx: RequestContext) {
    return this.success({ message: `Hello, ${ctx.query.name ?? "world"}!` });
  }
}

// 3. Register a route
router.get("/hello", HelloController);

// 4. Start the server
await app.listen();

Run it:

bun run app.ts
# Listening on http://localhost:3000

Documentation Map

Topic Guide
Application setup, routing, DI Core
Controllers, helpers, Problem Details HTTP
Global and named middleware Middleware
Schema validation Validation
JWT auth Authentication
Policy-based gates Authorization
Rate limiting Rate Limiting
Structured logging Logging
Correlation IDs + trace context Observability
Cache abstraction Cache
Queue, retry, scheduling Queue
Event bus Events
Health endpoints Health Checks
OpenAPI generation OpenAPI
Typed config from env Config
Framework plugins Plugins
Service providers Service Providers
Test helpers Testing

Examples

Working examples: