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.
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.