14 KiB
Common Container Patterns
This document provides reusable architecture patterns for C4 Model Level 2 (Container) analysis with detailed examples.
Pattern 1: Simple SPA + API + Database
Scenario: Basic web application with frontend, backend, and database
Containers identified:
-
Frontend SPA Container
- Type:
spa - Technology: React 18 + TypeScript
- Runtime: Browser
- Communicates with API via HTTP REST
- Type:
-
Backend API Container
- Type:
api - Technology: Express.js + Node.js 18
- Runtime: Server (Node.js)
- Communicates with database via PostgreSQL protocol
- Type:
-
PostgreSQL Database Container
- Type:
database - Technology: PostgreSQL 15
- Runtime: Server (Docker)
- Stores application data
- Type:
Architecture:
┌──────────────────┐
│ Browser │
│ ┌────────────┐ │
│ │ React SPA │ │
│ └──────┬─────┘ │
└─────────┼────────┘
│ HTTP REST
▼
┌─────────────────┐
│ Server │
│ ┌────────────┐ │
│ │ Express API│ │
│ └──────┬─────┘ │
└─────────┼───────┘
│ SQL
▼
┌─────────────────┐
│ ┌────────────┐ │
│ │PostgreSQL │ │
│ │ Database │ │
│ └────────────┘ │
└─────────────────┘
Detection Commands:
# Detect pattern
find . -name "package.json" | grep -E "(frontend|client|web)"
find . -name "package.json" | grep -E "(backend|server|api)"
find . -name "docker-compose.yml" | xargs grep postgres
# Verify frontend
cat frontend/package.json | jq '.dependencies | keys | .[]' | grep -E "react|vue|angular"
# Verify backend
cat backend/package.json | jq '.dependencies | keys | .[]' | grep -E "express|fastify|nestjs"
# Verify database
docker-compose config | grep postgres
Pattern 2: Microservices with API Gateway
Scenario: Multiple microservices behind API gateway
Containers identified:
-
API Gateway Container
- Type:
web-server - Technology: Nginx or Kong
- Runtime: Server
- Routes requests to services
- Type:
-
Auth Service Container
- Type:
api - Technology: NestJS
- Runtime: Server (Node.js in Docker)
- Handles authentication
- Type:
-
User Service Container
- Type:
api - Technology: Spring Boot
- Runtime: Server (JVM in Docker)
- Manages user data
- Type:
-
Order Service Container
- Type:
api - Technology: FastAPI
- Runtime: Server (Python in Docker)
- Processes orders
- Type:
-
Message Broker Container
- Type:
message-broker - Technology: RabbitMQ
- Runtime: Server (Docker)
- Event bus
- Type:
-
Per-Service Databases
- Each service has its own database container
Architecture:
┌──────────────┐
│ API Gateway │
└──────┬───────┘
│ HTTP
┌───┴────┬────────┐
│ │ │
▼ ▼ ▼
┌─────┐ ┌──────┐ ┌───────┐
│Auth │ │User │ │Order │
│Svc │ │Svc │ │Svc │
└──┬──┘ └──┬───┘ └───┬───┘
│ │ │
└───────┴────┬────┘
│
▼
┌─────────┐
│RabbitMQ │
└─────────┘
Detection Commands:
# Detect microservices pattern
find . -type d -name "*-service" -o -name "*-api"
ls services/ | wc -l # Count service directories
# Find API gateway
grep -r "nginx\|kong\|traefik" docker-compose.yml k8s/
# Find message broker
grep -r "rabbitmq\|kafka" docker-compose.yml k8s/
# Count services
find services/ -name "package.json" -o -name "pom.xml" -o -name "requirements.txt" | wc -l
Pattern 3: Serverless Architecture
Scenario: Serverless functions with managed services
Containers identified:
-
Frontend SPA Container
- Type:
spa - Deployed to: CloudFront + S3
- Technology: React
- Runtime: Browser
- Type:
-
API Lambda Functions Container(s)
- Type:
api - Multiple functions or single function
- Technology: Node.js Lambda handlers
- Runtime: AWS Lambda (serverless)
- Type:
-
DynamoDB Database
- Type:
database - Technology: AWS DynamoDB
- Runtime: AWS managed
- Fully serverless
- Type:
-
S3 Storage Container
- Type:
file-storage - Technology: AWS S3
- Runtime: AWS managed
- Stores uploaded files
- Type:
Architecture:
┌─────────────┐
│ CloudFront │
│ + S3 │
│ (SPA) │
└──────┬──────┘
│ HTTP
▼
┌─────────────┐
│ API Gateway │
└──────┬──────┘
│
▼
┌─────────────┐ ┌──────────┐
│ Lambda │──────▶ DynamoDB │
│ Functions │ └──────────┘
└─────────────┘
│
▼
┌─────────────┐
│ S3 Bucket │
└─────────────┘
Detection Commands:
# Detect serverless pattern
find . -name "serverless.yml" -o -name "serverless.yaml"
find . -name "vercel.json" -o -name "netlify.toml"
find . -name "template.yaml" | xargs grep "AWS::Serverless"
# Find Lambda functions
grep -r "AWS::Serverless::Function\|handler:" serverless.yml
# Find DynamoDB tables
grep -r "DynamoDB\|AWS::DynamoDB" template.yaml
# Find S3 usage
grep -r "S3_BUCKET\|aws-sdk.*s3" .
Pattern 4: Full-Stack Framework (Next.js/Nuxt)
Scenario: Single full-stack application with SSR
Containers identified:
-
Next.js Application Container
- Type:
app-server(full-stack) - Technology: Next.js 13
- Runtime: Server (Node.js)
- Serves both frontend and API routes
- Note: This is ONE container, not separate frontend/backend
- Type:
-
Database Container
- Type:
database - Technology: PostgreSQL
- Runtime: Server (Docker)
- Type:
-
Redis Cache Container
- Type:
cache - Technology: Redis
- Runtime: Server (Docker)
- Caches SSR pages
- Type:
Architecture:
┌────────────────────┐
│ Next.js App │
│ ┌──────────────┐ │
│ │ SSR + API │ │
│ │ Routes │ │
│ └──────┬───────┘ │
└─────────┼──────────┘
┌─┴──┐
│ │
┌───▼──┐ └──▼─────┐
│ DB │ │ Redis │
└──────┘ └───────┘
Detection Commands:
# Detect Next.js/Nuxt pattern
grep -r "\"next\":\|\"nuxt\":" package.json
# Check for API routes
find . -type d -name "api" -path "*/pages/api" -o -path "*/app/api"
# Check for SSR
grep -r "getServerSideProps\|getStaticProps" pages/ app/
# Verify single application
[ $(find . -name "package.json" -not -path "*/node_modules/*" | wc -l) -eq 1 ] && echo "Single app"
Pattern 5: Mobile App + Backend
Scenario: Mobile application with supporting backend
Containers identified:
-
Mobile Application Container
- Type:
mobile-app - Technology: React Native
- Runtime: iOS/Android
- Communicates with API
- Type:
-
Backend API Container
- Type:
api - Technology: Django REST Framework
- Runtime: Server (Python)
- Provides mobile API
- Type:
-
PostgreSQL Database Container
- Type:
database - Technology: PostgreSQL
- Runtime: Server
- Type:
-
Redis Cache Container
- Type:
cache - Technology: Redis
- Runtime: Server
- API response caching
- Type:
-
Push Notification Service Container
- Type:
worker - Technology: Custom Python service
- Runtime: Server
- Sends push notifications via FCM/APNS
- Type:
Architecture:
┌─────────────────┐
│ Mobile Device │
│ ┌─────────────┐ │
│ │React Native │ │
│ │ App │ │
│ └──────┬──────┘ │
└────────┼────────┘
│ HTTPS
▼
┌────────────────┐ ┌────────┐
│ Django API │──────▶ Postgres│
└────────┬───────┘ └────────┘
│
┌────┴────┐
▼ ▼
┌──────┐ ┌────────┐
│Redis │ │Push │
│Cache │ │Service │
└──────┘ └────────┘
Detection Commands:
# Detect mobile app
find . -name "package.json" | xargs grep "react-native\|@ionic\|flutter"
find . -name "Podfile" -o -name "build.gradle"
# Detect backend API
grep -r "djangorestframework\|flask\|fastapi" requirements.txt
# Find push notification service
grep -r "fcm\|apns\|firebase-admin" . | grep -v node_modules
Pattern 6: Event-Driven with Workers
Scenario: Async processing with message queue and workers
Containers identified:
-
Web Application Container
- Type:
spa - Technology: Vue 3
- Runtime: Browser
- Type:
-
Backend API Container
- Type:
api - Technology: FastAPI
- Runtime: Server (Python)
- Publishes events to queue
- Type:
-
Message Queue Container
- Type:
message-broker - Technology: Kafka
- Runtime: Server (Docker)
- Event streaming
- Type:
-
Email Worker Container
- Type:
worker - Technology: Celery
- Runtime: Server (Python)
- Consumes email events
- Type:
-
Report Worker Container
- Type:
worker - Technology: Celery
- Runtime: Server (Python)
- Generates reports
- Type:
-
Database Container
- Type:
database - Technology: PostgreSQL
- Runtime: Server
- Type:
Architecture:
┌──────┐ ┌─────┐
│ Vue │───▶│ API │
│ SPA │ └──┬──┘
└──────┘ │
│ publish
▼
┌──────────┐
│ Kafka │
│ Queue │
└─────┬────┘
┌───┴───┐
subscribe subscribe
│ │
┌────▼──┐ ┌─▼──────┐
│Email │ │Report │
│Worker │ │Worker │
└───────┘ └────────┘
Detection Commands:
# Detect event-driven pattern
grep -r "celery\|sidekiq\|bull\|bee-queue" requirements.txt package.json Gemfile
# Find message brokers
grep -r "kafka\|rabbitmq\|redis.*pub.*sub" docker-compose.yml
# Find worker definitions
find . -name "*worker*.py" -o -name "*job*.py"
grep -r "celery.*worker\|worker.*start" .
Pattern Selection Guide
When to Use Each Pattern
| Pattern | Best For | Complexity | Scalability |
|---|---|---|---|
| Pattern 1: SPA + API + DB | Simple web apps, MVPs | Low | Medium |
| Pattern 2: Microservices | Large systems, independent teams | High | Very High |
| Pattern 3: Serverless | Variable load, cost optimization | Medium | Auto-scale |
| Pattern 4: Full-Stack Framework | Rapid development, SSR needs | Low-Medium | Medium |
| Pattern 5: Mobile + Backend | Mobile-first apps | Medium | High |
| Pattern 6: Event-Driven | Async processing, decoupling | Medium-High | Very High |
Mixing Patterns
Real-world systems often combine patterns:
Example: E-commerce Platform
- Pattern 1: Customer web portal (SPA + API + DB)
- Pattern 5: Mobile shopping app (Mobile + Backend)
- Pattern 6: Order processing (Event-driven workers)
- Pattern 3: Static assets (Serverless CDN)
Detection Best Practices
- Start with docker-compose.yml or K8s manifests - Shows all containers
- Check package manifests - package.json, requirements.txt, pom.xml
- Look for framework indicators - next.config.js, serverless.yml
- Examine folder structure - services/, apps/, packages/
- Review deployment configs - Dockerfile, K8s deployments
- Check environment variables - .env files reveal connections
Common Variations
Pattern 1 Variations
- Add Redis cache → Pattern 1 + Cache
- Add Nginx proxy → Pattern 1 + Reverse Proxy
- Add worker → Pattern 1 + Background Jobs
Pattern 2 Variations
- Per-service databases → Database-per-Service
- Shared database → Shared-Database (anti-pattern)
- Service mesh → Add Istio/Linkerd sidecar containers
Pattern 3 Variations
- Vercel deployment → Vercel Edge Functions
- Netlify deployment → Netlify Functions
- Azure → Azure Functions + Cosmos DB
Pattern 4 Variations
- Monorepo → Multiple Next.js apps
- Standalone API → Next.js + Separate API
- Edge runtime → Vercel Edge Runtime
Anti-Patterns to Avoid
-
Shared Database Across Services
- Violates microservices principles
- Creates tight coupling
- Makes each service dependent
-
Monolith in Disguise
- Multiple "microservices" that all call each other synchronously
- Should be one container
-
Over-Granular Containers
- Breaking down below deployment boundary
- Example: Separating utility functions into "containers"
-
Missing Infrastructure Containers
- Forgetting databases, caches, message brokers
- Only documenting application containers
-
Generic Container Types
- "Node.js App" instead of "Express API Server"
- "Python Service" instead of "FastAPI API + Celery Worker"
Next Steps
After identifying the pattern:
- Document each container using container-types-reference.md
- Map communication using communication-patterns.md
- Capture technology details using technology-detection-patterns.md
- Add observations per observation-categories-c2.md
- Validate using melly-validation scripts