CLI

@beignet/cli creates Beignet apps, generates feature slices, inspects route wiring, and catches drift after manual edits.

Most users start with these commands:

bunx -p @beignet/cli beignet create my-app
cd my-app
bunx -p @beignet/cli beignet make resource projects
bunx -p @beignet/cli beignet routes
bunx -p @beignet/cli beignet lint
bunx -p @beignet/cli beignet doctor

create starts the app. make resource adds a full contract-to-test feature slice. routes shows what the CLI can inspect. lint checks dependency direction. doctor catches drift after manual edits.

Create a new app

bunx -p @beignet/cli beignet create my-app

By default create uses the standard preset:

The CLI writes files only. After creation, install dependencies and run the app:

cd my-app
bun install
cp .env.example .env.local
bun run dev

Choose a starter preset

Presets describe the amount of app structure to scaffold on day one. Integrations stay separate, so you only add the services your app needs.

bunx -p @beignet/cli beignet create my-app --preset standard
PresetIncludes
minimalSmall contract/core/server/use-case loop for early adoption or experiments
standardFull app layout with app errors, env validation, devtools, provider wiring, health checks, typed client, React Query, React Hook Form, OpenAPI, and separated ports/ + infra/

Use minimal when you want the smallest useful contract/core/server loop:

bunx -p @beignet/cli beignet create my-api --preset minimal

Use standard when you want the full app layout:

bunx -p @beignet/cli beignet create my-app --preset standard

The starter includes a provider-neutral AuthPort, anonymous auth adapter, typed UNAUTHORIZED and FORBIDDEN errors, and a request-bound authorization gate. Use hooks for HTTP boundary authentication and use cases or policies for business authorization.

Choose features

Features are optional capabilities layered onto the base app.

bunx -p @beignet/cli beignet create my-app \
  --preset minimal \
  --features client,openapi

Available features:

FeatureAdds
clientA typed Beignet HTTP client
react-queryTanStack Query provider and contract query helpers
formsReact Hook Form wired to the contract body schema
openapi/api/openapi route generated from contracts

Choose integrations

Integrations add provider packages, setup notes, env examples, and provider wiring where the provider can run without app-specific infrastructure.

bunx -p @beignet/cli beignet create my-app \
  --integrations drizzle-turso,inngest,pino

You can also repeat --integration:

bunx -p @beignet/cli beignet create my-app \
  --integration inngest \
  --integration resend

Selected integrations add the provider package, required peer dependencies, .env.example, and setup notes in docs/integrations.md.

For an app with extra services, compose the preset and integrations explicitly:

bunx -p @beignet/cli beignet create my-app \
  --preset standard \
  --integrations drizzle-turso,inngest,resend,upstash-rate-limit

Available integrations:

IntegrationAdds
better-auth@beignet/provider-auth-better-auth, better-auth, and notes for replacing the starter's anonymous AuthPort
drizzle-turso@beignet/provider-drizzle-turso, @libsql/client, drizzle-orm, drizzle-kit, and persistence scaffolding
inngest@beignet/core/jobs, @beignet/provider-inngest, and inngest
pino@beignet/provider-logger-pino and pino
resend@beignet/provider-mail-resend and resend
upstash-rate-limit@beignet/provider-rate-limit-upstash, @upstash/ratelimit, and @upstash/redis

App conventions

See App architecture for the full structure and route registration model.

Beignet CLI commands are convention-aware. routes, lint, doctor, and generators work best in the Next.js layout created by beignet create:

features/
app/api/
server/index.ts
server/routes.ts

Route inspection supports contract-group definitions and direct createContract({ method, path }) exports.

The standard app layout includes the files resource generators expect:

app-context.ts
infra/app-ports.ts
ports/index.ts
lib/use-case.ts

Generated apps include these files by default. If you move them, keep the same architecture and point beignet.config.* at the new paths. The CLI uses this shape to inspect routes, wire generated resources, and report drift safely.

beignet doctor reports when a directory does not match the app layout.

