CLI#
Buntok provides a CLI for scaffolding and managing projects.
init#
Initialize a new Buntok project with optimal configuration.
bunx buntok initInteractive Prompts#
During initialization, you'll be asked:
? Do you want to deploy to Vercel? (y/N):
? Do you want to add Docker support? (Y/n):If you answer y, a vercel.json file will be created with the recommended configuration for Bun projects.
What Gets Created#
$ bunx buntok init
✓ Created .agents/skills/buntok-skill/SKILL.md
✓ Updated package.json (added 6 scripts)
• Installing @buntok/core...
✓ Installed @buntok/core
• Installing TypeScript toolchain (@types/bun, @types/node, typescript)...
✓ Installed @types/bun, @types/node, typescript
✓ Created tsconfig.json
• Installing @biomejs/biome...
✓ Installed @biomejs/biome
✓ Created biome.json
✓ Created .vscode/settings.json
✓ Created src/env.ts
✓ Created src/index.ts
✓ Created .env
✓ Created .env.example
✓ Created .gitignore
? Do you want to deploy to Vercel? (y/N): y
✓ Created vercel.json
✓ Created server.ts
✓ Updated dev script to: bun --watch server.ts
? Do you want to add Docker support? (Y/n): y
✓ Created Dockerfile
✓ Created .dockerignoreGenerated env.ts
The src/env.ts file contains a type-safe environment schema using validateEnv(). All variables have sensible defaults and are validated at startup.
import { Buntok } from "@buntok/core";
import { z } from "@buntok/core/middlewares/validator";
export const env = Buntok.validateEnv({
PORT: z.coerce.number().default(1212),
AUTH_STORE: z.enum(["header", "cookie"]).default("header"),
AUTH_COOKIE: z.string().default("session"),
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
});Add more variables as needed (e.g., DATABASE_URL, JWT_SECRET). The server will exit with a clear error if any required variable is missing or invalid.
build#
Build project for production. Compiles TypeScript to JavaScript and outputs to buntok/.
bunx buntok buildWhat It Does#
- Compiles the root
server.tsentry point usingBun.build() - Resolves path aliases (e.g.,
@/*) fromtsconfig.json - Marks all packages as external (not bundled)
- Outputs to
buntok/server.js
Output#
$ bunx buntok build
🔨 Building project...
✅ Build successful → buntok/server.js
Deploy: copy buntok/ + node_modules/ + package.json to serverDeploying#
After building, deploy these files to your server:
# Files needed for production
buntok/server.js # Compiled application
node_modules/ # Dependencies
package.json # Package manifestDevelopment vs Production#
# Development (hot reload)
bun run dev
# Build for production
bun run build
# Run production build
bun run startcheck#
Run TypeScript type checking without emitting files. Displays all errors with file locations and a summary.
bunx buntok check$ bunx buntok check
Running type check...
src/index.ts(1,7): error TS2322: Type 'string' is not assignable to type 'number'.
src/index.ts(2,7): error TS2322: Type 'number' is not assignable to type 'string'.
✗ 2 errors in 2 filesOptions#
| Flag | Description |
|---|---|
--json | Output results as JSON for CI/CD |
--plain | Plain text output without colors |
JSON Output#
$ bunx buntok check --json
{
"success": false,
"errors": [
{
"file": "src/index.ts",
"line": 1,
"col": 7,
"code": "TS2322",
"message": "Type 'string' is not assignable to type 'number'."
}
],
"errorCount": 1,
"fileCount": 1
}create#
Generate repository, service, controller, and schema files for an entity using a modular structure. The generator is aware of your project: if a module already exists, new files are merged into its barrel and registration instead of being duplicated. The zod schema, faker sample data, and TypeScript types are derived from your Prisma schema when one exists (see --fields below otherwise).
bunx buntok create <entity>Example Output#
$ bunx buntok create user
Creating User entity (orm: prisma)...
✓ Created src/modules/user/user.repository.ts
✓ Created src/modules/user/user.service.ts
✓ Created src/modules/user/user.controller.ts
✓ Created src/modules/user/user.schema.ts
✓ Created src/modules/user/index.tsGenerated Files#
By default, create generates all files using the modular structure with @Dependencies for auto DI:
Controller#
// src/modules/user/user.controller.ts
import { Dependencies, Controller } from "@buntok/core";
import { BaseController } from "@buntok/core";
import { UserService } from "./user.service";
import type { User } from "@prisma/client";
@Dependencies(UserService)
@Controller("/users")
export class UserController extends BaseController<User> {
constructor(private readonly userService: UserService) {
super(userService);
}
}Service#
// src/modules/user/user.service.ts
import { Dependencies } from "@buntok/core";
import { BaseService } from "@buntok/core";
import { UserRepository } from "./user.repository";
import type { User } from "@prisma/client";
@Dependencies(UserRepository)
export class UserService extends BaseService<User> {
constructor(private readonly userRepository: UserRepository) {
super(userRepository);
}
}Repository#
// src/modules/user/user.repository.ts
import { BaseRepository } from "@buntok/prisma";
import { prisma } from "@/lib/prisma";
import type { User, Prisma } from "@prisma/client";
export class UserRepository extends BaseRepository<
User,
Prisma.UserCreateInput,
Prisma.UserUpdateInput
> {
constructor() {
super(prisma, "user");
}
}Schema (Zod)#
// src/modules/user/user.schema.ts
import { z } from "@buntok/core/middlewares/validator";
export const CreateUserSchema = z.object({
name: z.string().min(1).max(100),
// TODO: Add more fields
});
export const UpdateUserSchema = CreateUserSchema.partial();
export type CreateUserInput = z.infer<typeof CreateUserSchema>;
export type UpdateUserInput = z.infer<typeof UpdateUserSchema>;Barrel Export#
// src/modules/user/index.ts
export { UserRepository } from "./user.repository";
export { UserService } from "./user.service";
export { UserController } from "./user.controller";
export { CreateUserSchema, UpdateUserSchema } from "./user.schema";
export type { CreateUserInput, UpdateUserInput } from "./user.schema";Partial Generation#
Use flags to generate only specific files. Flags can be combined:
# Generate only the repository
bunx buntok create user --repo
# Generate only the service
bunx buntok create user --service
# Generate only the controller
bunx buntok create user --controller
# Generate only the schema
bunx buntok create user --schema
# Combined (repo + service)
bunx buntok create user --repo --serviceCustom Fields & Base Classes#
No Prisma schema? Pass fields explicitly with --fields - the CLI generates the zod validation schema, faker sample data, and TypeScript types from them. Use --base to generate classes that extend the reusable BaseRepository / BaseService / BaseController instead of plain classes:
# Generate from custom fields (no Prisma schema needed)
bunx buntok create product --fields "name:string,price:number,isActive:boolean"
# Generate against existing Base* classes
bunx buntok create user --repo --service --baseORM Selection#
By default, the CLI auto-detects your ORM from package.json dependencies. When no ORM is found it falls back to plain code - an in-memory repository, ORM-free service and controller, no @prisma/client imports. You can also specify it explicitly:
# Auto-detect ORM (default, plain fallback when none)
bunx buntok create user
# Force Prisma
bunx buntok create user --prisma
# Force Drizzle
bunx buntok create user --drizzle
# Force TypeORM
bunx buntok create user --typeormController Registration (‑‑app)#
The generated controller is registered automatically in the file that declares your Buntok (e.g. src/index.ts) - not the listener-only server.ts. Both const app = new Buntok(...) instances and group declarations like const apiv1 = app.group("/api/v1") are detected. Use --app to pick the target explicitly:
# Register into the apiV1 instance (or group)
bunx buntok create user --app apiV1
# Single Buntok instance → registered automatically, no flag needed
bunx buntok create user--app name errors before any file is written, and existing registerController([…]) arrays are merged instead of duplicated.Dry Run#
Preview what would be generated without writing files:
bunx buntok create user --dry-rundb#
Database management commands. They delegate to your detected ORM (Prisma / Drizzle / TypeORM); db seed falls back to a local seeder runner in src/db/seeders when the ORM has no seed configuration. Destructive commands ask for confirmation.
# Run pending migrations (optional name)
bunx buntok db migrate
bunx buntok db migrate add-users-table
# Reset database (drop all tables)
bunx buntok db reset
# Seed database with initial data
bunx buntok db seed
# Generate migration from schema changes
bunx buntok db generate
# Open studio (Prisma Studio / Drizzle Studio)
bunx buntok db studio
# Show migration status
bunx buntok db status@buntok/prisma, @buntok/drizzle, @buntok/typeorm) via detectOrm(). migrate [name] accepts optional migration name.make:test#
Generate a unit test file for an entity.
bunx buntok make:test <entity> [--dry-run]$ bunx buntok make:test user
✓ Created tests/user.test.ts
# Preview without writing
$ bunx buntok make:test user --dry-runmake:test:e2e#
Generate an E2E test file for an entity's API endpoints.
bunx buntok make:test:e2e <entity> [--dry-run]$ bunx buntok make:test:e2e user
✓ Created tests/e2e/user.e2e.test.ts
# Preview without writing
$ bunx buntok make:test:e2e user --dry-runmake:seeder#
Generate a database seeder file for an entity. Works with any ORM (Prisma, Drizzle, TypeORM).
bunx buntok make:seeder <entity> [--factory] [--dry-run]$ bunx buntok make:seeder user
✓ Created src/db/seeders/user.seeder.ts
# With factory pattern
$ bunx buntok make:seeder user --factory
# Preview without writing
$ bunx buntok make:seeder user --dry-runFactory Pattern#
Use the --factory flag to generate a seeder that uses the Factory pattern for data generation:
bunx buntok make:seeder user --factory// src/db/seeders/user.seeder.ts
import { prisma } from "@/lib/prisma";
import { UserFactory } from "@/factories/user.factory";
export async function seedUser() {
console.log("Seeding User...");
const items = UserFactory.buildMany(100);
await prisma.user.createMany({ data: items });
console.log("✓ User seeded successfully (100 records)");
}src/factories/<entity>.factory.ts. Run buntok make:factory <entity> first.make:factory#
Generate a factory scaffold for an entity. Add the required fields to the generated definition before using it in tests or seeders.
bunx buntok make:factory <entity>$ bunx buntok make:factory user
Created: src/factories/user.factory.ts
Usage:
import { UserFactory } from "@/factories/user.factory";
const user = await UserFactory.create();
const users = await UserFactory.createMany(10);
const admin = await UserFactory.create({ role: "admin" });Generated Factory#
The generated file is a Prisma-oriented scaffold with a TODO definition. It is not ready to compile until you replace the placeholder with fields required by your User type.
// src/factories/user.factory.ts
import { Factory } from "@buntok/core";
import { faker } from "@faker-js/faker";
import type { User } from "@prisma/client";
export const UserFactory = Factory.define<User>(() => ({
// TODO: Define your factory fields here
// Example:
// id: faker.number.int({ max: 10000 }),
// name: faker.person.fullName(),
// email: faker.internet.email(),
// role: faker.helpers.arrayElement(["user", "admin"]),
}));Factory API#
| Method | Description |
|---|---|
Factory.define<T>(fn) | Create a new factory with type T |
.create(overrides?) | Create one item (async, runs afterCreate) |
.createMany(count, overrides?) | Create multiple items |
.build(overrides?) | Generate one item synchronously |
.buildMany(count, overrides?) | Generate multiple items synchronously |
.withDefaults(defaults) | Set default overrides |
.afterCreate(callback) | Register post-creation hook |
Factory.ref(fn) | Lazy reference for relations |
Factory.pick(arr, count?) | Random item(s) from array |
@faker-js/faker as a peer dependency. bunx buntok make:factory installs it automatically with bun add -d @faker-js/faker when it is missing.debug:routes#
Show all registered routes with their middleware chains. Useful for debugging route registration and middleware ordering. The command tries app entry candidates in order (server.ts, src/index.ts, ...) and exits after printing - the server never stays running. A listener-only server.ts without export { app }; simply falls through to the next candidate; only when no candidate exports an app does it fail with exit code 1.
bunx buntok debug:routes$ bunx buntok debug:routes
Method │ Path │ Middlewares │ Handler
───────┼────────────────────┼────────────────────────────────┼──────────
GET │ / │ - │ (index)
GET │ /users │ cors, compress │ getAll
GET │ /users/:id │ cors, compress, auth │ getById
POST │ /users │ cors, compress, validation │ create
4 routes registered
By source:
UserController: 3 routes
direct: 1 routesJSON Output#
Use --json flag for programmatic access:
bunx buntok debug:routes --jsondev#
Start the development server with hot reload. Optionally expose it publicly for testing webhooks or sharing.
bunx buntok dev$ bunx buntok dev
Starting development server...
Server running at http://localhost:1212
Press Ctrl+C to stopPublic Tunnel#
Use --expose to create a public URL via localtunnel. Useful for webhook testing, mobile testing, or sharing with others:
bunx buntok dev --expose$ bunx buntok dev --expose
Starting development server with tunnel...
Server running at http://localhost:1212
Tunnel: https://buntok-1234.loca.lt → http://localhost:1212
Press Ctrl+C to stoplocaltunnel as a dev dependency. Install with: bun add -d localtunnelOptions#
| Flag | Description |
|---|---|
--expose | Create public tunnel URL via localtunnel |
--port=PORT | Port number (default: 1212) |
make:middleware#
Generate a middleware file.
bunx buntok make:middleware <name> [--dry-run]$ bunx buntok make:middleware auth
✓ Created src/middlewares/auth.ts
# Preview without writing
$ bunx buntok make:middleware auth --dry-runmake:docs#
Manually regenerate OpenAPI documentation. Optional - swagger.json is auto-generated on app.listen().
bunx buntok make:docsswagger.json without starting the server.Aliases#
The create command has shorter aliases:
# These are all equivalent:
bunx buntok create user
bunx buntok g user
bunx buntok gen user
bunx buntok generate userProject Structure#
After using buntok init and buntok create user:
my-app/
├── src/
│ ├── index.ts
│ ├── env.ts
│ └── modules/
│ └── user/
│ ├── index.ts # barrel export
│ ├── user.controller.ts # @Dependencies + BaseController
│ ├── user.service.ts # @Dependencies + BaseService
│ ├── user.repository.ts # BaseRepository (Prisma)
│ └── user.schema.ts # Zod schemas
├── .agents/
│ └── skills/
│ └── buntok-skill/
│ └── SKILL.md
├── .env
├── .env.example
├── .gitignore
├── .vscode/
│ └── settings.json
├── biome.json
├── tsconfig.json
├── Dockerfile? # buntok init (optional)
├── .dockerignore? # buntok init (optional)
└── package.jsonsrc/modules/. The @Dependencies decorator enables automatic dependency injection - just register your controllers with app.registerController() and the container resolves the entire dependency tree.Flags Reference#
| Flag | Description |
|---|---|
--repo | Generate only repository |
--service | Generate only service |
--controller | Generate only controller |
--schema | Generate only Zod schema |
--prisma | Use Prisma ORM (default: auto-detect, falls back to plain code) |
--drizzle | Use Drizzle ORM |
--typeorm | Use TypeORM |
--dry-run | Preview files without writing |