
Compose Patterns 2025
- 158 installs
- 50 repo stars
- Updated June 18, 2026
- josiahsiegel/claude-plugin-marketplace
Apply Jetpack Compose 2025 UI architecture patterns when building Android screens, state hoisting, navigation, theming, and reusable composable components.
About
Compose-patterns-2025 guides Android Jetpack Compose implementation: declarative UI structure, state management, navigation, theming, and 2025 best practices for maintainable mobile frontend code in Claude Code.
- Composable architecture
- State hoisting
- Navigation patterns
- Material theming
- Reusable UI blocks
Compose Patterns 2025 by the numbers
- 158 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #521 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill compose-patterns-2025Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 158 |
|---|---|
| repo stars | ★ 50 |
| Last updated | June 18, 2026 |
| Repository | josiahsiegel/claude-plugin-marketplace ↗ |
What it does
Apply Jetpack Compose 2025 UI architecture patterns when building Android screens, state hoisting, navigation, theming, and reusable composable components.
Files
Docker Compose Patterns for Production (2025)
Overview
This skill documents production-ready Docker Compose patterns and best practices for 2025, based on official Docker documentation and industry standards.
File Format Changes (2025)
IMPORTANT: The version field is now obsolete in Docker Compose v2.42+.
Correct (2025):
services:
app:
image: myapp:latestIncorrect (deprecated):
version: '3.8' # DO NOT USE
services:
app:
image: myapp:latestMultiple Environment Strategy
Pattern: Base + Environment Overrides
compose.yaml (base):
services:
app:
build:
context: ./app
dockerfile: Dockerfile
environment:
- NODE_ENV=production
restart: unless-stoppedcompose.override.yaml (development - auto-loaded):
services:
app:
build:
target: development
volumes:
- ./app/src:/app/src:cached
environment:
- NODE_ENV=development
- DEBUG=*
ports:
- "9229:9229" # Debuggercompose.prod.yaml (production - explicit):
services:
app:
build:
target: production
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M
restart_policy:
condition: on-failure
max_attempts: 3Usage:
# Development (auto-loads compose.override.yaml)
docker compose up
# Production
docker compose -f compose.yaml -f compose.prod.yaml up -d
# CI/CD
docker compose -f compose.yaml -f compose.ci.yaml up --abort-on-container-exitEnvironment Variable Management
Pattern: .env Files per Environment
.env.template (committed to git):
# Database
DB_HOST=sqlserver
DB_PORT=1433
DB_NAME=myapp
DB_USER=sa
# DB_PASSWORD= (set in actual .env)
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
# REDIS_PASSWORD= (set in actual .env)
# Application
NODE_ENV=production
LOG_LEVEL=info.env.dev:
DB_PASSWORD=Dev!Pass123
REDIS_PASSWORD=redis-dev-123
NODE_ENV=development
LOG_LEVEL=debug.env.prod:
DB_PASSWORD=${PROD_DB_PASSWORD} # From CI/CD
REDIS_PASSWORD=${PROD_REDIS_PASSWORD}
NODE_ENV=production
LOG_LEVEL=infoLoad specific environment:
docker compose --env-file .env.dev upSecurity Patterns
Pattern: Run as Non-Root User
services:
app:
image: node:20-alpine
user: "1000:1000" # UID:GID
read_only: true
tmpfs:
- /tmp
- /app/.cache
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Only if binding to ports < 1024
security_opt:
- no-new-privileges:trueCreate user in Dockerfile:
FROM node:20-alpine
# Create app user
RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser
# Set ownership
WORKDIR /app
COPY --chown=appuser:appuser . .
USER appuserPattern: Secrets Management
Docker Swarm secrets (production):
services:
app:
secrets:
- db_password
- api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true # Managed by SwarmAccess secrets in application:
// Read from /run/secrets/
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();Development alternative (environment):
services:
app:
environment:
- DB_PASSWORD_FILE=/run/secrets/db_passwordHealth Check Patterns
Pattern: Comprehensive Health Checks
HTTP endpoint:
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40sDatabase ping:
services:
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
interval: 10s
timeout: 3s
retries: 3Custom script:
services:
app:
healthcheck:
test: ["CMD", "node", "/app/scripts/healthcheck.js"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40shealthcheck.js:
const http = require('http');
const options = {
hostname: 'localhost',
port: 8080,
path: '/health',
timeout: 2000
};
const req = http.request(options, (res) => {
process.exit(res.statusCode === 200 ? 0 : 1);
});
req.on('error', () => process.exit(1));
req.on('timeout', () => {
req.destroy();
process.exit(1);
});
req.end();Dependency Management
Pattern: Ordered Startup with Conditions
services:
web:
depends_on:
database:
condition: service_healthy
redis:
condition: service_started
migration:
condition: service_completed_successfully
database:
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
redis:
# No health check needed, just wait for start
migration:
image: myapp:latest
command: npm run migrate
restart: "no" # Run once
depends_on:
database:
condition: service_healthyNetwork Isolation Patterns
Pattern: Three-Tier Network Architecture
services:
nginx:
image: nginx:alpine
networks:
- frontend
ports:
- "80:80"
api:
build: ./api
networks:
- frontend
- backend
database:
image: postgres:16-alpine
networks:
- backend # No frontend access
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No external accessPattern: Service-Specific Networks
services:
web-app:
networks:
- public
- app-network
api:
networks:
- app-network
- data-network
postgres:
networks:
- data-network
redis:
networks:
- data-network
networks:
public:
driver: bridge
app-network:
driver: bridge
internal: true
data-network:
driver: bridge
internal: trueVolume Patterns
Pattern: Named Volumes for Persistence
services:
database:
volumes:
- db-data:/var/lib/postgresql/data # Persistent data
- ./init:/docker-entrypoint-initdb.d:ro # Init scripts (read-only)
- db-logs:/var/log/postgresql # Logs
volumes:
db-data:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/data/postgres # Host path
db-logs:
driver: localPattern: Development Bind Mounts
services:
app:
volumes:
- ./src:/app/src:cached # macOS optimization
- /app/node_modules # Don't overwrite installed modules
- app-cache:/app/.cache # Named volume for cacheVolume mount options:
:ro- Read-only:rw- Read-write (default):cached- macOS performance optimization (host authoritative):delegated- macOS performance optimization (container authoritative):z- SELinux single container:Z- SELinux multi-container
Resource Management Patterns
Pattern: CPU and Memory Limits
services:
app:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256MCalculate total resources:
# 3 app replicas + database + redis
services:
app:
deploy:
replicas: 3
resources:
limits:
cpus: '0.5' # 3 x 0.5 = 1.5 CPUs
memory: 512M # 3 x 512M = 1.5GB
database:
deploy:
resources:
limits:
cpus: '2' # 2 CPUs
memory: 4G # 4GB
redis:
deploy:
resources:
limits:
cpus: '0.5' # 0.5 CPUs
memory: 512M # 512MB
# Total: 4 CPUs, 6GB RAM minimumLogging Patterns
Pattern: Centralized Logging
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
compress: "true"
labels: "app,environment"Alternative: Log to stdout/stderr (12-factor):
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"View logs:
docker compose logs -f app
docker compose logs --since 30m app
docker compose logs --tail 100 appInit Container Pattern
Pattern: Database Migration
services:
migration:
image: myapp:latest
command: npm run migrate
depends_on:
database:
condition: service_healthy
restart: "no" # Run once
networks:
- backend
app:
image: myapp:latest
depends_on:
migration:
condition: service_completed_successfully
networks:
- backendYAML Anchors and Aliases
Pattern: Reusable Configuration
x-common-app-config: &common-app
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
services:
app1:
<<: *common-app
build: ./app1
ports:
- "8001:8080"
app2:
<<: *common-app
build: ./app2
ports:
- "8002:8080"
app3:
<<: *common-app
build: ./app3
ports:
- "8003:8080"Pattern: Environment-Specific Overrides
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
x-resources: &default-resources
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
services:
app:
logging: *default-logging
deploy:
resources: *default-resourcesPort Binding Patterns
Pattern: Security-First Port Binding
services:
# Public services
web:
ports:
- "80:8080"
- "443:8443"
# Development only (localhost binding)
debug:
ports:
- "127.0.0.1:9229:9229" # Debugger only accessible from host
# Environment-based binding
app:
ports:
- "${DOCKER_WEB_PORT_FORWARD:-127.0.0.1:8000}:8000"Environment control:
# Development (.env.dev)
DOCKER_WEB_PORT_FORWARD=127.0.0.1:8000 # Localhost only
# Production (.env.prod)
DOCKER_WEB_PORT_FORWARD=8000 # All interfacesRestart Policy Patterns
services:
# Always restart (production services)
app:
restart: always
# Restart unless manually stopped (most common)
database:
restart: unless-stopped
# Never restart (one-time tasks)
migration:
restart: "no"
# Restart on failure only (with Swarm)
worker:
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120sValidation and Testing
Pattern: Pre-Deployment Validation
#!/bin/bash
set -euo pipefail
echo "Validating Compose syntax..."
docker compose config > /dev/null
echo "Building images..."
docker compose build
echo "Running security scan..."
for service in $(docker compose config --services); do
image=$(docker compose config | yq ".services.$service.image")
if [ -n "$image" ]; then
docker scout cves "$image" || true
fi
done
echo "Starting services..."
docker compose up -d
echo "Checking health..."
sleep 10
docker compose ps
echo "Running smoke tests..."
curl -f http://localhost:8080/health || exit 1
echo "✓ All checks passed"Complete Production Example
# Modern Compose format (no version field for v2.40+)
x-common-service: &common-service
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
security_opt:
- no-new-privileges:true
services:
nginx:
<<: *common-service
image: nginxinc/nginx-unprivileged:alpine
ports:
- "80:8080"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
networks:
- frontend
depends_on:
api:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"]
interval: 30s
api:
<<: *common-service
build:
context: ./api
dockerfile: Dockerfile
target: production
user: "1000:1000"
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
networks:
- frontend
- backend
depends_on:
migration:
condition: service_completed_successfully
redis:
condition: service_started
env_file:
- .env
healthcheck:
test: ["CMD", "node", "healthcheck.js"]
interval: 30s
start_period: 40s
deploy:
resources:
limits:
cpus: '1'
memory: 512M
migration:
image: myapp:latest
command: npm run migrate
restart: "no"
networks:
- backend
depends_on:
postgres:
condition: service_healthy
postgres:
<<: *common-service
image: postgres:16-alpine
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
secrets:
- postgres_password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
deploy:
resources:
limits:
cpus: '1'
memory: 2G
redis:
<<: *common-service
image: redis:7.4-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
postgres-data:
driver: local
redis-data:
driver: local
secrets:
postgres_password:
file: ./secrets/postgres_password.txtCommon Mistakes to Avoid
1. Using `version` field - Obsolete in 2025 2. No health checks - Leads to race conditions 3. Running as root - Security risk 4. No resource limits - Can exhaust host resources 5. Hardcoded secrets - Use secrets or environment variables 6. No logging limits - Disk space issues 7. Bind mounts in production - Use named volumes 8. Missing restart policies - Services don't recover 9. No network isolation - All services can talk to each other 10. Not using .dockerignore - Larger build contexts
Troubleshooting Commands
# Validate syntax
docker compose config
# View merged configuration
docker compose config --services
# Check which file is being used
docker compose config --files
# View environment interpolation
docker compose config --no-interpolate
# Check service dependencies
docker compose config | yq '.services.*.depends_on'
# View resource usage
docker stats $(docker compose ps -q)
# Debug startup issues
docker compose up --no-deps service-name
# Force recreate
docker compose up --force-recreate service-name