Development
Services
Define local development service tasks that lazy and datasets can coordinate.
Two kinds of services
Application services are Go packages under services/ and are wired into the
app context. Read Dependencies And Services
for that application code.
Development services are local processes such as PostgreSQL, MinIO, search, or queues. They are owned by mise tasks so every app can decide how those tools start and stop.
Name lifecycle tasks
Use one service name and a fixed set of actions:
mise postgres:start
mise postgres:check
mise postgres:create
mise postgres:migrate
mise postgres:dump -- datasets/baseline/postgres.dump
mise postgres:load -- datasets/baseline/postgres.dump
With file-based tasks, that usually means:
.mise/tasks/postgres/start
.mise/tasks/postgres/check
.mise/tasks/postgres/create
.mise/tasks/postgres/migrate
.mise/tasks/postgres/dump
.mise/tasks/postgres/load
postgres:start must run the service in the foreground and block until it is
interrupted. During lazy development it runs as a managed subprocess, not an
interactive shell.
postgres:check must exit with status 0 only when the service is up and ready
for dependent commands. lazy runs it after starting the service process and
before running create, migrate, or the app.
postgres:create creates the database, bucket, schema, or equivalent local
resource if it is missing. It should be safe to run repeatedly.
postgres:migrate applies pending migrations. It should fail loudly if the
database is reachable but migrations cannot run.
postgres:dump PATH writes service data to the provided path.
postgres:load PATH replaces or imports service data from the provided path.
Document destructive behavior in the task itself.
No normal stop task is required when start runs in the foreground. Add a
postgres:kill task only as an escape hatch for stale local processes.
List services
Declare services explicitly in lazy.toml when the app needs a stable order or
when a service does not have a conventional :start task:
services = ["postgres", "minio"]
When lazy.toml lists services, lazy uses that list. Otherwise, lazy
discovers services from task names that end in :start, such as
.mise/tasks/postgres/start.
What lazy runs
When services are present, lazy starts each service in parallel after the
development proxy and panel are already serving:
mise run postgres:start
Each service's stdout and stderr are recorded in the development panel and stay
attached to the terminal. The panel's Services tab shows service output as a
tree with the App service, managed services, lifecycle scripts, and general
mise tasks below a separator. Output rows include source, run, stdout/stderr,
timestamp, message, and parsed JSON attributes. Repeated readiness checks
appear as separate runs. The bottom status bar shows each service with stopped,
not-ready, or ready indicators. The Services tab can restart, stop, or start
one managed service at a time; restart stops that service process and then runs
the same start, check, create, and migrate flow for that service. If a
check task exists, lazy calls it every 500ms. After five seconds of
failures, lazy reports that the check is still failing and keeps checking
until it succeeds.
After the service check succeeds, lazy runs the preparation tasks that exist,
in this order:
postgres:check
postgres:create
postgres:migrate
Missing optional actions are skipped. create and migrate failures are
reported and do not stop other services from finishing their startup work. The
Go app starts after all services have finished startup preparation.
On Ctrl-C, lazy stops the app first, then stops all managed services. A second
Ctrl-C escalates to killing child processes.
Read Lazy for the full development loop and
Datasets for how dump and load are used.