Dependencies
Define startup order, health conditions, and cross-deployment references so your services and deployments start in the right sequence every time.
Dependencies control the startup order of your services and deployments. When one service needs another to be running first, you declare that relationship in your JuhJuh File and JuhJuh handles the rest: health checks, ordering, parallel execution where possible, and validation that no circular chains exist.
Service dependencies¶
Services declare dependencies in two ways: explicit dependsOn entries and implicit dependencies through links.
Explicit dependencies¶
Add a dependsOn block to any service that needs another service or resource running first:
yaml
services:
web:
type: web
dependsOn:
api:
condition: service_healthy
migrations:
condition: service_completed_successfully
Each entry maps a service or resource name to a condition that must be satisfied before the dependent service starts.
Conditions¶
| Condition | Behavior |
|---|---|
service_started |
Proceed as soon as the dependency's container begins running |
service_healthy |
Wait for the dependency's health check to pass |
service_completed_successfully |
Wait for the dependency to finish with exit code 0 (useful for one-off jobs like migrations) |
service_healthy is the most common choice. Use service_started when you only need the process to be up, and service_completed_successfully for init jobs or migration tasks that must finish before the next service begins.
Link-based dependencies¶
When you link a service to a resource, JuhJuh creates an automatic dependency with service_healthy condition. You do not need to also add an explicit dependsOn for the same resource.
yaml
services:
web:
type: web
links:
- postgres
- redis
In this example, web automatically waits for both postgres and redis to pass their health checks before starting. The linked resources also inject their connection environment variables into the service.
Template inheritance¶
If a service extends a template, it inherits the template's dependencies. A service can override inherited dependencies by declaring its own dependsOn block.
```yaml templates: base-app: dependsOn: postgres: condition: service_healthy
services: web: extends: base-app # Inherits postgres dependency from base-app worker: extends: base-app dependsOn: redis: condition: service_healthy # Overrides with its own dependencies ```
Deployment dependencies¶
Deployments can depend on other deployments. This is how you coordinate multi-VM infrastructure where, for example, a database VM must be healthy before the application VM starts deploying.
```yaml deployments: database: vm: db-server resources: [postgres] expose: - port: 5432 as: postgres
app: vm: app-server services: [web, worker] dependsOn: - deployment: database condition: healthy ```
Deployment conditions¶
| Condition | Behavior |
|---|---|
started |
Proceed once the dependency's deployment begins |
healthy |
Wait for the dependency to reach a healthy state (default) |
completed |
Wait for the dependency to finish entirely |
If you omit condition, it defaults to healthy.
Parallel execution with levels¶
JuhJuh groups deployments into levels based on their dependency graph. Deployments at the same level run in parallel. Deployments at level N only start after all level N-1 deployments succeed.
```yaml deployments: postgres-primary: vm: db-1 resources: [postgres]
redis-cache: vm: cache-1 resources: [redis]
api: vm: app-1 services: [web, worker] dependsOn: - deployment: postgres-primary condition: healthy - deployment: redis-cache condition: healthy
frontend: vm: web-1 services: [static-site] dependsOn: - deployment: api condition: healthy ```
graph TB
subgraph "Level 0 (parallel)"
pg[postgres-primary]
redis[redis-cache]
end
subgraph "Level 1"
api[api]
end
subgraph "Level 2"
fe[frontend]
end
pg --> api
redis --> api
api --> feIn this setup, postgres-primary and redis-cache deploy in parallel (level 0). Once both are healthy, api starts (level 1). After api succeeds, frontend begins (level 2).
Deployment references¶
Once a deployment is running, other deployments can reference its runtime values using ${deployment.<name>.<attribute>} syntax. This is how services on one VM discover services on another.
yaml
envGroups:
app-config:
clear:
POSTGRES_HOST: "${deployment.database.host}"
POSTGRES_PORT: "${deployment.database.port.postgres}"
DATABASE_URL: "postgres://user@${deployment.database.endpoint.postgres}/mydb"
Available attributes¶
| Attribute | Returns | Example value |
|---|---|---|
host |
Private IP of the deployment's VM | 10.0.1.5 |
port.<alias> |
Port number for a named exposed service | 5432 |
endpoint.<alias> |
Combined host:port |
10.0.1.5:5432 |
status |
Current deployment status | HEALTHY |
network |
Network name the deployment belongs to | internal |
The <alias> in port and endpoint matches the as field from the deployment's expose configuration.
Dependency requirement¶
Any deployment you reference with ${deployment.<name>.<attribute>} must also appear in your dependsOn list. JuhJuh enforces this during validation. If you reference a deployment without declaring a dependency on it, the config fails validation with an error identifying the missing dependency.
This rule exists because deployment references resolve at deploy time. Without a dependency, the referenced deployment might not exist yet, producing an unresolvable reference.
Validation¶
JuhJuh validates your dependency graph during both juhjuh validate and juhjuh apply. Three checks run automatically:
1. Target existence¶
Every deployment referenced in a dependsOn entry must be defined in the same config. Referencing a deployment that does not exist produces an error naming the missing target.
2. Circular dependency detection¶
JuhJuh uses topological sorting to detect cycles. If deployment A depends on B, B depends on C, and C depends on A, validation fails and reports which deployments form the cycle.
Error: circular dependency detected among deployments: A, B, C
3. Reference validation¶
Every ${deployment.<name>.<attribute>} reference is traced back to the deployment's dependsOn list. If the referenced deployment is not listed as a dependency, validation fails. This check traverses through services, templates, and environment groups to find all references.
Environment overrides¶
Environments can modify dependencies for specific contexts. A staging environment might remove a dependency that only applies in production, or add a test database dependency that does not exist in the production config.
yaml
environments:
staging:
services:
web:
dependsOn:
staging-db:
condition: service_healthy
When an environment overrides a service's dependsOn, the override replaces the base dependencies entirely for that service in that environment.
Best practices¶
Prefer healthy over started. The started condition only confirms a container is running, not that the service inside it is ready to accept connections. Unless you have a specific reason to use started, default to healthy.
Keep dependency chains short. Deep chains (A depends on B depends on C depends on D depends on E) serialize your deployment and slow down the overall process. Where possible, structure your infrastructure so deployments at the same level can run in parallel.
Use exposed ports for cross-deployment communication. When deployment A needs to reach a service in deployment B, expose the port in B's config and reference it with ${deployment.B.port.alias} or ${deployment.B.endpoint.alias}. This keeps connection details dynamic and avoids hardcoded IPs.
Validate before applying. Run juhjuh validate to catch missing targets, circular dependencies, and unresolved references before starting a deploy. Add --strict to treat warnings as errors.
Related¶
- Deployments for creating, rolling back, and managing deployment lifecycle
- JuhJuh File for the full configuration reference including services, resources, and templates
- VMs for provisioning the compute instances that deployments target
- Vault for managing secrets injected into deployments at deploy time
- Infrastructure Overview for the full platform architecture
- CLI for running validation, apply, and deployment commands