v0.1.0 · Node 22+ and Bun

Room to spare.

Suku is a lightweight TypeScript backend framework built from four ideas: routes, features, middlewares and services. Routes are typed by their schemas, and services come from a dependency injection container with real lifetimes and scopes. No runtime dependencies.

main.ts
import { Routes, Suku, feature, route, singleton } from '@sukujs/core';
import { nodeAdapter } from '@sukujs/platform-node';
import { z } from 'zod';

class UsersService {
  find(id: number) {
    return { id, name: 'Ada' };
  }
}

@Routes('/users')
class UsersRoutes {
  constructor(private readonly users: UsersService) {}

  findOne = route.get('/:id', {
    params: z.object({ id: z.coerce.number() }),
    handle: ({ params }) => this.users.find(params.id),
  });

  create = route.post('/', {
    body: z.object({ name: z.string().min(2) }),
    handle: ({ body }) => ({ created: body.name }),
  });
}

const UsersFeature = feature('users', {
  routes: [UsersRoutes],
  services: [singleton(UsersService)],
});

const app = await Suku.create({
  features: [UsersFeature],
  adapter: nodeAdapter(),
});
await app.listen(3000);

Types written once

A route's schemas validate the request and type the handler. The path itself is checked against the params schema at compile time.

With a class, or without

Group routes in a class with constructor injection, or declare them as plain values that list the services they need.

Dependency injection like .NET

One flat service collection with singleton, scoped and transient lifetimes, a scope per request, and disposal in reverse order.

One cross-cutting concept

Authentication, logging, caching and CORS are all middlewares: code before next(), code after it.

Zero runtime dependencies

No RxJS, no reflect-metadata, no Express. Validation works with any Standard Schema library.

Web-standard core

The kernel speaks Fetch Request and Response. On Bun the full framework runs at parity with raw Bun.serve.