Local development
pier dev runs the current environment on your machine with docker — the same variables, links and ports the platform injects
pier devBuilds the environment's apps (the same Dockerfile or detected build the platform uses),
starts them with docker compose alongside a Postgres per declared instance and a MinIO for
declared buckets, injects the same environment variables and links the platform would, and
prints a stable localhost port per app.
pier dev up --dry-run! running against env vars and secrets from "prod"
1 secret(s) would be revealed from server
Plan
pg-main: postgres:17.9 → localhost:7100
minio: localhost:7101 — buckets: uploads
app-api: pier-dev/acme-1ab0-prod-api:latest → localhost:7103 (build /Users/ian/piercomputing/pier/examples/docs-acme/api)
VAR SOURCE DETAIL
API_KEY reveal app
DATABASE_URL link postgres.main.url
LOG_LEVEL config app
PORT auto
PIER_DB_MAIN_URL auto
PIER_S3_ENDPOINT auto
PIER_S3_ACCESS_KEY auto
PIER_S3_SECRET_KEY auto
PIER_BUCKET_UPLOADS auto
www: site — not emulated
Generated compose (/Users/ian/Library/Application Support/pier/dev/ws_01ky4wcrsne6s8gtm3jdpaj2tw/proj_01m19h7s7tew3t0505y6q9077c/prod/compose.yaml)
name: pier-dev-acme-1ab0-prod
services:
app-api:
image: pier-dev/acme-1ab0-prod-api:latest
What matches the platform
| Surface | Platform | pier dev |
|---|---|---|
PORT | the target's port (default 8080) | the same; published on a stable host port from 7100 |
| variables | environment < app < target, secrets from the vault, links resolved at start | the same merge, computed locally; links point at the local stand-ins |
DATABASE_URL and the other link fields | the instance's public DSN | postgresql://app:…@db-main:5432/app?sslmode=disable |
| Postgres | the declared major, pinned patch | the official image of the same major; data in a named docker volume |
| buckets | S3 endpoint and keys per project | a local MinIO with one bucket per declaration |
| volumes | block storage at mount_path | a named docker volume at mount_path |
| readiness | TCP on PORT | the same wait before "ready" |
Known differences: sslmode=disable locally, no replicas or limits, and compose gives apps
each other's names as DNS (app-<name>), which the platform does not.
Secrets
Values for secret: true variables are resolved in order: from .pier/dev.env in the
project (local substitutes; gitignored), then from the platform (--pull-secrets, which is
always confirmed on a protected: true environment). If a required value is still missing
the run fails and lists the keys; --allow-missing runs without them. Values are written
to a generated compose file under the user configuration directory and removed by
pier dev reset.
Commands
| Command | Does |
|---|---|
pier dev / pier dev up | build what changed, start, wait for ready; --watch rebuilds on change; --only api a subset |
pier dev logs [api] | follow the local stack's logs |
pier dev status | this project's local stacks, per environment |
pier dev stop | stop; data kept |
pier dev reset [--all] | remove containers, volumes and generated files |
Docker is the only source of truth for what is running; nothing is cached. Switching
environments with pier use staging and running pier dev again starts staging's stack
and stops prod's unless --keep-others.
See also
pier dev · Environment variables ·
Use Postgres from your laptop