メインコンテンツまでスキップ

Getting Started with Bun

This guide walks you through building a Zelt application on Bun from scratch.

Prerequisites

  • Node.js v20 or higher (or Bun v1.0 or higher)
  • A package manager: pnpm (recommended), npm, or bun

Installation

bun add @zeltjs/core @zeltjs/adapter-bun

Project Structure

my-app/
├── src/
│   ├── entry/
│   │   ├── controllers/    # HTTP endpoints
│   │   └── commands/       # CLI commands
│   ├── services/           # Business logic
│   ├── configs/            # Configuration classes
│   ├── app.ts              # Application definition
│   ├── cli.ts              # CLI entry point
│   └── main.ts             # HTTP server entry point
├── package.json
└── tsconfig.json
DirectoryPurpose
entry/External entry points (HTTP, CLI)
services/Business logic, injected via DI
configs/Environment variables and settings

Hello World

Step 1: Create the Controller

Create src/entry/controllers/hello.controller.ts:

@Controller('/hello')
export class HelloController {
  @Get('/:name')
  greet(name = pathParam('name')) {
    return { message: `Hello, ${name}!` };
  }
}

Step 2: Create the Application

Create src/app.ts:

export const app = createApp([http({
    controllers: [HelloController],
  })]);

Step 3: Create the Entry Point

Create src/index.ts:

const bunApp = await onBun(app);

const server = bunApp.serve({ port: 3000 });
console.log(`Server running at http://${server.address.hostname}:${server.address.port}`);

The onBun() function prepares your app for the Bun runtime. It returns an object with:

  • serve(options?) — Starts an HTTP server using Bun.serve()
  • shutdown() — Gracefully shuts down the application
  • get<T>(Class) — Resolves a service from the DI container
  • args — Command-line arguments (Bun.argv.slice(2))

Step 4: Run the Server

bun run src/index.ts

Visit http://localhost:3000/hello/world to see:

{ "message": "Hello, world!" }

Server Options

The serve() method accepts options for port and hostname:

const server = bunApp.serve({
  port: 8080,
  hostname: '127.0.0.1',
});
OptionDefaultDescription
port3000Port to listen on
hostname'0.0.0.0'Hostname to bind to

Command Support

If your app includes commands, onBun() keeps command capabilities under the commands namespace for CLI execution:

const bunApp = await onBun(app);

const result = await bunApp.commands.execCommand(['greet', 'world']);
console.log(result.exitCode); // 0 or 1

Warmup Option

By default, onBun() uses eager initialization (warmup: true) — all controllers are resolved at startup.

For lazy initialization (controllers resolved on first request):

const bunApp = await onBun(app, { warmup: false });
OptionBehaviorUse Case
warmup: true (default)All controllers resolved at startupLong-running servers
warmup: falseControllers resolved on first requestOptimized cold starts

What's Next?