The Problem with Technical Silos

Many engineering teams organize their Terraform code based on technical concerns. You'll find directories like modules/vpc/, modules/ecs/, or modules/rds/. This structure, while seemingly logical at first glance, quickly breaks down when faced with real-world development needs. A new engineer asking where to place a Lambda function for a notification feature highlights this flaw. Is it a reusable Lambda module, or is it intrinsically tied to the order workflow domain? The conventional structure offers no clear answer, leading to arbitrary decisions and future confusion.

This technical-first organization creates a disconnect between infrastructure and the business logic it supports. When a change is needed for a specific feature, engineers have to navigate multiple technical modules, understand their interdependencies, and risk breaking unrelated components. It's like trying to renovate a single room in a house but having to understand the entire plumbing and electrical system of the whole building just to change a light fixture.

Introducing Domain-Driven Infrastructure

Domain-Driven Design (DDD) principles, when applied to infrastructure as code, offer a powerful alternative. Instead of organizing by vpc or ecs, you organize by the business domain. Think of domains as distinct areas of business capability. For an e-commerce platform, domains might include orders, products, users, or notifications. Each domain would have its own dedicated Terraform configuration, encapsulating all the infrastructure resources required for that specific business function.

This approach means that all infrastructure related to the order workflow—the databases, the compute instances, the queues, the networking components, and even specific Lambda functions—resides within the orders/ domain directory. The notifications Lambda, in this case, would live within the notifications/ domain, or potentially within the orders/ domain if it's exclusively tied to order processing.

Illustrative diagram showing a DDD-based Terraform directory structure.

Benefits of Domain-Centric Organization

This shift from technical to domain-centric organization yields significant advantages:

  • Improved Clarity and Ownership: Engineers responsible for a specific business domain can easily locate and manage all related infrastructure. This fosters a sense of ownership and reduces the cognitive load when working on feature development or bug fixes.
  • Reduced Blast Radius: Changes to infrastructure within one domain are less likely to impact other unrelated domains. If the orders/ domain needs a database upgrade, the changes are confined to that directory, minimizing the risk of unintended consequences elsewhere.
  • Enhanced Collaboration: Teams can work more autonomously within their domains. This reduces inter-team dependencies for infrastructure changes, speeding up development cycles.
  • Simplified Onboarding: New engineers can quickly understand the infrastructure landscape by focusing on specific business domains rather than abstract technical components. The question of where to place a resource becomes obvious: it belongs to the domain it serves.
  • Better Alignment with Business: Infrastructure decisions are directly tied to business needs and evolution. As business domains change and grow, the infrastructure organization naturally reflects these shifts.

Structuring Your Domain-Driven Terraform

A typical domain-driven infrastructure repository might look like this:

├── modules/
│   ├── reusable-vpc/
│   ├── reusable-ecs-service/
│   └── ...
├── domains/
│   ├── orders/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── ... (e.g., order_db.tf, order_api.tf)
│   ├── products/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── ... (e.g., product_catalog_db.tf)
│   ├── notifications/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── ... (e.g., notification_lambda.tf, notification_queue.tf)
│   └── users/
│       ├── main.tf
│       ├── variables.tf
│       ├── outputs.tf
│       └── ...
├── main.tf
├── variables.tf
└── outputs.tf

In this structure:

  • The top-level modules/ directory houses generic, reusable Terraform modules that can be consumed by multiple domains. These are your building blocks.
  • The domains/ directory contains subdirectories, each representing a distinct business domain.
  • Within each domain directory, you define the specific infrastructure resources needed for that domain. This could include databases, compute resources, queues, serverless functions, and any other infrastructure components.
  • The top-level main.tf, variables.tf, and outputs.tf files can be used for overarching infrastructure or to orchestrate the deployment of different domains.

Challenges and Considerations

While powerful, domain-driven infrastructure is not without its challenges:

  • Defining Domain Boundaries: Establishing clear and stable domain boundaries can be difficult, especially in complex or rapidly evolving systems. What constitutes a