@beignet/cli
v0.0.3
Published
CLI for creating and maintaining Beignet apps.
Downloads
240
Maintainers
Readme
@beignet/cli
Command-line tools for creating and maintaining Beignet apps.
Create an app
bunx -p @beignet/cli beignet create my-appOr use the package binary directly:
bunx -p @beignet/cli create-beignet my-appBy default the CLI creates a Next.js app with:
- Contract-first todos API routes
- Better Auth routes and Beignet auth provider wiring
- Drizzle/libSQL persistence with a local SQLite default and Turso-ready config
- UOW, audit logging, and a durable outbox drain route
- Jobs, events, listeners, schedules, mail-backed notifications, and uploads
- App-owned ports with provider-backed infra adapters
- Validated application use cases
- A Beignet server wired through Next.js route handlers
- App error helpers, auth helpers, env validation, health checks, and devtools
- A typed client
- TanStack Query
- React Hook Form
- OpenAPI output
The CLI writes files only. After creation:
cd my-app
bun install
cp .env.example .env.local
bun run devCommon follow-up commands:
# in another terminal, from my-app
bunx -p @beignet/cli beignet make feature projects
bunx -p @beignet/cli beignet db generate
bunx -p @beignet/cli beignet db migrate
bunx -p @beignet/cli beignet routes
bunx -p @beignet/cli beignet lint
bunx -p @beignet/cli beignet doctorOptions
beignet create <directory> [options]
beignet make contract <name> [options]
beignet make event <feature>/<name> [options]
beignet make factory <feature>/<name> [options]
beignet make feature <name> [options]
beignet make job <feature>/<name> [options]
beignet make notification <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 seed <feature>/<name> [options]
beignet make test <feature>/<action> [options]
beignet make use-case <feature>/<action> [options]
beignet db generate [--dry-run] [--json]
beignet db migrate [--dry-run] [--json]
beignet db seed [--dry-run] [--json]
beignet db reset [--dry-run] [--json]
beignet routes [--json]
beignet lint [--json]
beignet doctor [--json] [--strict] [--fix]
Options:
--template next Template to use. Currently only `next`.
--preset standard `minimal` or `standard`.
--package-manager bun Package manager shown in next steps.
--feature react-query Add a starter feature. Repeatable.
--features client,openapi Add features from a comma-separated list.
--integration inngest Add an integration. Repeatable.
--integrations inngest,pino Add integrations from a comma-separated list.
--force Write into a non-empty directory.
--dry-run Preview make writes without changing files.
--json Print machine-readable output.
--with policy,events Add optional artifacts to `make feature`; also supports jobs, notifications, uploads.
--event posts/published Event for `make listener`.
--cron "0 9 * * *" Cron expression for `make schedule`.
--timezone America/Chicago Timezone for `make schedule`.
--route Add a Next.js cron route for `make schedule`.
--strict Include CI-oriented doctor warnings and fail on warnings.
--fix Apply low-risk doctor fixes before reporting.
-h, --help Show help.App conventions
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.tsRoute inspection supports contract-group definitions and direct
createContract({ method, path }) exports.
The standard app layout includes the files feature generators expect:
app-context.ts
infra/app-ports.ts
ports/index.ts
lib/use-case.tsGenerated apps include these files by default. The CLI uses this shape to
inspect routes, wire generated features, 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 projectsThe 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 feature when you want the full path from contract to tests.
Like make feature, make contract skips identical files and stops on
divergent files unless you pass --force.
Generate a feature
Inside a Beignet app, scaffold the standard contract-first vertical slice with:
beignet make feature projectsThe command honors beignet.config.* path overrides. It writes:
features/projects/contracts.tsfeatures/projects/use-cases/features/projects/ports.tsinfra/projects/drizzle-project-repository.tsfeatures/projects/routes.tsfeatures/projects/tests/projects.test.ts
It also wires the slice into the central route registry (server/routes.ts in
generated apps), ports/index.ts, infra/db/repositories.ts, and adds a
test script if the app does not already have one. The generated slice uses a small
name field by default so the app stays typecheckable immediately. Treat that
field as a placeholder and shape the schemas, use cases, repository, and tests
around the feature's real workflow.
Add common feature-owned artifacts with --with:
beignet make feature projects --with policy,events,jobs,uploadsThe optional artifacts use predictable starter names:
features/projects/policy.tsfeatures/projects/domain/events/created.tsfeatures/projects/jobs/process.tsfeatures/projects/uploads/attachment.ts
Event, job, and upload registries are created or updated in the matching
folder index.ts files.
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-projectThe 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-projectThe 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 a port
Use make port inside a Beignet app when a use case needs a new
application boundary:
beignet make port emailThe 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 postsThe 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(...).
For tenant, ownership, or role-heavy rules, add a matrix test with
createPolicyTester(...) from @beignet/core/ports/testing.
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 emailThe 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 when the feature you are building is CRUD-shaped and you
prefer resource language:
beignet make resource projectsToday make resource and make feature generate the same contract-to-test
slice. The feature command is the recommended default because not every Beignet
feature maps cleanly to a REST resource.
In standard apps, the command also creates
infra/db/schema/projects.ts,
infra/projects/drizzle-project-repository.ts, and registers the repository in
infra/db/repositories.ts.
Generate events, jobs, notifications, listeners, schedules, and uploads
Use feature artifact generators when a workflow grows beyond a single use case:
beignet make event posts/published
beignet make job posts/send-published-email
beignet make notification posts/published
beignet make listener posts/enqueue-published-email --event posts/published
beignet make schedule posts/daily-summary --cron "0 9 * * *" --timezone America/Chicago --route
beignet make upload posts/attachmentThese commands use feature/name format and write colocated feature files:
features/posts/domain/events/published.tsfeatures/posts/jobs/send-published-email.tsfeatures/posts/notifications/published.tsfeatures/posts/listeners/enqueue-published-email.tsfeatures/posts/schedules/daily-summary.tsfeatures/posts/uploads/attachment.ts
Each command creates or updates the folder's index.ts with an exported
registry such as postJobs, postNotifications, postListeners,
postSchedules, or postUploads. Event and listener generators add
@beignet/core/events, job generators use @beignet/core/jobs, notification
generators use @beignet/core/notifications, schedule generators use
@beignet/core/schedules, and upload generators use @beignet/core/uploads.
--route also writes a Next.js cron
route under app/api/cron/<feature>/<name>/route.ts. Generated cron routes
require CRON_SECRET and record schedule start, completion, and failure events
in devtools. Generated uploads include starter metadata, constraints,
authorization, storage key, storage metadata, and completion hooks.
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.
make feature and make resource are idempotent for unchanged generated files:
repeated runs skip identical files and avoid duplicate wiring. If a generated
file exists with different content, the command stops unless you pass --force.
Database lifecycle
Use beignet db from an app root to run database workflow scripts through one
stable framework command surface:
beignet db generate
beignet db migrate
beignet db seed
beignet db resetThe CLI delegates to app-owned package scripts named db:generate,
db:migrate, db:seed, and db:reset. In standard Drizzle apps, those scripts
run Drizzle Kit and the generated infra/db/seed.ts / infra/db/reset.ts
entrypoints. This keeps schema generation and migration behavior Drizzle-native
while making the lifecycle discoverable through Beignet.
db reset is intentionally app-owned because destructive behavior depends on
the environment. The standard starter refuses to reset non-local database URLs
unless BEIGNET_ALLOW_DATABASE_RESET=true is set.
Generate feature-owned test factories and local/demo seeds with:
beignet make factory posts/post
beignet make seed posts/demo-postsFactories are written under features/posts/tests/factories/ and persist
through app-owned repository ports. Seeds are written under
features/posts/seeds/; import them from the app-owned database seed entrypoint
and run them with runSeeds(...).
Preview writes without changing files:
beignet make feature projects --dry-runUse JSON output when another tool needs the exact planned changes:
beignet make feature projects --dry-run --jsonInspect app routes
Inside an app, list the contracts the CLI can match to Next.js route handlers:
beignet routesUse JSON output when you want to feed the route catalog into another tool:
beignet routes --jsonLint app architecture
Run lint when you want the CLI to enforce Beignet dependency direction:
beignet lintThe command scans static imports and fails when core feature layers reach into
runtime or framework layers. It catches domain, use case, workflow, policy,
port, contract, and route files importing things like infra/, UI components,
client modules, provider packages, Next.js, React, or database vendors in the
wrong direction. Workflow folders include feature-owned jobs, listeners,
notifications, schedules, and uploads.
Use JSON output in CI or custom scripts:
beignet lint --jsonCheck for drift
Run doctor when you want quick feedback on contract wiring drift:
beignet doctorToday it detects:
- Contracts without a matching Next.js route handler
- Feature route groups that are not registered in the central route list
- Next.js route handlers that do not map to known contracts
- OpenAPI drift in direct arrays and common exported contract lists
- Partially wired generated feature slices
- Provider packages without matching canonical app ports
- Generated ports without test fakes
- Drizzle repository adapters that are not wired through
infra/db/repositories.ts - Repository ports whose infra folder has no repository adapter
- Feature seeds without a matching feature factory
- Feature seeds without a
db:seedpackage script - Upload definitions without an upload route
- Notification dispatchers that bypass
ctx.ports.notifications - Feature artifacts in non-canonical folders
Use beignet doctor --strict for CI-oriented checks that may be noisy
locally, such as missing generated feature tests. Use
beignet doctor --json in CI or custom scripts.
Use beignet doctor --fix for low-risk maintenance fixes. Today it can add
a missing test script and repair direct createOpenAPIHandler([...]) arrays
when the missing contracts are already imported in the OpenAPI route.
Available presets:
minimal- choose this when you want the small contract/core/server/use-case loop without the full app conventions.standard- choose this when you want the full app layout with Better Auth, Drizzle/libSQL, UOW, outbox, audit logging, devtools, provider wiring, health checks, typed clients, feature-owned jobs/events/schedules/uploads/notifications, and separatedports/+infra/.
The standard preset includes the local production-shaped defaults: Better Auth, Drizzle/libSQL, Pino logging, local storage, devtools, UOW, outbox, audit logging, and feature-owned background workflow examples. Add external service integrations only when you want those providers:
bunx -p @beignet/cli beignet create my-app --preset standard --integrations drizzle-turso,inngest,resendAvailable features:
clientreact-queryformsopenapi
Available integrations:
better-authdrizzle-tursoinngestpinoresendupstash-rate-limit
With --preset standard, Drizzle/libSQL is included by default. The starter scaffolds infra/db/schema/, infra/db/repositories.ts, a Drizzle todo repository adapter, drizzle.config.ts, database scripts, and TURSO_* env examples so the generated todo resource uses durable persistence instead of the in-memory repository. Later make feature or make resource calls in that app generate both a Drizzle table/repository and an in-memory test fake.
With --preset standard, Better Auth is included by default. The starter adds
the Better Auth Next.js route, Beignet auth provider wiring, typed
UNAUTHORIZED and FORBIDDEN errors, a request-bound authorization gate, and
requireUser(ctx). Use hooks for HTTP boundary authentication and use cases or
policies for business authorization.
License
MIT
