Agent skill
twelve-factor-app-modernization
Systematic process for analyzing and modernizing legacy applications to comply with the 12-Factor App methodology. Covers code analysis, configuration externalization, dependency management, and container/Kubernetes best practices.
Install this agent skill to your Project
npx add-skill https://github.com/stakpak/community-paks/tree/main/Twelve-factor-app-modernization
Metadata
Additional technical details for this skill
- author
- Stakpak <team@stakpak.dev>
- version
- 1.0.22
SKILL.md
12-Factor App Modernization
Quick Start
Analyze Application
# Clone repository
git clone <repo-url>
cd <repo-name>
# Create inventory of services
# Document tech stack, deployment configs, backing services
Generate Compliance Report
Create a structured JSON report documenting compliance status for all 12 factors.
The 12 Factors
| Factor | Principle | Key Questions |
|---|---|---|
| I. Codebase | One codebase, many deploys | Is there a single repo? Are there environment-specific branches? |
| II. Dependencies | Explicitly declare and isolate | Are all dependencies declared with pinned versions? |
| III. Config | Store config in environment | Are connection strings, credentials, and settings externalized? |
| IV. Backing Services | Treat as attached resources | Can backing services be swapped without code changes? |
| V. Build, Release, Run | Strict separation | Are build artifacts immutable? Is config injected at runtime? |
| VI. Processes | Stateless processes | Is session state stored externally? |
| VII. Port Binding | Export via port binding | Are services self-contained with embedded servers? |
| VIII. Concurrency | Scale via process model | Can the app scale horizontally? |
| IX. Disposability | Fast startup, graceful shutdown | Does the app handle SIGTERM? Is there an init system (tini)? |
| X. Dev/Prod Parity | Keep environments similar | Are dev and prod using same backing services? |
| XI. Logs | Treat as event streams | Does the app write to stdout/stderr? |
| XII. Admin Processes | Run as one-off processes | Are migrations and admin tasks separate from the main app? |
Application Analysis
Step 1: Clone and Inventory
Map out the application architecture:
- Identify all services/microservices
- Document the tech stack for each service (language, framework, runtime)
- List all deployment configurations (Dockerfiles, docker-compose, Kubernetes manifests)
- Identify backing services (databases, caches, message queues)
Step 2: Analyze Against Each Factor
Systematically evaluate each service against all 12 factors. Create a structured report documenting compliance status.
Compliance Report Structure
{
"title": "12-Factor App Compliance Report",
"repository": "<repo-url>",
"analysis_date": "<date>",
"summary": {
"total_factors": 12,
"services_analyzed": ["<service-list>"],
"overall_compliance": "<status>"
},
"factors": {
"<factor_id>": {
"name": "<factor-name>",
"status": "<COMPLIANT|PARTIAL|NON-COMPLIANT>",
"findings": ["<observations>"],
"issues": [{"service": "", "file": "", "problem": "", "severity": "", "impact": ""}],
"fixes": [{"service": "", "file": "", "action": ""}]
}
},
"priority_fixes": [{"priority": 1, "category": "", "description": "", "affected_files": []}]
}
Configuration Externalization (Factor III - Highest Priority)
This is typically the most critical violation. Hardcoded credentials and connection strings are security risks.
Python (Flask/Django)
# Before (hardcoded)
redis = Redis(host="redis", port=6379)
# After (externalized)
redis_host = os.getenv('REDIS_HOST', 'redis')
redis_port = int(os.getenv('REDIS_PORT', '6379'))
redis = Redis(host=redis_host, port=redis_port)
Node.js
// Before (hardcoded)
const pool = new Pool({
connectionString: 'postgres://user:pass@db/mydb'
});
// After (externalized)
const pool = new Pool({
connectionString: process.env.DATABASE_URL || 'postgres://user:pass@db/mydb'
});
C#/.NET
// Before (hardcoded)
var conn = new NpgsqlConnection("Server=db;Username=postgres;Password=secret;");
// After (externalized)
var host = Environment.GetEnvironmentVariable("DB_HOST") ?? "db";
var user = Environment.GetEnvironmentVariable("DB_USER") ?? "postgres";
var password = Environment.GetEnvironmentVariable("DB_PASSWORD") ?? "postgres";
var connString = $"Server={host};Username={user};Password={password};";
Dependency Management (Factor II)
Unpinned dependencies cause reproducibility issues and potential security vulnerabilities.
Python (requirements.txt)
# Before
Flask
Redis
gunicorn
# After
Flask==3.0.0
Redis==5.0.1
gunicorn==21.2.0
Node.js (package.json)
// Before - caret allows minor/patch updates
"dependencies": {
"express": "^4.18.2"
}
// After - exact versions
"dependencies": {
"express": "4.18.2"
}
Important: After changing package.json versions, regenerate package-lock.json:
rm package-lock.json && npm install --package-lock-only
Signal Handling (Factor IX)
Containers need proper init systems to handle signals correctly for graceful shutdown.
Add tini to Dockerfiles
# Install tini
RUN apt-get update && \
apt-get install -y --no-install-recommends tini && \
rm -rf /var/lib/apt/lists/*
# Use tini as entrypoint
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["your-app-command"]
Docker Compose Configuration
Replace hardcoded values with environment variable substitution:
services:
app:
environment:
DATABASE_URL: "postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db/mydb"
REDIS_HOST: redis
db:
environment:
POSTGRES_USER: "${POSTGRES_USER:-postgres}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-postgres}"
Kubernetes Secrets
Never store credentials in plain text in Kubernetes manifests.
Create Secret Manifest
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: <generate-strong-password>
Reference in Deployments
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: POSTGRES_PASSWORD
Validation
Docker Compose Validation
docker compose config --quiet && echo "✓ Valid"
Kubernetes Manifest Validation
kubectl apply --dry-run=client -f k8s-specifications/
Build and Test
docker compose build
docker compose up -d
docker compose ps # Verify all services healthy
Common Anti-Patterns
- Hardcoded connection strings - Most common and most critical
- Unpinned dependencies - Causes "works on my machine" issues
- Missing init systems - Causes zombie processes and slow shutdowns
- Credentials in source control - Security vulnerability
- Environment-specific code branches - Violates codebase principle
Environment Variable Naming Conventions
Use consistent, descriptive names:
DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAMEREDIS_HOST,REDIS_PORTDATABASE_URL(for connection string format)<SERVICE>_URLfor full connection strings
Backward Compatibility
Always provide sensible defaults when externalizing config:
# Maintains backward compatibility with existing deployments
host = os.getenv('REDIS_HOST', 'redis') # Falls back to 'redis'
References
- The Twelve-Factor App - Original methodology
- Beyond the Twelve-Factor App - O'Reilly extended guide
- Kubernetes Secrets Best Practices
- Docker Init Systems - tini documentation
- OWASP Secrets Management
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
how-to-publish-paks
A practical guide for creating and publishing high-quality Agent Skills (paks) to the Paks registry. Covers SKILL.md format, frontmatter structure, content writing best practices, validation, versioning, and publishing workflow.
beads-issue-tracker
Guide for using Beads (bd), a dependency-aware issue tracker for AI agents. Issues chained together like beads.
vllm-deployment
Deploy vLLM for high-performance LLM inference. Covers Docker CPU/GPU deployments and cloud VM provisioning with OpenAI-compatible API endpoints.
dockerization
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
simple-deployment-on-vm
How to do simple but secure deployments using virtual machines on different cloud providers
migrating-bitnami-to-bitnami-legacy
This rule book helps you migrate Bitnami Helm charts and container images from the bitnami repository to the bitnamilegacy repository. This migration is necessary due to Bitnami's transition, effective August 28th, 2025, where existing images will be moved to the legacy repo
Didn't find tool you were looking for?