The only cross-platform, cross-runtime, decorator-based framework for building modular applications in JavaScript and TypeScript.
| Package | Version | For |
|---|---|---|
@chojs/web |
HTTP applications | |
@chojs/command |
Command-line applications | |
@chojs/vendor-cho |
Middlewares for the built-in router of @chojs/web, such as CORS |
|
@chojs/vendor-hono |
Running @chojs/web on Hono |
|
@chojs/vendor-fastify |
Running @chojs/web on Fastify (Node.js only) |
|
@chojs/core |
The dependency injection engine underneath |
CHO is a tiny decorator-based framework for building modular applications. It uses modern JavaScript decorators (see About JavaScript Decorators) to provide a clean and efficient way to define the structure of an application.
The concept is inspired by Angular, NestJS and Spring, but with a different approach (or why this project exists):
In the modern software development landscape, the ability to deploy applications across various environments and platforms is crucial. Developers often face challenges when trying to ensure that their applications run seamlessly on different runtimes such as Node.js, Deno, Bun, Cloudflare Workers, AWS Lambda and more. Each of these runtimes has its own set of features, performance characteristics and limitations, making it difficult to write code that is truly portable.
CHO keeps application code away from all of that. A web handler receives the
standard Request and answers with a standard Response; the HTTP library
underneath is a small adapter you can swap. The framework itself uses no
runtime-specific API, and every change is tested on Deno, Node.js and Bun. (An
adapter may support fewer runtimes than the framework: each one says which.)
Decorators and reflect metadata are not yet part of the official ECMAScript standard, leading to inconsistencies in their implementation across different runtimes (TS experimental vs TC39 proposal, for example). This lack of standardization can result in compatibility issues and hinder the adoption of these features in different production environments. This project aims to provide a consistent and reliable way to use decorators across multiple JavaScript runtimes, ensuring that developers can leverage these powerful features without worrying about compatibility issues.
The same CHO application runs with standard (TC39) decorators and with legacy or
Bun decorators. It needs no reflect-metadata and no compiler plugin:
dependencies are declared explicitly, and still checked against the constructor
at compile time.
Minimalistic and optimized for performance!
There is no reflection at runtime. The whole module graph is validated and linked once, when the application starts, so creating an instance afterwards needs no lookup, and a mistake in the wiring never waits for the first request to show up.
An HTTP application:
import {
ChoWeb,
type ChoWebContext,
Controller,
Get,
Injectable,
Module,
} from "@chojs/web";
@Injectable()
class UserStore {
find(id: string) {
return {id, name: "Ada"};
}
}
@Controller({route: "users", dependencies: [UserStore]})
class UsersController {
constructor(readonly store: UserStore) {
}
@Get(":id") // GET /users/42
get(ctx: ChoWebContext) {
return this.store.find(ctx.params.id!); // sent as JSON
}
}
@Module({providers: [UserStore], controllers: [UsersController]})
class App {
}
const app = await ChoWeb.create(App);
Deno.serve(app.handler); // Bun: Bun.serve({ fetch: app.handler })A command-line application, with the same modules, controllers and providers:
import {
Action,
ChoCommand,
type ChoCommandContext,
Controller,
Help,
Module,
} from "@chojs/command";
@Controller()
class Greeter {
@Help("Say hello")
@Action("hello", {string: ["name"]})
hello(ctx: ChoCommandContext) {
console.log(`Hello, ${ctx.args.name ?? "world"}!`);
}
}
@Module({controllers: [Greeter]})
class App {
}
const app = ChoCommand.create(App, {name: "greet"});
Deno.exit(await app.run(Deno.args)); // greet hello --name youPick the package for what you are building; it brings everything an application needs.
# an HTTP application
deno add jsr:@chojs/web
npx jsr add @chojs/web
bunx jsr add @chojs/web
# a command-line application
deno add jsr:@chojs/command
npx jsr add @chojs/command
bunx jsr add @chojs/command@chojs/web has a router built in, on the standard URL Pattern API, so an HTTP
application needs nothing else. To match requests with another HTTP library,
give ChoWeb.create the linker of an adapter:
| Router | Runs on |
|---|---|
| Built in | Runtimes with URLPattern: Deno, Node.js 24, Bun 1.3.4, Cloudflare Workers |
@chojs/vendor-hono |
Deno, Node.js, Bun and edge runtimes |
@chojs/vendor-fastify |
Node.js only |
Deno and Bun run TypeScript decorators directly. On Node.js, compile the
application with TypeScript 5 or run it with a tool such as tsx.
| Package | Guide | Specification |
|---|---|---|
@chojs/web |
README | specs |
@chojs/command |
README | specs |
@chojs/vendor-cho |
README | |
@chojs/vendor-hono |
README | |
@chojs/vendor-fastify |
README | |
@chojs/core |
README | specs |
Runnable examples are in examples/.
Contributions are welcome: see CONTRIBUTING.md and the code of conduct.
This project uses the TC39 stage 3 decorators proposal (JavaScript decorators).