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.
mermaid
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
code
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
hcl
# 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
typescript
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