Skip to content

Every command

All of them, as bun elvel list prints them. A command exists only if its package is registered, so this is the framework's full set and your application's list is the honest one:

bash
bun elvel list
bun elvel <command> --help

--isolated on a command that allows it runs only if no other copy holds the lock — see the console page.

Running things

Command
serveServe the application
devServer (--hot), Vite, a queue worker and the scheduler, in one terminal
aboutEnvironment, paths, registered routes, view engine
envWhich environment this is
pingReplies, to prove command discovery works

Making things

make:cast · make:channel · make:class · make:command · make:component · make:config · make:controller · make:enum · make:event · make:exception · make:factory · make:interface · make:job · make:job-middleware · make:listener · make:mail · make:middleware · make:migration · make:model · make:notification · make:observer · make:policy · make:provider · make:request · make:resource · make:rule · make:scope · make:seeder · make:test · make:view

Every one reads a stub, and the stubs are yours: stub:publish --list shows what would be published and from where.

make:controller -r adds CRUD routes.

Database

Command
migrateRun the pending migrations
migrate:statusWhich have run
migrate:rollbackReverse the last batch
migrate:resetReverse every migration
migrate:refreshReverse and re-run
migrate:freshDrop every table and re-run
migrate:installCreate the tracking table by itself
dbOpen a database CLI session
db:seedRun the seeders
db:showThe tables
db:tableThe columns of one
db:wipeDrop every table, no migrations
db:monitorHow many connections each database has open
schema:dumpWrite the current schema to a file
model:showA model, its table and its columns
model:pruneDelete records a model says are no longer needed

Three of those are worth a second look.

db:monitor takes --max and --json, so it is a health check rather than a curiosity: over the threshold it fails, and a scheduled entry can page you. Remember a Bun SQL connection is a poolnew SQL() opens ten by default, so anything counting connections has to allow for its own.

schema:dump --prune replaces the migration files it folds in. That is what keeps a five-year-old application from running four hundred migrations to build a test database.

model:prune --pretend reports what it would delete. Run that first, every time.

Cache, queue, schedule

cache:clear · cache:forget · cache:prune · cache:tableCache
queue:work · queue:listen · queue:restart · queue:pause · queue:resume · queue:size · queue:monitor · queue:clearQueues
queue:failed · queue:retry · queue:forget · queue:flush · queue:retry-batch · queue:prune-batchesFailures and batches
queue:table · queue:failed-table · queue:batches-tableMigrations
schedule:run · schedule:work · schedule:list · schedule:test · schedule:interrupt · schedule:pause · schedule:resume · schedule:clear-cacheScheduling

cache:prune is for the database store only — it has no expiry of its own, so something has to sweep it. A scheduled cache:prune --store=database is the usual answer.

Configuration and caches

Command
config:showWhat the application actually resolved — a file or one key
config:publishFetch a config file the kit did not ship
mail:themeWrite a copy of the mail stylesheet to edit
config:cacheFreeze every config file into one JSON document
config:clearUndo that
optimizeconfig:cache + app:build
optimize:clearUndo both
app:buildBundle to dist/elvel.js

config:show is the one to reach for when a value is not what you expected: it prints what was resolved, after .env, defaults and the cache.

Inspecting

Command
route:listEvery route, with its middleware
middleware:listAliases, groups, and how many routes use each
event:listRegistered listeners
channel:listBroadcast channels and the order they match in
log:tailFollow the log as it is written

middleware:list's route count is the useful column — a middleware at 0 is either dead or a guard somebody forgot to apply.

log:tail takes --level, --filter and --lines, so it is tail -f | grep without needing to know where the file is.

Lens

Only when @elvel/lens is installed and registered.

Command
lens:installPublish the config and your own provider
lens:tableMigration for the three tables
lens:statusIs it recording, what does it hold, which watchers are awake
lens:pause / lens:resumeStop and start recording without a deploy
lens:prune --hours=48Delete entries past the retention window — schedule this
lens:clearEverything

lens:prune takes --keep-exceptions. Nothing prunes on its own, so an application that never schedules it grows a table without a ceiling.

Keys and secrets

Command
key:generateWrite APP_KEY
auth:secretWrite AUTH_SECRET
env:encryptEncrypt .env so it can be committed
env:decryptDecrypt it again
encryption:rotate <table> <column>Re-encrypt a column onto the current key

APP_KEY and AUTH_SECRET are different keys and must stay different. One encrypts data, the other signs sessions; a single value doing both means a leak of either is a leak of both.

env:encrypt takes --env=staging to encrypt .env.staging, and prints the key it generated unless you pass --key. That key does not belong in the repository — it goes wherever your deployment keeps secrets.

encryption:rotate walks a table and re-encrypts one column, which is how you retire an old APP_KEY without losing the data encrypted under it. Without it, rotating a key means every encrypted cast stops decrypting.

Auth, storage, install

Command
auth:schemaGenerate a migration for better-auth's tables
auth:schema --diffOnly what the database is missing — the one to use after the first migration
session:gcDelete sessions idle past their lifetime — nothing else does
storage:link / storage:unlinkThe symlinks config/filesystems.ts names
session:table · notifications:tableMigrations for those drivers
install:apiAdd an API routes file and wire it into the bootstrap
install:broadcastingAdd the broadcasting config file
stub:publishPublish the framework's stubs for editing

install:* exists because a starter kit prunes what it does not use: an application scaffolded with --kit=none has no API routes file, and this adds one without re-scaffolding.

Maintenance mode

bash
bun elvel down --retry=60 --except=/health --with-secret
bun elvel down --render=errors.maintenance
bun elvel up

Middleware has what --with-secret does and why the payload lives in a file.

MIT. Alpha — the shape is settled, the surface still moves.