Layered Stacks Architecture
Overview
Layered stacks separate infrastructure into independent, loosely-coupled layers that can be deployed and managed separately. This reduces blast radius, enables team autonomy, and improves deployment velocity.
graph TB
subgraph "Layer 3: Workloads"
App1[Application 1]
App2[Application 2]
App3[Application 3]
end
subgraph "Layer 2: Platform"
EKS[EKS Cluster]
RDS[(RDS Database)]
Redis[(ElastiCache)]
end
subgraph "Layer 1: Foundation"
VPC[VPC / Networking]
IAM[IAM Roles]
KMS[KMS Keys]
end
App1 --> EKS
App2 --> EKS
App3 --> RDS
EKS --> VPC
RDS --> VPC
EKS --> IAM
Layer Definitions
| Layer | Contents | Change Frequency | Team |
|---|---|---|---|
| Foundation | VPC, networking, IAM baseline, KMS | Rarely | Platform |
| Platform | EKS, RDS, caching, monitoring | Monthly | Platform |
| Workloads | Applications, CI/CD, configs | Daily | App teams |
Best Practices
- Clear boundaries - Each layer has distinct responsibilities
- Output only what's needed - Minimize cross-layer coupling
- Separate state files - Independent deployment
- Use data sources - Reference other layers via outputs
- Version layer interfaces - Treat outputs as APIs
- Different approval processes - Foundation needs more review
Example 1: Terraform - Three-Layer Architecture
Complete three-layer deployment with remote state references.
📁 Location: terraform/examples/layered-stacks/
Directory Structure
terraform/
├── layers/
│ ├── 01-foundation/
│ │ ├── main.tf # VPC, IAM, KMS
│ │ └── outputs.tf # Outputs for other layers
│ ├── 02-platform/
│ │ ├── main.tf # EKS, RDS (references foundation)
│ │ └── outputs.tf
│ └── 03-workloads/
│ └── main.tf # Apps (references platform)
Cross-Layer References
# 02-platform/main.tf
# Reference foundation layer outputs via data source
data "terraform_remote_state" "foundation" {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "foundation/${var.environment}/terraform.tfstate"
region = "us-east-1"
}
}
# Use foundation outputs
module "eks" {
source = "../../modules/eks"
vpc_id = data.terraform_remote_state.foundation.outputs.vpc_id
subnet_ids = data.terraform_remote_state.foundation.outputs.private_subnet_ids
}
Example 2: CDK - Stack Dependencies
CDK stacks with explicit dependencies and cross-stack references.
📁 Location: cdk/examples/layered-stacks/
Stack Structure
const app = new cdk.App();
// Layer 1: Foundation
const foundationStack = new FoundationStack(app, 'Foundation', {
env: prodEnv,
});
// Layer 2: Platform (depends on foundation)
const platformStack = new PlatformStack(app, 'Platform', {
env: prodEnv,
vpc: foundationStack.vpc, // Cross-stack reference
kmsKey: foundationStack.kmsKey,
});
platformStack.addDependency(foundationStack);
// Layer 3: Workloads (depends on platform)
const workloadsStack = new WorkloadsStack(app, 'Workloads', {
env: prodEnv,
cluster: platformStack.cluster, // Cross-stack reference
database: platformStack.database,
});
workloadsStack.addDependency(platformStack);
State Separation
| Layer | State Path | Rationale |
|---|---|---|
| Foundation | foundation/{env}/terraform.tfstate |
Rarely changes |
| Platform | platform/{env}/terraform.tfstate |
Team-owned |
| Workloads | workloads/{app}/{env}/terraform.tfstate |
Per-app isolation |
Validation Checklist
- Layers have clear, documented boundaries
- State files separated per layer
- Cross-layer dependencies use remote state/imports
- Foundation has stricter approval process
- Layer outputs treated as stable APIs
- Changes tested layer-by-layer
Related Skills
- Remote State Boundaries - State isolation
- Modular IaC - Reusable modules in layers
- GitOps Workflow - Layer-specific approvals