It's 2AM. You're staring at a failed deployment pipeline, trying to figure out why your EKS cluster can't find the right subnets. You've checked the variables, verified the outputs, and triple-checked your depends_on statements. Everything looks correct, yet it still fails.

This scenario plays out daily across organizations that have adopted Terraform. While modules promised composable, reusable infrastructure, the reality has become a complex web of string-matching, implicit dependencies, and tribal knowledge.

How much of your team's time is spent debugging module connections rather than delivering value?

The Hidden Tax of Module Stitching

Every time a team provisions infrastructure for a new service or application, they pay an invisible tax in cognitive overhead:

Hunt & Wire

For each input a module needs, someone must make critical decisions: Is this value a hard-coded constant? A data lookup? An output from another module? The answer differs for every project and environment, so this decision tree must be rebuilt from scratch each time.

A seemingly simple task like connecting a Kubernetes cluster to a VPC becomes a detective exercise in matching string outputs to string inputs, with no verification until runtime, long after the PR is merged.

Re-implement Environment Rules

Resource naming, tagging strategies, IAM permissions, and security controls must be consistently applied across environments. Yet traditional modules handle environments inconsistently—sometimes a module accepts an environment parameter, sometimes it doesn't, and nothing enforces correct usage.

The burden of "getting production right" sits squarely on whoever writes the module composition code, with no systematic guardrails.

Maintain a Second Codebase

The glue code that ties modules together inevitably balloons into a project-sized Terraform configuration:

# Just a small sample of typical glue code
locals {
vpc_name = "${var.prefix}-${var.environment}-vpc"
private_subnets = module.vpc.private_subnet_ids
cluster_name = "${local.vpc_name}-eks"
# ... dozens more variable mappings
}


This "composition layer" often contains more logic and complexity than the underlying modules themselves.

The result is a silent cost curve: each new service adds marginally less business value but exactly the same cognitive overhead. At scale, that overhead caps delivery speed, security posture, and team morale.

Four Pillars of Infrastructure Design by Contract

Software engineers have long used "Design by Contract" to create reliable, modular systems. This approach establishes formal agreements between components about what each provides and requires. Applying these same principles to infrastructure transforms how components interact through four key pillars:

1. Contract-Led Composition: Explicit Interfaces Between Components

Traditional Reality: Infrastructure integration is a string-matching game of chance. You pray that the VPC module's outputs match what the EKS module expects, but there's no guarantee until runtime:

# Traditional Terraform Approach
# VPC module outputs
output "vpc_id" { value = aws_vpc.this.id }
output "subnet_ids" { value = aws_subnet.private.*.id }

# EKS module variables
variable "vpc_id" { type = string }
variable "subnet_ids" { type = list(string) }

# Manual wiring in root module
module "eks" {
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.subnet_ids
# No validation that these are the correct subnets
# No guarantee vpc_id is from a compatible VPC
}


With dozens of modules interacting, teams waste significant time debugging issues when these string interfaces don't align perfectly.

Contract-Based Transformation: Modern approaches transform infrastructure composition through explicit type contracts:

# VPC module declares what it produces
outputs:
default:
type: "@output/aws-vpc"

# Kubernetes module declares what it requires
inputs:
network:
type: "@output/aws-vpc"


This implements true Design by Contract, where each component makes explicit promises about what it provides and requires. The orchestrator enforces that producers and consumers speak the same language, catching mismatches immediately rather than during production deployment.

Just as software contracts guarantee function behavior, these infrastructure contracts guarantee correct composition and integration.

2. Environment-Aware by Design: Contracts Across Environments

Traditional Reality: Environment handling is bolted on as an afterthought. Teams create convoluted folder structures, copy-paste config files, or resort to complex variable overrides that inevitably drift out of sync.

Contract-Based Transformation: Environment becomes a first-class dimension in each contract, with explicit declarations of what can vary between environments and what must remain consistent:

vpc_cidr:
default: "10.0.0.0/16"
x-ui-overrides-only: true # Can change per environment

enable_dns_hostnames:
default: true
x-ui-override-disable: true # Cannot change per environment


