An enterprise-friendly structure for Elysia applications: explicit constructor DI, feature boundaries, and native Elysia routes in controllers.
Working alpha. APIs and conventions may change. Elpod is a foundation for application structure, not a production-readiness or security guarantee.
Documentation: https://elpod.vercel.app/
Elpod is for teams building a medium-to-large Bun/Elysia service who want named feature boundaries, visible dependency graphs, and useful operational checks without replacing Elysia. It is not a database, identity provider, message broker, deployment platform, or drop-in NestJS migration.
| Approach | Strength | Trade-off |
|---|---|---|
| Plain Elysia | Small, direct, native API | Your team owns conventions as the codebase grows |
| Elpod | Explicit DI, pods, lifecycle boundaries, native routes, elpod audit |
Working alpha; adapters and deployment policy remain application-owned |
| NestJS | Mature batteries-included application conventions | Decorators and framework abstractions are a poor fit for teams choosing native Elysia/Bun |
| Hand-rolled structure | Total freedom | Boundaries, testing conventions, and architecture checks must be designed and maintained by each team |
bun create elpod my-app
cd my-app
bun run devbun create elpod creates the starter structure and installs both @elpod/core and @elpod/cli. See Getting started for the longer path.
Controllers use the native Elysia instance. Pods wire the controller and its providers. Services contain application logic.
// src/features/hello/hello.service.ts
export class HelloService {
greet() { return { line: "the service is alive" }; }
}// src/features/hello/hello.controller.ts
import type { ElpodElysia } from "@elpod/core";
import { HelloService } from "./hello.service";
export class HelloController {
static readonly inject = [HelloService] as const;
constructor(private readonly hello: HelloService) {}
routes(app: ElpodElysia) {
return app.get("/", () => this.hello.greet());
}
}// src/features/hello/hello.pod.ts
import { pod } from "@elpod/core";
import { HelloController } from "./hello.controller";
import { HelloService } from "./hello.service";
export const hello = pod({
name: "hello", prefix: "/hello", controller: HelloController,
providers: [HelloService],
});GET /hello returns:
{"line":"the service is alive"}- No decorators, reflection, service locator, or parallel router.
- Constructor injection and provider lifetimes are explicit and type-checked.
- Routes stay native Elysia routes, so Eden Treaty inference is preserved.
elpod audit --production --strict --jsoncan be a CI or release gate.- Bun-first commands, generated declarations, a CLI, and a package smoke test.
| Capability | Reference |
|---|---|
| Features, pods, and project layout | Features and pods, project structure |
| Constructor DI, lifetimes, overrides | Dependency injection |
| Providers, imports, exports, plugins | Provider boundaries, plugins |
| Native routes, Eden, OpenAPI | Routing, OpenAPI |
| Configuration, errors, health, shutdown | Configuration, errors, health |
| Authentication, sessions, CSRF, tenancy | Security overview, authentication, tenancy |
| HTTP clients and persistence boundaries | HTTP client, database and migrations |
| Events, jobs, caching, rate limiting | Events, jobs, cache and locks, rate limiting |
| Observability, testing, deployment | Observability, testing, deployment |
| CLI diagnostics | CLI |
The core composition model, native routing, DI, lifecycle, configuration, health checks, security primitives, observability boundaries, events/jobs boundaries, cache primitives, HTTP client, testing harness, and CLI diagnostics are implemented. Vendor database adapters, durable queues and brokers, distributed cache/rate limiting, OpenTelemetry SDK/exporter setup, identity providers, and deployment hardening remain application-owned or planned.
See the production boundary and the roadmap. Overview and guides: elpod.vercel.app; full in-repo map: docs/README.md.
Read CONTRIBUTING.md, then run bun install --frozen-lockfile and bun run check. Small, focused pull requests are welcome. Please treat the alpha caveat and the 250-line TypeScript limit as repository rules.
MIT. See LICENSE.