Claude
Skills
Sign in
Back

twelve-factor

Included with Lifetime
$97 forever

Guide for 12-Factor cloud-native applications. Use when designing microservices, configuring containers, deploying to Kubernetes, or following cloud-native patterns.

Cloud & DevOps

What this skill does


# 12-Factor App Methodology

Guide for building scalable, maintainable, and portable cloud-native applications following the 12-Factor App principles and modern extensions.

## When to Activate

Use this skill when:
- Designing or refactoring cloud-native applications
- Building applications for Kubernetes deployment
- Setting up CI/CD pipelines
- Implementing microservices architecture
- Migrating applications to containers
- Reviewing architecture for cloud readiness
- Troubleshooting deployment or scaling issues
- Working with environment configuration

## The 12 Factors

### I. Codebase

**One codebase tracked in revision control, many deploys**

```
myapp-repo/
├── src/
├── config/
├── deploy/
│   ├── staging/
│   ├── production/
│   └── development/
└── Dockerfile
```

**Key principles:**
- Single Git repository for the application
- Multiple environments deploy from same codebase
- Environment-specific config separate from code
- Use GitOps (ArgoCD, Flux) for deployment automation

**Anti-patterns:**
- ❌ Multiple repositories for the same application
- ❌ Different codebases for different environments
- ❌ Copying code between repositories

### II. Dependencies

**Explicitly declare and isolate dependencies**

Declare all dependencies explicitly using package managers:

```dockerfile
# Multi-stage build for dependency isolation
FROM node:18-alpine AS dependencies
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=dependencies /app/node_modules ./node_modules
COPY . .
CMD ["node", "index.js"]
```

**Language-specific examples:**
- Node.js: `package.json` and `package-lock.json`
- Python: `requirements.txt` or `Pipfile.lock`
- Java: `pom.xml` or `build.gradle`
- Go: `go.mod` and `go.sum`
- Elixir: `mix.exs` and `mix.lock`
- Rust: `Cargo.toml` and `Cargo.lock`

**Key principles:**
- Never rely on system-wide packages
- Use lock files for reproducible builds
- Vendor dependencies when possible
- Multi-stage builds for smaller images

### III. Config

**Store config in the environment**

All configuration should come from environment variables:

```elixir
# Elixir - config/runtime.exs
import Config

config :my_app, MyApp.Repo,
  database: System.get_env("DATABASE_NAME") || "my_app_dev",
  username: System.get_env("DATABASE_USER") || "postgres",
  password: System.fetch_env!("DATABASE_PASSWORD"),
  hostname: System.get_env("DATABASE_HOST") || "localhost",
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
```

```javascript
// Node.js
const config = {
  database: {
    url: process.env.DATABASE_URL,
    pool: {
      min: parseInt(process.env.DB_POOL_MIN || '2'),
      max: parseInt(process.env.DB_POOL_MAX || '10')
    }
  },
  cache: {
    ttl: parseInt(process.env.CACHE_TTL || '3600')
  }
};
```

**Kubernetes ConfigMaps:**

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: "postgres-service"
  CACHE_TTL: "3600"
  LOG_LEVEL: "info"
```

**Kubernetes Secrets:**

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  DATABASE_PASSWORD: <base64-encoded>
  JWT_SECRET: <base64-encoded>
  API_KEY: <base64-encoded>
```

**Anti-patterns:**
- ❌ Hardcoded configuration values
- ❌ Configuration files committed to version control
- ❌ Different code paths for different environments

### IV. Backing Services

**Treat backing services as attached resources**

Connect to all backing services (databases, queues, caches, APIs) via URLs in environment variables:

```javascript
// Treat all backing services uniformly
const services = {
  database: createConnection(process.env.DATABASE_URL),
  cache: createRedisClient(process.env.REDIS_URL),
  queue: createQueueClient(process.env.RABBITMQ_URL),
  storage: createS3Client(process.env.S3_ENDPOINT)
};
```

**Kubernetes Service Discovery:**

```yaml
apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  selector:
    app: redis
  ports:
  - port: 6379
    targetPort: 6379
```

**Key principles:**
- No distinction between local and third-party services
- Swappable via configuration change only
- No code changes to swap backing services
- Connection via URL in environment

### V. Build, Release, Run

**Strictly separate build and run stages**

Three distinct stages:
1. **Build**: Convert code to executable bundle
2. **Release**: Combine build with config
3. **Run**: Execute in target environment

```yaml
# GitHub Actions CI/CD Pipeline
name: Build and Deploy
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build Docker image
        run: docker build -t myapp:${{ github.sha }} .
      - name: Push to registry
        run: docker push myapp:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Kubernetes
        run: kubectl set image deployment/myapp myapp=myapp:${{ github.sha }}
```

**Key principles:**
- Immutable releases (never modify, only deploy new)
- Unique release identifiers (git SHA, semver)
- Rollback by redeploying previous release
- Separate build artifacts from runtime config

### VI. Processes

**Execute the app as one or more stateless processes**

Application processes should be stateless and share-nothing. Store persistent state in backing services.

```javascript
// ❌ Bad: In-memory session store
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false
  // Uses memory store by default
}));

// ✓ Good: Store session in Redis
app.use(session({
  store: new RedisStore({
    client: redisClient,
    prefix: 'sess:'
  }),
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false
}));
```

**Kubernetes Deployment:**

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3  # Can scale horizontally
  selector:
    matchLabels:
      app: myapp
  template:
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
```

**Key principles:**
- Stateless processes enable horizontal scaling
- No sticky sessions
- No local filesystem for persistent data
- Shared state goes in databases, caches, or queues

### VII. Port Binding

**Export services via port binding**

Applications are self-contained and bind to a port:

```javascript
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;

app.listen(port, '0.0.0.0', () => {
  console.log(`Server running on port ${port}`);
});
```

```elixir
# Phoenix endpoint config
config :my_app, MyAppWeb.Endpoint,
  http: [port: String.to_integer(System.get_env("PORT") || "4000")],
  server: true
```

**Kubernetes Service:**

```yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 3000
  type: LoadBalancer
```

**Key principles:**
- Bind to `0.0.0.0`, not `localhost`
- Port number from environment variable
- No reliance on runtime injection (e.g., Apache, Nginx)
- HTTP server library embedded in app

### VIII. Concurrency

**Scale out via the process model**

Scale by adding more processes (horizontal scaling), not by making processes larger (vertical scaling):

```yaml
# Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
```

**Process types (Procfile concept):**

```
web: node server.js
worker: node worker.js
scheduler: node scheduler.js
```

**Key principles:**
- Different process types for differen

Related in Cloud & DevOps