Service dependencies
Declare that one service needs another. The reconciler waits for dependencies to be ready before creating instances.
Services rarely run alone. An API needs a database. A worker needs a queue. Rune lets you express that as data, not bash.
Declare a dependency
A dependency is a reference to a service, secret, or configmap — written either as a structured entry or as a string shorthand:
service:
name: api
image: ghcr.io/example/api:1.0.0
scale: 2
dependencies:
# Structured form
- service: postgres
- service: auth
namespace: shared
- secret: db-credentials
- configmap: app-settings
# String shorthand — equivalent to the structured form
- service:redis
- secret:api-keys
- configmap:feature-flags
| Field | Notes |
|---|---|
service | Name of a service this one depends on. |
secret | Name of a secret that must exist before rollout. |
configmap | Name of a configmap that must exist before rollout. |
namespace | Optional. Defaults to the dependent's namespace. |
Each entry must specify exactly one of service, secret, or configmap — rune cast rejects entries that specify none.
String shorthand
The shorthand forms are:
service:<name>,secret:<name>,configmap:<name>— a typed reference in the dependent's namespace.service:<name>.<namespace>.rune(and likewise forsecret:/configmap:) — a typed reference in another namespace.- A bare name like
postgres— treated as a service dependency in the dependent's namespace. - A dotted name like
postgres.prod— a service dependency in theprodnamespace.
When is a dependency ready?
The readiness condition is fixed — it is not configurable per dependency:
- Service without a readiness probe: ready when at least one instance is
Running. - Service with a readiness probe (
health.readinessin the dependency's own spec): ready when at least one instance isRunningand its readiness probe is passing. - Secret or configmap: ready when the resource exists. Individual keys are not checked.
In other words: to wait for a dependency to be healthy rather than merely running, give that dependency a readiness probe. See Health checks.
What it does
On rollout (cast or scale up), the reconciler:
- Resolves each dependency reference (applying namespace defaults).
- Checks readiness of every dependency, using the conditions above.
- Creates the dependent's instances only after all dependencies are ready.
While any dependency is unready or missing, the dependent stays pending and no instances are created. There is no timeout: the reconciler re-checks on every reconcile cycle (roughly every 30 seconds) indefinitely, and logs that instance creation is being delayed. A missing dependency never fails the rollout — it just keeps it waiting.
If a dependency cycle exists, rune cast rejects the spec.
Dependencies gate instance creation only. Once the dependent's instances are running, the dependency is not re-checked — if it later becomes unhealthy or is deleted, the dependent keeps running (see Updates).
Inspecting
rune deps graph api
Renders the dependency graph for api, including transitive deps.
rune deps check api
Reports current readiness status of each dependency.
rune deps validate api
Validates the dependency definitions in the spec without applying.
rune deps dependents postgres
Lists services that depend on postgres. Useful before deleting a database.
Updates
When a dependency restarts, dependents are not automatically restarted. Most services tolerate transient dependency blips and reconnect on their own. If yours doesn't, you have two options:
- Fix the service to reconnect (preferred).
- Cascade restart manually:
rune restart apiafter arune restart postgres.
Anti-patterns
- Deep dependency chains. A → B → C → D → E means a single slow service stalls the whole stack. Try to keep depth ≤ 2.
- Circular dependencies. Rejected by the linter. If you think you need one, you don't — invert the dependency or split a service.
- Using deps for ordering only. If service B doesn't actually need A to be running, leave the dependency off. Rune will start them in parallel — usually faster.