This extends the contract beyond just interfaces to include environment-specific guarantees. Module authors don't just hope their code handles environments correctly—they design explicit contracts for multi-environment deployment with orchestrator-enforced invariants.

3. Progressive Rollouts for Infrastructure: Versioned Contracts

Traditional Reality: Infrastructure updates are all-or-nothing affairs. "Let's merge this change to all environments and hope nothing breaks" is the unstated strategy. Version control exists primarily in git, with no structured way to progressively roll out changes across environments.

Contract-Based Transformation: Users control which contract version is deployed to each resource in each environment:

# Deploy version 2.0 to dev, 1.5 to staging, 1.0 to prod
infrastructure:
network:
environments:
dev:
version: "2.0" # Testing new features
staging:
version: "1.5" # Partial upgrade
prod:
version: "1.0" # Stable version


This brings software-style contract versioning to infrastructure. Security patches can be rapidly deployed to lower environments, validated, and then incrementally rolled out to production. The versioning system creates a safety net that traditional Terraform lacks, allowing teams to move quickly with the ability to roll back precisely if a contract is broken.

4. Developer Experience That Preserves Governance: Preconditions and Postconditions

Traditional Reality: Infrastructure teams face an impossible choice: lock everything down and become a bottleneck, or expose raw Terraform and risk security or compliance issues. The common "solution" is complex approval workflows that frustrate everyone and slow down delivery.

Contract-Based Transformation: Schema-driven interfaces implement preconditions and postconditions that adapt to context:

# Schema-driven interfaces enforce conditions
database:
engine:
type: string
enum: ["postgres", "mysql"]
performance:
type: string
enum: ["dev", "standard", "premium"]
x-ui-visible-if:
environment: ["staging", "prod"] # Hidden in dev


Just as Design by Contract uses preconditions and postconditions to ensure correct function behavior, this approach uses them to ensure correct infrastructure behavior. The result is interfaces that adapt to context, showing different options based on environment, user role, or related settings, while maintaining critical governance boundaries.

From Configuration to Contract-Driven Infrastructure

The shift from traditional Terraform modules to contract-driven modules isn't just a technical improvement—it's a fundamental change in how we think about infrastructure. By applying Design by Contract principles to infrastructure, we create:

  • Explicit guarantees about how components interact
  • Verifiable constraints on what can change between environments
  • Clear boundaries between different teams' responsibilities
  • Consistent interfaces that scale across an organization

Ask yourself:

  • How much time does your team spend troubleshooting module integration issues?
  • Do you have confidence that your environments differ only in the ways you intend?
  • Can you safely roll out infrastructure changes gradually, or are you forced into risky all-or-nothing deployments?

This contract-driven approach creates a clearer separation of concerns:

  • Platform engineers focus on building robust modules with explicit contracts
  • Developers express their infrastructure needs through verified interfaces
  • The orchestrator handles the complex validation and enforcement

The future of infrastructure isn't about writing more configuration—it's about establishing clear, enforceable contracts between components and letting orchestrators ensure those contracts are honored.

It's important to understand that contract-driven infrastructure is not a replacement for Terraform, but rather a framework built on top of it—similar to how Spring Boot relates to Java. Just as Spring Boot provides structure, convention, and higher-level abstractions over Java while leveraging its core capabilities, contract-driven approaches like Facets provide organization, guarantees, and higher-level abstractions over Terraform while maintaining all its underlying power and flexibility.

Facets: The Contract-Driven Orchestrator

Facets is an orchestrator built from the ground up to adhere to these principles. We aimed to unlock AI-powered infrastructure and truly scalable practices by "shifting left" the validation, composition, and governance that traditionally happens too late in the deployment cycle.

With Facets:

  • Contracts become the foundation of your infrastructure strategy
  • AI assistance can leverage these contracts to generate and validate infrastructure designs
  • Teams can collaborate with clear boundaries and responsibilities
  • Organizations can scale infrastructure practices across hundreds of applications

The result is dramatically reduced cognitive overhead, faster deployments, and infrastructure that genuinely serves the business rather than becoming a bottleneck. See our article comparing Facets with other terraform platforms

Contact us if you relate to the concepts above and want to envision what life looks like after this innovation.