Patterns
Short, copy-ready FlowLayer config fragments for one situation at a time — a single readiness probe, one dependsOn chain, one oneshot. Adapt names, commands, and ports to your stack.
Pattern guides
Section titled “Pattern guides”These pages cover common orchestration shapes with when-to-use guidance, why they work, and where they break:
TCP readiness
Section titled “TCP readiness”Use a TCP probe when a dependency is ready as soon as it accepts connections. This is the clean default for databases, brokers, and non-HTTP infra.
{ "services": { "postgres": { "cmd": ["docker", "compose", "up", "postgres"], "stopCmd": ["docker", "compose", "down", "postgres"], "port": 5432, "ready": { "type": "tcp", "port": 5432 } } }}HTTP readiness
Section titled “HTTP readiness”Use an HTTP probe when the service exposes a health endpoint and startup is only complete after app boot. This keeps downstream services blocked until the app is actually responding.
{ "services": { "api": { "cmd": ["node", "dist/server.js"], "port": 3001, "ready": { "type": "http", "url": "http://127.0.0.1:3001/health" } } }}dependsOn chain
Section titled “dependsOn chain”Use dependsOn to turn service relationships into deterministic startup waves.
Each dependency must reach its terminal startup state before the next service starts.
{ "services": { "postgres": { "cmd": ["docker", "compose", "up", "postgres"], "ready": { "type": "tcp", "port": 5432 } }, "migrate": { "cmd": ["pnpm", "--dir", "./services/users", "run", "db:migrate"], "kind": "oneshot", "dependsOn": ["postgres"] }, "users": { "cmd": ["pnpm", "--dir", "./services/users", "run", "start:dev"], "port": 3002, "ready": { "type": "http", "url": "http://127.0.0.1:3002/health" }, "dependsOn": ["migrate"] } }}One-shot job
Section titled “One-shot job”Mark setup steps as oneshot when they are expected to finish and unlock downstream services.
This is the right fit for migrations, seed jobs, or code generation.
{ "services": { "seed": { "cmd": ["pnpm", "--dir", "./services/users", "run", "db:seed"], "kind": "oneshot", "dependsOn": ["postgres"] } }}Worker process
Section titled “Worker process”Model queue consumers and background workers as normal long-running services. They stay visible in the same runtime and can depend on infra plus APIs.
{ "services": { "billing-worker": { "cmd": ["pnpm", "--dir", "./services/billing", "run", "start:worker"], "dependsOn": ["postgres", "users-api"], "env": { "QUEUE_NAME": "billing-jobs" } } }}Shell command string vs array
Section titled “Shell command string vs array”Use string form for simple argv splitting and array form whenever quoting or spaces matter.
If you need shell features like &&, invoke a shell explicitly in the array.
{ "services": { "safe-array": { "cmd": ["sh", "-c", "cd backend && pnpm start"] }, "simple-string": { "cmd": "pnpm --dir ./frontend dev" } }}Environment variables
Section titled “Environment variables”Attach service-local environment with env when the process needs explicit runtime configuration.
Those values are merged into the parent environment for both cmd and stopCmd.
{ "services": { "users-api": { "cmd": ["pnpm", "--dir", "./services/users", "run", "start:dev"], "env": { "PORT": "3002", "DATABASE_URL": "postgres://postgres:postgres@127.0.0.1:5432/users" }, "port": 3002, "ready": { "type": "http", "url": "http://127.0.0.1:3002/health" } } }}Monorepo service
Section titled “Monorepo service”Point each service at its package root instead of wrapping the whole repo in one command. This keeps logs, restart controls, and dependency edges readable per service.
{ "services": { "billing": { "cmd": ["pnpm", "--dir", "./services/billing", "run", "start:dev"], "port": 3003, "ready": { "type": "http", "url": "http://127.0.0.1:3003/health" } }, "users": { "cmd": ["pnpm", "--dir", "./services/users", "run", "start:dev"], "port": 3002, "ready": { "type": "http", "url": "http://127.0.0.1:3002/health" } } }}Docker + native mixed stack
Section titled “Docker + native mixed stack”FlowLayer works well when infra comes from Docker while app services run natively. Use explicit stop commands for Docker services and normal process commands for the rest.
{ "services": { "redis": { "cmd": ["docker", "compose", "up", "redis"], "stopCmd": ["docker", "compose", "down", "redis"], "port": 6379, "ready": { "type": "tcp", "port": 6379 } }, "api": { "cmd": ["go", "run", "./cmd/api"], "dependsOn": ["redis"], "port": 8080, "ready": { "type": "http", "url": "http://127.0.0.1:8080/health" } } }}stopCmd for explicit teardown
Section titled “stopCmd for explicit teardown”Use stopCmd when normal signal-based shutdown is not enough to tear down the underlying resource.
This is especially useful for Docker Compose services or custom cleanup steps.
{ "services": { "python-stack": { "cmd": ["docker", "compose", "-f", "./docker/python.compose.yml", "up"], "stopCmd": ["docker", "compose", "-f", "./docker/python.compose.yml", "down"] } }}Watch mode dev service
Section titled “Watch mode dev service”Long-running watch processes fit naturally as daemon services. Keep the command explicit so restarts and logs stay tied to the same package.
{ "services": { "billing": { "cmd": ["pnpm", "--dir", "./services/billing", "run", "start:dev"], "port": 3003, "ready": { "type": "http", "url": "http://127.0.0.1:3003/health" } } }}Delayed dependency stack
Section titled “Delayed dependency stack”When one dependency starts slowly, let the rest of the graph stay blocked instead of racing manually. The readiness gate becomes the single unlock point for the whole downstream chain.
{ "services": { "search": { "cmd": ["docker", "compose", "up", "search"], "port": 9200, "ready": { "type": "tcp", "port": 9200 } }, "indexer": { "cmd": ["pnpm", "--dir", "./services/indexer", "run", "start"], "dependsOn": ["search"] }, "api": { "cmd": ["pnpm", "--dir", "./services/api", "run", "start:dev"], "dependsOn": ["indexer"] } }}Event stack
Section titled “Event stack”Bring up Kafka first, then start producers and consumers that wait on real infra readiness. Models a local event-driven stack with explicit boot ordering.
{ "services": { "kafka": { "cmd": "docker compose up kafka", "stopCmd": "docker compose down kafka", "ready": { "type": "tcp", "port": 9092 } }, "api": { "cmd": "pnpm --dir ./apps/api dev", "port": 3001, "dependsOn": ["kafka"], "env": { "KAFKA_BROKERS": "localhost:9092" } }, "worker": { "cmd": "go run ./cmd/worker", "dependsOn": ["kafka"], "env": { "KAFKA_BROKERS": "localhost:9092" } } }}Ephemeral job
Section titled “Ephemeral job”Run disposable tooling in a container before booting the app. A reproducible one-shot gate keeps local workflows clean and consistent.
{ "services": { "go-test": { "kind": "oneshot", "cmd": [ "docker", "run", "--rm", "-v", "./:/workspace", "-w", "/workspace", "golang:1.24", "go", "test", "./..." ] }, "api": { "cmd": "go run ./cmd/api", "dependsOn": ["go-test"], "port": 8080, "ready": { "type": "http", "url": "http://localhost:8080/healthz" } } }}Python logs (unbuffered)
Section titled “Python logs (unbuffered)”Python buffers stdout by default - output won’t appear in FlowLayer until the buffer flushes.
Pass -u or set PYTHONUNBUFFERED=1 to stream logs in real time.
{ "services": { "worker": { "cmd": "python -u worker.py" } }}Or via environment variable:
{ "services": { "worker": { "cmd": "python worker.py", "env": { "PYTHONUNBUFFERED": "1" } } }}Port wait (external dependency)
Section titled “Port wait (external dependency)”Wait for a dependency that lives outside FlowLayer - a shared database, a remote queue, or a service on another machine. A shell wrapper probes the TCP port in a loop, then hands off.
{ "services": { "api": { // Polls port 5432 until the external DB accepts connections, then starts "cmd": [ "sh", "-c", "until nc -z localhost 5432; do sleep 1; done && node dist/server.js" ], "port": 3001 } }}More advanced examples
Section titled “More advanced examples”Need full walkthroughs, the AI Prompt Builder, or larger reference snippets? Open Examples.