Unleash your server
development.

A TypeScript server framework with decorators and dependency injection, as fast as a bare router. Runs on Node.js, Bun and Deno.

Get started →
~/projectsready

$ pnpm create vercube my-app

ℹWelcome to Vercube!

◇Template › api

◇Modules › schema, testing, devtools

◇Deploy target › node

◒Applying recipes, installing dependencies…

✔Created my-app from the api template

Modules: schema, testing, devtools

Next: cd my-app && pnpm dev

$

Runs on the web's own Request and Response, so it runs wherever they do.

01 Controllers

Write a class.
Get a route.

A controller is a class and a route is a decorated method. Arguments arrive parsed, and validated when you hand them a schema: a body that does not fit never reaches your code.

DecoratorsValidationFetch Request / Response
Controllers guide →
src/controller/UserController.ts
@Controller('/users')
export class UserController {
  @Inject(UserService)
  private readonly users!: UserService;

  @Get('/:id')
  public get(@Param('id') id: string) {
    return this.users.find(id);
  }

  @Post('/')
  public create(@Body({ validationSchema: User }) body: User) {
    return this.users.create(body);
  }
}
requestslive

GET/users/42200

route/users/:id
argsid: string
handlerget()
response200 · 3ms

{ "id": 42, "name": "Ada" }

  • GET/users/423ms200
  • DELETE/users/421ms404
  • GET/users/422ms200
  • POST/users1ms400
  • GET/users/72ms200

02 Dependency injection

Bind once.
Inject anywhere.

Services are classes the container builds for you. Bind a key to an implementation in one place, ask for it with @Inject, and swap it for a mock in a test without touching the code that uses it.

bindbindTransientbindMock
Container guide →
  • One place for wiring src/boot/Container.ts decides what every key resolves to.
  • Mocks without ceremony bindMock takes only the methods your test calls.
  • Seen before it throws Devtools marks an @Inject that nothing binds.
src/boot/Container.ts
import type { Container } from '@vercube/di';
import { Database, PostgresDatabase } from '../services/Database';
import { ConsoleLogger, Logger } from '../services/Logger';
import { UserService } from '../services/UserService';

export function useContainer(container: Container): void {
  container.bind(Database, PostgresDatabase);
  container.bind(Logger, ConsoleLogger);
  container.bind(UserService);
}

bindings

  • Database→PostgresDatabase
  • Logger→ConsoleLogger
  • UserService→UserService

trace

  1. container.get(UserService)
  2. new UserService()cached
  3. @Inject(Database)
  4. new PostgresDatabase()new
  5. @Inject(Logger)
  6. new ConsoleLogger()new
  7. properties filledready
  8. container.get(UserService)
  9. same instancesingleton

03 Project generator · new in 1.5

One command.
The project you meant.

create-vercube pins every @vercube package, applies a recipe per module and per deploy target, and adds the services they need to docker-compose. Edit the command below and watch the project change.

2 templates10 modules3 deploy targetsvercube add
Generator reference →
~/projects — zshclick the command to edit

$

  1. ℹWelcome to Vercube!
  2. ◇Template › api
  3. ◇Modules › schema, devtools, testing
  4. ◇Deploy target › node
  5. +Schema SchemaPlugin, docs at /_schema/docs
  6. +Devtools DevtoolsPlugin at /_devtools
  7. +Testing vitest and @vercube/testing
  8. ✔Created my-app from the api template
  9. Modules: schema, devtools, testing
  10. Next: cd my-app && pnpm dev

$

my-app/7 files · 3 recipes
  • src
  • boot
  • Container.ts
  • controller
  • GreetingController.tsschema
  • FooController.tstesting
  • index.ts
  • test
  • FooController.test.tstesting
  • vercube.config.ts
  • package.json
Try

04 Devtools

See inside
the running app.

One page served by your own app: the container, the route table, every request as a waterfall, logs, config and an audit. No outbound traffic, no second process.

/_devtoolslocal onlyOpenTelemetry
Devtools guide →
Vercube Devtools, Overview panel

05 Performance

The speed of a router,
with a container on.

Same 112-route table, same machine, one run of the open benchmark suite. Node 24, 500 connections, 10 seconds per route, September 2026.

Run the suite yourself →

Requests per second · GET /

  • Vercube99,030
  • Fastify97,072
  • Hono91,927
  • Elysia90,005
  • h387,526
  • Ts.ED46,909
  • NestJS39,833
  • routing-controllers35,155

×

NestJS throughput on plain text (99,030 vs 39,833)

×

NestJS throughput on a JSON body (86,259 vs 31,224)

%

more than Fastify on a JSON body (86,259 vs 66,571)

06 Modules

Add what you need,
when you need it.

Every module is a package with a recipe: vercube add queue installs it, registers the plugin and writes a working example into your project.

All modules →

Free and MIT licensed.
Built in the open, shaped by the people who use it.

Start with one command, then read the guide.

$ pnpm create vercubeGet started →