CLI
CLI
The jsails binary is the single entry point for scaffolding, serving, schema
history, jobs, and deployment planning. It is human-first: it scaffolds and
serves, but decisions with domain impact — applying migrations, destructive
schema changes, deploy configuration — stay explicit human actions.
Built-in commands
The CLI implements these built-ins:
makemigrations— diff the model metadata against recorded history and write a migration file.migrate— apply migrations, or roll them back with--down/--steps.showmigrations— list applied and pending migrations.work— run a job worker and register schedules.schedule— register schedules once, then exit.queue— a read-only queue dashboard.build— static export intoout/.serve— listen untilSIGINT/SIGTERM.create— scaffold a new project.dev— compile, watch, and serve.seed— run registered database seeders.make:<page|api|job|model|command>— generate a single conventional file.jamal— deployment planning (see Jamal).plugins— discover, check, install, enable, disable, uninstall, and roll back plugins.inspect,describe,explain— read-only introspection (see Introspection).
jamal, plugins, make, inspect, describe, and explain own their own
subcommands and flags, so they are routed before the shared flag-gating and never
import an app config.
Config-file defaults
Each command family reads a compiled ESM config module. .ts config paths are
rejected — compile first.
| Command family | Default config |
|---|---|
makemigrations, migrate, showmigrations |
jsails.config.js |
work, schedule, queue |
jsails.runtime.js |
seed |
jsails.seed.js |
build, serve, dev |
jsails.app.js |
build, serve, and dev take no host/port/output flags — those come from the
app config. create takes no --config.
Scaffolding with create
create <dir> generates the starter file set and writes it through
writeProjectFiles. It refuses an existing non-empty target, a symlink target,
and a non-directory target, and never overwrites an existing file.
jsails create my-app --install --jsails-dependency "file:/tmp/jsails-0.1.0.tgz"
Flags:
--name <pkg>— the package name; defaults to the directory basename.--jsails-dependency <spec>— afile:tarball or path for the generatedpackage.json.--install— runnpm installafter writing. Nothing is installed unless this is passed; a failed install returns its exit code but keeps the scaffold so you can retry.--admin— add the first-party admin panel.--blog— add the first-party blog; implies--admin.--cli— scaffold a Laravel-Zero-style CLI-only project with no web surface but the same framework and plugin system.--static— scaffold a pure static-site (SSG) starter with no server plugins.
There is no --auth flag: the starter always includes auth. --cli is mutually
exclusive with --admin / --blog.
Generators — make:*
make:<page|api|job|model|command> <name> [--dir <path>] generates a single
conventional file using exclusive creation, so an existing file is never
overwritten:
pages/<name>.tsxapi/<name>.tsjobs/<name>.tsmodels/<name>.tscommands/<name>.ts
Names must match [A-Za-z][A-Za-z0-9_-]* and are case-normalized. The templates
follow the starter's own conventions so they compile against a fresh scaffold.
The command performs no writes beyond the single generated file and never imports
application code.
User-defined commands
An application can add commands without touching the entry point by declaring
them on the app config (commands: [...]) or on an extension
(extensions: [{ ..., commands: [...] }]). runCli dispatches a leading
non-builtin token to the custom path.
// jsails.app.js (app-owned; plain ESM, compiled JS)
export default {
commands: [
{
name: 'hello',
summary: 'say hello',
usage: 'hello [name]',
run(rawArgs, ctx) {
ctx.stdout(`hello ${rawArgs[0] ?? 'world'}`);
},
},
],
};
A command object is { name, summary, usage?, run(rawArgs, ctx) }. run may
return nothing (exit 0), a number in 0..255, or a promise of either, and
ctx.stdout / ctx.stderr write lines.
jsails hello --config jsails.app.js --rawargs
- Syntax is
<command> [--config <path>] [raw args]— the command name comes first. The custom path is taken only when--configis explicit or the defaultjsails.app.jsexists. - Only
--config <value>/--config=<value>before a--delimiter are parsed; every other token — including--itself and everything after it — is forwarded verbatim and in original order torun. jsails <command> --helpprints that command's exact metadata (name - summary,Usage: jsails <usage>) without invokingsetup,run, orcreateApplication. Globaljsails --helpimports no app config.- No application is assembled for a custom command and no extension
setupruns. A config module must still be imported to collect commands, so its own top-level code runs — trusted app JS side effects are not prevented. - The built-in names above (including
jamalandplugins) are always reserved and cannot be shadowed.
Next steps
- Introspection —
inspect,describe,explain, and the opt-in runtime endpoint.