Use beignet.config.ts, beignet.config.js, beignet.config.mjs, or beignet.config.json when your app keeps the same architecture under different paths:

// beignet.config.ts
import { defineConfig } from "@beignet/cli/config";

export default defineConfig({
  paths: {
    contracts: "src/features",
    features: "src/features",
    routes: "src/app/api",
    server: "src/core/server/index.ts",
  },
});

Config values are optional overrides. Omitted paths fall back to the generated defaults. routes, lint, doctor, and make generators all load the same resolved config before inspecting or writing files.

Generate a contract

Use make contract when you want to start with the HTTP contract only:

beignet make contract projects

The command honors beignet.config.* path overrides and writes features/projects/contracts.ts. It creates a self-contained contract group with a starter list endpoint, schema, standard error response, and exported contract list. It does not wire route handlers, use cases, ports, or OpenAPI; use make resource when you want the full path from contract to tests.

Like make resource, make contract skips identical files and stops on divergent files unless you pass --force.

Generate a use case

Use make use-case inside a Beignet app when you want a focused application workflow without generating HTTP contracts or ports:

beignet make use-case projects/archive-project

The name uses feature/action format. The command writes features/projects/use-cases/archive-project.ts and creates or updates features/projects/use-cases/index.ts. Read-style actions that start with get, list, find, search, or count generate .query(...); other actions generate .command(...).

Generate a test

Use make test after generating a use case:

beignet make use-case projects/archive-project
beignet make test projects/archive-project

The command writes features/projects/tests/archive-project.test.ts, builds the app context through createUseCaseTester, and asserts the starter { ok: true } response. It also adds a test script when the app does not already define one. Treat the output as a compiling starting point: replace the input, context setup, and assertion with behavior-specific coverage as the use case grows.

Generate events, jobs, listeners, and schedules

Use feature artifact generators when a workflow needs facts, background work, event reactions, or cron-triggered work:

beignet make event posts/published
beignet make job posts/send-published-email
beignet make listener posts/enqueue-published-email --event posts/published
beignet make schedule posts/daily-summary --cron "0 9 * * *" --timezone America/Chicago --route

The name uses feature/name format. The commands write colocated feature files:

Each command creates or updates the folder's index.ts with a registry such as postEvents, postJobs, postListeners, or postSchedules. Those registries give provider wiring, workers, cron routes, and tests one predictable import.

make event and make listener add @beignet/core/events; make job adds @beignet/core/jobs; make schedule adds @beignet/core/schedules; passing --route also writes app/api/cron/<feature>/<name>/route.ts. Generated cron routes require CRON_SECRET and record schedule start, completion, and failure events in devtools.

make listener expects the event file to exist at the canonical generated path. Run make event <feature>/<event> first, then generate listeners for that event.

Generate a port

Use make port inside a Beignet app when a use case needs a new application boundary:

beignet make port email

The command writes ports/email.ts, adds the port to AppPorts, creates a small fake adapter for tests, and wires a throwing infra stub so the app still typechecks until you replace it with a real port adapter. The generated port starts with a generic execute method; rename it to the domain operation your use case needs.

Generate a policy

Use make policy when repeated authorization rules need a named home:

beignet make policy posts

The command writes features/posts/policy.ts with a definePolicy(...) starter. Register the policy with createGate(...), install the gate as a port, and bind it into request context so use cases can call ctx.gate.authorize(...).

Generate a port adapter

Use make adapter after generating a port when you are ready to replace the generated throwing stub with a concrete infra implementation.

beignet make port email
beignet make adapter email

The command writes infra/email/email-adapter.ts and replaces the generated inline infra stub with email: createEmailAdapter(). The adapter still throws by default; replace its implementation with real infrastructure code while keeping use cases behind the port interface. If the infra wiring was already customized, the command stops instead of guessing.

Generate a resource

Use make resource inside a Beignet app when you want a new vertical slice with contracts, use cases, ports, infra, feature route wiring, and tests.

beignet make resource projects

The command honors beignet.config.* path overrides and writes:

