Runtime commands
Generated projects wire steward.CLI in main.go, which turns your app
binary into its own operations tool — migrations are Go code compiled into
the app, so runtime operations run in the app, not in the global
steward generator.
steward.CLI(steward.App{
Build: app.Build, // constructs the configured *steward.Admin
Migrations: migrations.All, // the app's own migrations
Jobs: registerJobs, // optional: recurring jobs (worker only)
})Commands
| Command | Does |
|---|---|
serve [-addr :8080] | start the panel (default command) |
worker | run App.Jobs on the scheduler — no HTTP |
migrate up | apply pending migrations |
migrate down [-steps N] | roll back (default: the last batch) |
migrate status | list every migration with batch and timestamp |
menu:sync | re-sync menu entries from registered resources |
admin:create-user | create a panel account (prompts for the password) |
The worker process
Background jobs deliberately do not run inside serve: if they did,
every extra web replica would fire every cron job again, and panel deploys
would kill mid-flight work. Instead, register jobs on App.Jobs and run
the same binary twice:
Jobs: func(a *steward.Admin, s steward.Scheduler) error {
err := s.Add("@every 10m", "cleanup-sessions", func(ctx context.Context) error {
return a.DB().WithContext(ctx).Exec("DELETE FROM ...").Error
})
if err != nil {
return err
}
return s.Add("0 3 * * *", "nightly-report", sendReport)
},./app serve # deployment 1: the panel, scale as you like
./app worker # deployment 2: exactly one instance runs the jobsOne build artifact, two independently deployable processes. The worker
stops gracefully on SIGINT/SIGTERM.
Schedule specs: @every <duration> (any time.ParseDuration string),
@hourly, @daily, @weekly, or a five-field cron expression
(30 2 * * 1-5, minute resolution).
Note
Run a single worker instance unless your jobs are idempotent — there is no distributed locking between workers.
Deployment sketch
FROM golang:1.26 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app .
FROM gcr.io/distroless/static
COPY --from=build /app /app
ENTRYPOINT ["/app"]
CMD ["serve"] # worker deployment overrides: CMD ["worker"]Set STEWARD_SECRET (scaffolded apps read it for the session key) and your
database DSN via the environment; run /app migrate up as a release step.