This document outlines resilient dependency patterns to prevent Terraform failures when services are enabled/disabled or scaled.
Problem:
resource "kubernetes_stateful_set" "my_service" {
count = var.my_service_enabled ? 1 : 0
depends_on = [
null_resource.some_resource[0], # β BREAKS if count = 0
]
}When null_resource.some_resource has count = 0, there is no [0] instance,
causing Terraform to fail.
Solution:
resource "kubernetes_stateful_set" "my_service" {
count = var.my_service_enabled ? 1 : 0
depends_on = [
null_resource.some_resource, # β
Works with count = 0 or count = 1
]
}Terraform automatically handles resources with count in depends_on:
- If
count = 0: Dependency is ignored (resource doesn't exist) - If
count = 1: Waits for the resource normally - Never use
[0]independs_on- reference the resource directly
Problem:
resource "null_resource" "cleanup" {
depends_on = [
kubernetes_stateful_set.service_a, # Might have count = 0
kubernetes_stateful_set.service_b, # Might have count = 0
kubernetes_stateful_set.service_c, # Might have count = 0
]
}This creates brittle dependencies. If services are enabled/disabled, the dependency tree doesn't adapt.
resource "null_resource" "cleanup" {
# No dependencies - script handles missing services gracefully
provisioner "local-exec" {
# Script checks if services exist before processing
command = "python cleanup.py"
}
}resource "null_resource" "update_dns" {
provisioner "local-exec" {
command = <<-EOT
for i in {1..30}; do
if python update_dns.py; then
exit 0
fi
echo "Waiting for service to be ready..."
sleep 10
done
EOT
}
}Problem:
resource "kubernetes_stateful_set" "service_a" {
count = var.service_a_enabled ? 1 : 0
depends_on = [
kubernetes_stateful_set.service_b[0], # β Breaks if service_b disabled
]
}Solution: Remove [0] and Add Comments
resource "kubernetes_stateful_set" "service_a" {
count = var.service_a_enabled ? 1 : 0
depends_on = [
# Conditional dependency - ignored if service_b_enabled = false
# Note: service_a requires service_b to be enabled for full functionality
kubernetes_stateful_set.service_b, # β
Safe with count = 0
]
}Each service should be independently deployable:
resource "kubernetes_stateful_set" "my_service" {
count = var.my_service_enabled ? 1 : 0
depends_on = [
# Core infrastructure only
null_resource.wait_for_namespace,
kubectl_manifest.wildcard_cert,
]
# No dependencies on other services
}If a service has optional integrations:
locals {
# Dynamic configuration based on what's enabled
my_service_config = merge(
{
# Base configuration
base_setting = "value"
},
var.feature_x_enabled ? {
# Optional feature X config
feature_x_setting = "value"
} : {}
)
}
resource "kubernetes_stateful_set" "my_service" {
count = var.my_service_enabled ? 1 : 0
depends_on = [
# Optional dependencies handled by Terraform's count logic
kubernetes_service.feature_x, # No [0] - works if count = 0
]
}Instead of batch processing all services:
# β Old: Batch processing with static dependencies
resource "null_resource" "update_all_dns" {
depends_on = [
kubernetes_stateful_set.service_a,
kubernetes_stateful_set.service_b,
kubernetes_stateful_set.service_c,
]
provisioner "local-exec" {
command = "python update_dns.py --all"
}
}
# β
New: Per-service processing
locals {
enabled_services = {
for svc in local.all_services :
svc.name => svc
if svc.enabled
}
}
resource "null_resource" "update_dns_per_service" {
for_each = local.enabled_services
# Only runs for enabled services
# No hardcoded dependencies
provisioner "local-exec" {
command = "python update_dns.py --service ${each.key}"
}
}Before adding depends_on, ask:
-
Does the dependency use
countorfor_each?- If yes, do NOT use
[0]or[key]indexing - Reference the resource directly
- If yes, do NOT use
-
Is the dependency always available?
- If no, make sure the script/config handles missing resources
-
Can I use retry logic instead?
- Prefer waiting for actual readiness over static dependencies
-
Is this a cross-service dependency?
- Consider if services should be decoupled
- Document why the dependency is necessary
-
Will this break if services are enabled/disabled?
- Test with different combinations of enabled services
Find all problematic references:
grep -r "\[0\]" *.tf | grep "depends_on" -B3Replace pattern:
# Before
depends_on = [resource.name[0]]
# After
depends_on = [resource.name]- Test with all services enabled
- Test with each service disabled individually
- Test with random combinations
- Check
terraform planfor errors
resource "kubernetes_stateful_set" "open_webui" {
count = var.open_webui_enabled ? 1 : 0
depends_on = [
# No [0] - works even if freeipa_enabled = false
kubernetes_secret.freeipa_ca,
kubernetes_stateful_set.freeipa,
]
}resource "null_resource" "dns_update_per_service" {
for_each = local.enabled_dns_services
# Retry loop waits for actual VPN IP
provisioner "local-exec" {
command = <<-EOT
for i in {1..30}; do
if python update_dns.py --service ${each.key}; then
exit 0
fi
sleep 10
done
EOT
}
}resource "null_resource" "post_deployment_cleanup" {
count = var.headscale_enabled ? 1 : 0
# No StatefulSet dependencies - script handles missing services
provisioner "local-exec" {
command = "python cleanup.py"
}
}resource "null_resource" "something" {
depends_on = [
kubernetes_stateful_set.service_a[0],
kubernetes_stateful_set.service_b[0],
kubernetes_stateful_set.service_c[0],
kubernetes_stateful_set.service_d[0],
]
}depends_on = [null_resource.something[0]]# Service A depends on B
# Service B depends on A
# Terraform will detect and fail