It also updates the central route registry (server/routes.ts in generated apps), ports/index.ts, infra/app-ports.ts, and adds a test script when the app does not already define one. OpenAPI routes that use server.contracts or contractsFromRoutes(routes) stay in sync automatically through route registration. Legacy direct createOpenAPIHandler([...]) arrays are updated conservatively when possible. Generated resources start with a minimal name field so the app typechecks immediately; rename the generated schemas and repository fields for your domain.

In apps created with the drizzle-turso integration, make resource also creates infra/db/schema/projects.ts, infra/projects/drizzle-project-repository.ts, and registers the repository in infra/db/repositories.ts. The in-memory repository remains available as a test fake.

Read Build your first resource for the guided version of this flow.

make resource is idempotent for unchanged generated files: repeated runs skip identical files and still avoid duplicate wiring. If a generated file exists with different content, the command stops unless you pass --force.

Preview writes without changing files:

beignet make resource projects --dry-run

Use JSON output when another tool needs the exact planned changes:

beignet make resource projects --dry-run --json

Inspect routes

Use routes inside an app when you want to see which contracts the CLI can match to Next.js route handlers.

beignet routes

The table shows method, path, contract export, and the handler file. For scripts or CI jobs, use JSON:

beignet routes --json

Check for drift

Use doctor to catch common contract wiring drift:

beignet doctor

The checks detect contracts without a matching Next.js route handler, feature route groups missing from the central route list, route handlers that do not map to known contracts, OpenAPI drift in legacy direct arrays and common exported contract lists, partially wired generated resource slices, provider packages without matching canonical app ports, and generated ports without test fakes. doctor exits non-zero for errors and also supports JSON output:

beignet doctor --json

Use --strict for CI-oriented checks that may be noisy locally, such as missing generated resource tests. Strict mode exits non-zero for warnings as well as errors.

beignet doctor --strict --json

Use --fix for low-risk maintenance fixes. Today it can add a missing test script and repair legacy direct createOpenAPIHandler([...]) arrays when the missing contracts are already imported in the OpenAPI route.

beignet doctor --fix

Lint dependency direction

Use lint when you want the CLI to enforce Beignet's architectural import rules:

beignet lint

The command scans static imports and exits non-zero when core feature code reaches into runtime or framework layers. It checks domain, use case, policy, port, contract, and route files for imports from infra/, UI components, client modules, provider packages, Next.js, React, database vendors, or other runtime-only dependencies in the wrong direction.

Use JSON output for CI annotations or custom scripts:

beignet lint --json

Options

beignet create <directory> [options]
beignet make contract <name> [options]
beignet make event <feature>/<name> [options]
beignet make job <feature>/<name> [options]
beignet make listener <feature>/<name> --event <feature>/<event> [options]
beignet make schedule <feature>/<name> [options]
beignet make port <name> [options]
beignet make policy <name> [options]
beignet make adapter <name> [options]
beignet make resource <name> [options]
beignet make test <feature>/<action> [options]
beignet make use-case <feature>/<action> [options]
beignet routes [--json]
beignet lint [--json]
beignet doctor [--json] [--strict] [--fix]
OptionDescription
--template nextSelects the app template. next is the only template today.
--preset standardSelects minimal or standard. Defaults to standard.
--package-manager bunControls the package manager shown in next steps.
--feature <name>Adds one feature. Repeatable.
--features <names>Adds features from a comma-separated list.
--integration <name>Adds one integration. Repeatable.
--integrations <names>Adds integrations from a comma-separated list.
--forceWith create, writes into a non-empty directory. With make, overwrites generated files.
--dry-runPreviews make writes without changing files.
--jsonPrints machine-readable output for routes, lint, doctor, or make commands.
--event <feature>/<event>Selects the event for make listener.
--cron <expression>Sets the cron expression for make schedule. Defaults to 0 9 * * *.
--timezone <zone>Sets the schedule timezone, for example America/Chicago.
--routeAdds a Next.js cron route for make schedule.
--strictIncludes CI-oriented doctor warnings and fails on warnings.
--fixApplies low-risk doctor fixes before reporting remaining drift.