CLI
@beignet/cli creates Beignet apps, generates feature slices and workflow
artifacts, runs database and operational entrypoints, inspects route wiring,
and catches drift after manual edits. Use Quickstart to
create and run your first app; use this page as the command reference.
Scaffold a new app through your package manager's create command. Inside a
generated app, @beignet/cli is already a dev dependency with a beignet
package script. Or run the scoped package without installing:
bun create beignet my-app
bun beignet lint
npm run beignet -- lint
bunx @beignet/cli doctor --strict
npx @beignet/cli doctor --strictAlways pass the scoped name (@beignet/cli) to bunx, npx, pnpm dlx, or
yarn dlx — the unscoped npm name beignet belongs to an unrelated package.
Reference blocks below show the bare beignet <command> syntax; prefix it
with your package manager. beignet --version prints the installed CLI
version.
Commands
| Command | What it does |
|---|---|
beignet create [directory] | Scaffold a new Beignet app. |
beignet make <generator> <name> | Generate feature slices and workflow artifacts. |
beignet db <subcommand> | Run the app's database lifecycle scripts. |
beignet routes | Inspect contract-to-route wiring. |
beignet lint | Enforce architecture dependency direction. |
beignet doctor | Report framework drift, optionally fixing it. |
beignet task run <name> | Run an app-owned operational task. |
beignet schedule run <name> | Run an app-owned schedule once. |
beignet outbox drain | Run one bounded outbox drain pass. |
beignet mcp | Run an MCP server exposing CLI tools to coding agents. |
beignet completion <install|uninstall> | Manage bash or zsh completions. |
create
bun create beignet my-appIn an interactive terminal without selection flags, create prompts for the
project directory, whether the app is API-only, which database to use, and
which integrations to add. A selection flag (--api, --db, or
--integrations) skips the prompts, --yes forces the defaults, and non-TTY
environments never see prompts. There is one full-stack starter; --api
drops the UI shell and app pages while keeping the same architecture, and
--db picks the database backend (sqlite by default). The CLI writes files
only — see Quickstart for what the starter contains and
the install, environment, migrate, and first-run steps, and
Database and transactions for what each --db backend
scaffolds.
Better Auth, Drizzle persistence, and Pino are part of every starter, so
passing them to --integrations is an error. Integrations add external
service providers on top: the provider package, peer dependencies, wiring in
server/providers.ts, .env.example entries, and setup notes in
docs/integrations.md.
| Integration | Adds |
|---|---|
inngest | @beignet/core/jobs, @beignet/provider-inngest, and inngest |
resend | @beignet/provider-mail-resend and resend |
upstash-rate-limit | @beignet/provider-rate-limit-upstash, @upstash/ratelimit, and @upstash/redis |
| Option | Description |
|---|---|
--template <name> | App template. next is the only template today. |
--api | Scaffold an API-only app without the UI shell. |
--db <database> | Database backend: sqlite (default), postgres, or mysql. |
--package-manager <pm> | bun, npm, pnpm, or yarn, used in printed next steps. |
--integrations <names> | One value or a comma-separated list. |
--yes | Skip interactive prompts and use the defaults. |
--force | Write into a non-empty directory. |
--dry-run | Preview planned writes without creating files. |
--json | Print the plan or result as JSON. |
make
Generators run inside an app and target the canonical structure described in
App architecture. All of them — along with routes,
lint, and doctor — resolve beignet.config.* (.ts, .json, .mjs, or
.js) path overrides first; omitted paths fall back to the generated
defaults. Generators are idempotent: repeated runs skip identical files and
avoid duplicate wiring, and a generated file that diverged stops the command
unless you pass --force.
Every make command accepts:
| Option | Description |
|---|---|
--dry-run | Preview generated changes without writing files. |
--json | Print the planned or written changes as JSON. |
--force | Overwrite generated files that diverged. |
make feature
beignet make feature projectsGenerates the contract-first vertical slice for a product capability:
contracts.ts, schemas.ts, use-cases/, ports.ts, routes.ts, a test
file, and a Drizzle repository adapter. It registers the route group in
server/routes.ts, the port in ports/index.ts, and the repository in
infra/db/repositories.ts; OpenAPI routes that use route registration stay in
sync automatically. The generated name field is a placeholder — reshape the
slice around the real workflow.
| Option | Description |
|---|---|
--with <addons> | Adds feature-owned artifacts: policy, task/tasks, event/events, job/jobs, notification/notifications, ui, upload/uploads. |
Each addon writes the same output as the matching standalone generator; ui
writes a feature-colocated React component wired to the typed client and
TanStack Query.
make resource
beignet make resource projects
beignet make resource projects --auth --tenant --events --soft-deleteGenerates a CRUD-shaped slice when the concept is an entity with
repository-backed persistence: list, create, get, update, and delete
contracts, use cases, route handlers, repository methods, a policy starter,
tests, feature-specific not-found and conflict catalog errors, a Drizzle
schema file, and repository registration. Generated list endpoints use cursor
pagination, and updates use optimistic concurrency version checks that turn
stale writes into the generated conflict error. See
Build your first feature for the guided flow.
| Option | Description |
|---|---|
--auth | Authorization metadata, policy wiring, ctx.gate.authorize(...) checks, and a policy matrix test. |
--tenant | Tenant-scoped schemas, repository filters, and use-case checks. |
--events | Created, updated, and deleted domain events published through ctx.ports.eventBus. |
--soft-delete | Archive rows with deletedAt instead of hard-deleting. |
--events also wires the event bus when the app has none, exactly like
make event (see workflow generators below).
make contract
beignet make contract projectsWrites features/projects/contracts.ts with a starter contract group, schema,
and standard error response. It does not wire routes, use cases, or ports —
use make feature for the full slice. See Contracts.
make use-case and make test
beignet make use-case projects/archive-project
beignet make test projects/archive-projectmake use-case writes features/projects/use-cases/archive-project.ts and
updates the use-case index; actions starting with get, list, find,
search, or count generate .query(...), others .command(...). make test writes features/projects/tests/archive-project.test.ts using the test
context helpers. See Application and Testing.
make port, make adapter, and make policy
beignet make port email
beignet make adapter email
beignet make policy postsmake port writes ports/email.ts, adds the port to AppPorts, creates a
test fake, and wires a throwing infra stub so the app still typechecks. make adapter writes infra/email/email-adapter.ts and replaces the stub; it stops
instead of guessing when the infra wiring was customized. make policy writes
features/posts/policy.ts with a definePolicy(...) starter. See
Ports and Authorization.
Workflow generators
beignet make event posts/published
beignet make listener posts/enqueue-published-email --event posts/published
beignet make job posts/send-published-email
beignet make notification posts/published
beignet make schedule posts/daily-summary --cron "0 9 * * *" --timezone America/Chicago --route
beignet make task posts/backfill-search
beignet make upload posts/attachmentNames use feature/name format. Each generator writes the colocated feature
file (for example features/posts/jobs/send-published-email.ts), creates or
updates the folder's registry index.ts (postEvents, postJobs, and so
on), and creates the matching app-bound lib/ builder such as lib/jobs.ts
on first use. New apps do not scaffold workflow folders; generators create
them on demand. They also keep central registries and ports wired:
make scheduleandmake taskcreate or update theserver/schedules.tsandserver/tasks.tsregistries used by the runners below.make eventandmake jobappend the feature's registries todefineOutboxRegistry({...})inserver/outbox.tswhen that file already exists; the outbox registry is opt-in, so the generators never create it. See Outbox.make eventandmake resource --eventswireeventBus: EventBusPortintoAppPorts, registercreateInMemoryEventBusProvider()inserver/providers.ts, and add the@beignet/provider-event-bus-memorydependency when the ports file lacks the key.make notificationwiresmailer: MailerPortwithcreateMemoryMailerProvider()andnotifications: NotificationPortwithcreateInlineNotificationsProvider(), each independently and only when missing, so integrations such as resend and app-owned adapters are left untouched. Swap the dev-default providers when you outgrow them.make listenerrequires--eventand expects the event file to exist; runmake eventfirst.make schedule --routewritesapp/api/cron/<feature>/<name>/route.ts, which requiresCRON_SECRET, and adds a generatedCRON_SECRETtolib/env.tsand.env.examplewhen the app does not define one.
| Command | Options |
|---|---|
make listener | --event <feature>/<event> (required). |
make schedule | --cron <expression> (defaults to 0 9 * * *), --timezone <zone>, --route. |
Concept pages: Events, Jobs, Schedules, Notifications, and Uploads. Operational tasks are app-owned entrypoints for backfills, maintenance, and one-off repair work; they should call use cases or ports rather than copying business rules into scripts.
make factory and make seed
beignet make factory posts/post
beignet make seed posts/demo-postsmake factory writes features/posts/tests/factories/post.ts plus a factory
registry; the starter persists through repository ports. make seed writes
features/posts/seeds/demo-posts.ts plus a seed registry; run seeds from the
app-owned infra/db/seed.ts entrypoint with runSeeds(...). See
Database.
db
beignet db generate
beignet db migrate
beignet db seed
beignet db resetEach subcommand delegates to the app-owned package script of the same name
(db:generate, db:migrate, db:seed, db:reset) and checks prerequisites
first — a missing script, missing drizzle.config.*, or removed seed/reset
entrypoint produces an error naming the exact file to restore. The starter
ships db:generate, db:migrate, and db:reset; run db migrate first
since the initial migration is vendored, and add a db:seed script with your
first feature seeds. See Database.
| Option | Description |
|---|---|
--dry-run | Print the command that would run without running it. |
--json | Print the script, runner, and captured output as JSON. |
routes
beignet routesPrints a table of method, path, contract export, and matched Next.js handler
file for every contract the CLI can inspect. It supports contract-group
definitions and direct defineContract({ method, path }) exports.
| Option | Description |
|---|---|
--json | Machine-readable route list. |
--cwd <dir> | Inspect an app root in another directory. Must point at an app, not a monorepo root. |
lint
beignet lintEnforces the architecture boundaries described in
App architecture: it scans static imports across app
layers, runs an additional value-import graph check for contracts and client
roots, and exits non-zero on findings. Diagnostics include the offending
file:line:column.
| Option | Description |
|---|---|
--json | Machine-readable diagnostics. |
--format <format> | human, json, or github workflow annotations. Defaults to human, or github when GITHUB_ACTIONS is set. |
--cwd <dir> | Lint an app root in another directory. |
doctor
beignet doctor
beignet doctor --strict
beignet doctor --fixThe framework integrity report. Diagnostics cover these areas:
- Routes and contracts — contracts without handlers, handlers without contracts, unregistered route groups, partially wired slices, and CRUD slices missing generated pieces.
- OpenAPI — drift in direct arrays, exported contract lists, and
contractsFromRoutes(routes)registries, plus entries for contracts outside the registered route surface. - Workflow registries — schedules and tasks missing from
server/schedules.tsorserver/tasks.ts, events with listeners and jobs missing fromdefineOutboxRegistry({...})whenserver/outbox.tsexists, listeners that noregisterListeners(...)call references, and serverless footguns such as background timers in provider files, outbox draining from lifecycle hooks, and outbox registries without a drain entrypoint. - Errors and authorization — route-owned catalog errors missing from
features/shared/errors.ts, runtimeappError(...)calls not declared on contracts, authorization metadata without policy coverage, and audit-required metadata without audit writes or test assertions. - Database — missing Drizzle config, schema exports, scripts, or
seed/reset entrypoints, unwired repository adapters, ports without
adapters, unguarded resets, and seeds without factories or a
db:seedscript. - Security and providers — devtools enabled without authorization, cron
routes without
CRON_SECRET, installed providers without expected env configuration, Better Auth without an auth route or trusted origins, credentialed wildcard CORS, uploads without routes or size limits, and notification dispatchers that bypassctx.ports.notifications. - Payments — billing slices without a payment webhook route, checkout
contracts missing idempotency metadata or an
idempotency-keyheader, and billing webhook use cases that referencectx.ports.idempotencywithout anAppPortsidempotency declaration, billing entitlement modules that are not wired into infra providers, entitlement checks without anAppPortsentitlements declaration, plus Stripe configuration still wired to local memory payments. - Structure and versions — feature artifacts in non-canonical folders,
strict-mode canonical conformance drift, mixed
@beignet/*version ranges or installed versions, and CLI/core version skew (an informational hint suggesting the app-localbun beignet).
Workflow artifacts the starter does not scaffold are not drift on their own;
doctor reports misplaced, unregistered, or partially wired artifacts, not
absent ones.
| Option | Description |
|---|---|
--strict | Include CI-oriented warnings (missing generated tests, conformance drift, unused route errors) and fail on warnings. Informational hints never affect the exit code. |
--fix | Apply low-risk fixes before reporting: add a missing test script, register route groups, register unregistered schedule, task, and outbox event/job registries in their existing central files, and repair direct createOpenAPIHandler([...]) arrays when the contracts are already imported. Registry fixes are append-only and bail out when the central file is missing or customized; listener registration is report-only. |
--json | Versioned payload (schemaVersion: 1) with targetDir, config, strict, convention, contracts, routes, diagnostics, and fixes. |
--format <format> | human, json, or github. Defaults to human, or github when GITHUB_ACTIONS is set. --json conflicts with any other --format. |
--cwd <dir> | Check an app root in another directory. |
task run
beignet task run posts.backfill-search --input '{"dryRun":true}'Runs an app-owned operational task through the registry in server/tasks.ts,
which exports tasks, createTaskContext(...), and optionally
stopTaskContext(...). Keep auth, tenancy, and provider lifecycle decisions
in that module so local shells, CI jobs, and deployed runners behave the same.
| Option | Description |
|---|---|
--input <json> | JSON input validated by the task schema. Defaults to {}. |
--module <path> | Task registry module. Defaults to server/tasks.ts or paths.tasks. |
--json | Print the task result as JSON. |
schedule run
beignet schedule run posts.daily-summary --scheduled-at 2026-01-01T09:00:00.000ZRuns a schedule explicitly from a local shell, CI job, or worker through the
registry in server/schedules.ts, which exports a schedules array,
createScheduleContext(...), and optionally stopScheduleContext(...). See
Schedules.
| Option | Description |
|---|---|
--payload <json> | JSON payload for the schedule schema. Omit it to use the schedule's createPayload(...). |
--module <path> | Schedule registry module. Defaults to server/schedules.ts or paths.schedules. |
--id <id> | Provider or app schedule run ID. |
--attempt <number> | One-based provider attempt number. |
--scheduled-at <date> | Provider scheduled timestamp. |
--triggered-at <date> | Schedule trigger timestamp. |
--source <label> | Provider or app source label. |
--json | Print the run result as JSON. |
outbox drain
beignet outbox drain --batch-size 100Drains durable events and jobs in one bounded pass through the registry in
server/outbox.ts, which exports outboxRegistry,
createOutboxDrainContext(...), and optionally stopOutboxDrainContext(...).
There is intentionally no separate jobs-drain command: outbox-backed jobs
drain here, and direct provider jobs use provider-owned worker entrypoints
such as an Inngest route. See Outbox.
| Option | Description |
|---|---|
--batch-size <number> | Maximum messages to claim in one pass. |
--module <path> | Outbox registry module. Defaults to server/outbox.ts or paths.outbox. |
--json | Print the drain result as JSON. |
mcp
beignet mcpRuns a Model Context Protocol server over stdio so coding agents can call the
CLI as tools: routes, doctor, doctor_fix, lint, and make. Tool
outputs are the same JSON the matching --json flags print, and make takes
the same artifact kinds as beignet make. Generated apps ship a .mcp.json
that registers the server, so MCP clients such as Claude Code pick it up
without configuration. See Coding agents for the tool list, manual
client registration, and the rest of the agent surface.
completion
beignet completion install
beignet completion install --shell zsh
beignet completion uninstallinstall writes a managed completion block to ~/.bashrc or ~/.zshrc,
detecting the shell from $SHELL; uninstall removes it. Restart your shell
or source the rc file to activate. Completions cover commands, subcommands,
flags, and enum values such as --with and --format, and complete whatever
beignet resolves to on your PATH through the internal
beignet completion propose helper.
| Option | Description |
|---|---|
--shell <shell> | bash or zsh. Defaults to $SHELL. |
--json | Print the install or uninstall result as JSON. |
Exit codes
Every command uses the same exit code contract, so CI scripts can branch on the result:
| Code | Meaning |
|---|---|
0 | Success. lint and doctor found nothing to report. |
1 | Findings. lint or doctor reported problems, or a command failed against the app. |
2 | Usage or internal error, such as an unknown command, invalid flags, or an unexpected CLI failure. |