Deployment
Superfunction applications are designed to be deployed using Docker, providing consistent environments across development and production.
Prerequisites
- Docker and Docker Compose installed
- PostgreSQL 16+ (provided via Docker)
- Redis 7+ (optional, provided via Docker for caching/sessions)
- Node.js 22+ (for local development)
Docker Compose Setup
Superfunction provides a pre-configured docker-compose.yml for running PostgreSQL and Redis. Redis is optional and can be removed if you don't need caching or session storage:
yaml# docker-compose.yml version: '3.8' services: # PostgreSQL postgres: image: postgres:16-alpine container_name: spfn-postgres environment: POSTGRES_USER: spfn POSTGRES_PASSWORD: spfn POSTGRES_DB: spfn_dev ports: - '5432:5432' volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ['CMD-SHELL', 'pg_isready -U spfn -d spfn_dev'] interval: 5s timeout: 5s retries: 5 # Redis redis: image: redis:7-alpine container_name: spfn-redis ports: - "6379:6379" command: redis-server --appendonly yes volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 2s timeout: 3s retries: 5 volumes: postgres_data: redis_data: networks: default: name: spfn-network
Starting Services
Terminal# Start PostgreSQL and Redis docker-compose up -d # Check service status docker-compose ps # View logs docker-compose logs -f # Stop services docker-compose down
Application Dockerfile
Superfunction provides a production-ready Dockerfile optimized for both Next.js and API server:
dockerfile# Production Dockerfile for Superfunction FROM node:22-alpine WORKDIR /app # Install pnpm RUN corepack enable pnpm # Copy dependency files COPY package.json pnpm-lock.yaml* ./ # Install dependencies RUN pnpm install --frozen-lockfile --prod=false # Copy source code COPY . . # Build application RUN pnpm run spfn:build # Remove dev dependencies (optional, reduces image size) RUN pnpm prune --prod # Environment ENV NODE_ENV=production # Expose ports (3790 for Next.js, 8790 for API) EXPOSE 3790 8790 # Health check HEALTHCHECK \ CMD node -e "require('http').get('http://localhost:8790/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" # Start application CMD ["pnpm", "run", "spfn:start"]
Note: Key Features
- Alpine-based: Minimal image size (~150MB)
- Layer caching: Dependencies cached separately from source code
- Production pruning: Dev dependencies removed after build
- Health checks: Built-in readiness probes
- Dual ports: Exposes both Next.js (3790) and API (8790)
Environment Configuration
Create separate environment files for different stages:
Development (.env.local)
Terminal# Database DATABASE_URL="postgresql://spfn:spfn@localhost:5432/spfn_dev" # Redis (Optional - remove if not needed) REDIS_URL="redis://localhost:6379" # API NEXT_PUBLIC_API_URL="http://localhost:8790" APP_PORT=3790 API_PORT=8790 # Next.js NODE_ENV=development
Production (.env.production)
Terminal# Database (use production credentials) DATABASE_URL="postgresql://user:password@postgres-host:5432/spfn_prod" # Redis (Optional - remove if not needed) REDIS_URL="redis://redis-host:6379" # API NEXT_PUBLIC_API_URL="https://api.yourdomain.com" APP_PORT=3790 API_PORT=8790 # Next.js NODE_ENV=production # Optional: Monitoring SENTRY_DSN=your-sentry-dsn LOG_LEVEL=info
⚠️ Warning: Security Warning
Never commit
.env.productionto version control. Use environment variable injection in your CI/CD pipeline or secrets management system.
Building for Production
Local Build
Terminal# Build Docker image docker build -t spfn-app:latest \ --build-arg CI_BOT_TOKEN=${CI_BOT_TOKEN} \ --build-arg APP_PORT=3790 \ . # Run container docker run -d \ --name spfn-app \ --network spfn-network \ -p 3790:3790 \ -e DATABASE_URL="postgresql://spfn:spfn@spfn-postgres:5432/spfn_dev" \ -e REDIS_URL="redis://spfn-redis:6379" \ spfn-app:latest # Check logs docker logs -f spfn-app
With Docker Compose
Create a docker-compose.production.yml that includes your application:
yamlversion: '3.8' services: postgres: image: postgres:16-alpine container_name: spfn-postgres environment: POSTGRES_USER: ${POSTGRES_USER:-spfn} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-spfn} POSTGRES_DB: ${POSTGRES_DB:-spfn_prod} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-spfn}'] interval: 5s timeout: 5s retries: 5 redis: image: redis:7-alpine container_name: spfn-redis command: redis-server --appendonly yes volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 2s timeout: 3s retries: 5 app: build: context: . dockerfile: Dockerfile args: CI_BOT_TOKEN: ${CI_BOT_TOKEN} APP_PORT: 3790 container_name: spfn-app ports: - "3790:3790" environment: DATABASE_URL: postgresql://${POSTGRES_USER:-spfn}:${POSTGRES_PASSWORD:-spfn}@postgres:5432/${POSTGRES_DB:-spfn_prod} REDIS_URL: redis://redis:6379 NODE_ENV: production depends_on: postgres: condition: service_healthy redis: condition: service_healthy restart: unless-stopped volumes: postgres_data: redis_data: networks: default: name: spfn-network
Terminal# Build and start all services docker-compose -f docker-compose.production.yml up -d --build # View logs docker-compose -f docker-compose.production.yml logs -f app # Stop all services docker-compose -f docker-compose.production.yml down
Database Migrations
Superfunction provides CLI commands for managing database migrations:
Terminal# Generate migration from schema changes npx spfn db generate # Apply migrations to database npx spfn db migrate # Development workflow npx spfn db generate # Create migration file npx spfn db migrate # Apply to local database # Production: Run migrations inside container docker exec spfn-app npx spfn db migrate # Or run migrations as a separate container docker run --rm \ --network spfn-network \ -e DATABASE_URL="postgresql://spfn:spfn@spfn-postgres:5432/spfn_prod" \ spfn-app:latest \ npx spfn db migrate
CI/CD Pipeline Example
Example GitHub Actions workflow for automated deployment:
yamlname: Deploy to Production on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Container Registry uses: docker/login-action@v3 with: registry: your-registry.com username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }} - name: Build and push uses: docker/build-push-action@v5 with: context: . push: true tags: your-registry.com/spfn-app:latest build-args: | CI_BOT_TOKEN=${{ secrets.CI_BOT_TOKEN }} cache-from: type=registry,ref=your-registry.com/spfn-app:buildcache cache-to: type=registry,ref=your-registry.com/spfn-app:buildcache,mode=max - name: Deploy to server uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USER }} key: ${{ secrets.SERVER_SSH_KEY }} script: | cd /opt/spfn-app docker-compose pull docker-compose up -d docker-compose exec -T app npx spfn db migrate
Production Considerations
1. Resource Limits
Set appropriate resource limits in your docker-compose file:
yamlservices: app: # ... other config deploy: resources: limits: cpus: '2' memory: 2G reservations: cpus: '1' memory: 1G
2. Health Checks
Add health checks to ensure services are ready:
yamlservices: app: # ... other config healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3790/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s
3. Logging
Configure logging drivers for production:
yamlservices: app: # ... other config logging: driver: "json-file" options: max-size: "10m" max-file: "3"
4. Reverse Proxy
Use Nginx or Caddy as a reverse proxy for SSL termination:
yamlservices: nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro depends_on: - app app: # ... other config # Don't expose port directly expose: - "3790"
Monitoring and Debugging
Container Logs
Terminal# View all container logs docker-compose logs -f # View specific service logs docker-compose logs -f app # View last 100 lines docker-compose logs --tail=100 app # View logs with timestamps docker-compose logs -f -t app
Container Shell Access
Terminal# Access container shell docker exec -it spfn-app sh # Run commands in container docker exec spfn-app pnpm run db:migrate docker exec spfn-app node --version # Check container resource usage docker stats spfn-app
Database Connection
Terminal# Connect to PostgreSQL docker exec -it spfn-postgres psql -U spfn -d spfn_prod # Run SQL from host docker exec -i spfn-postgres psql -U spfn -d spfn_prod < backup.sql # Create database backup docker exec spfn-postgres pg_dump -U spfn spfn_prod > backup.sql
Troubleshooting
Container Won't Start
Terminal# Check container status docker-compose ps # View detailed logs docker-compose logs app # Inspect container docker inspect spfn-app # Check if services are healthy docker-compose ps --format json | jq '.[].Health'
Database Connection Issues
Terminal# Check if PostgreSQL is ready docker exec spfn-postgres pg_isready -U spfn # Test connection from app container docker exec spfn-app sh -c 'apt-get update && apt-get install -y postgresql-client && psql $DATABASE_URL -c "SELECT 1"' # Check network connectivity docker exec spfn-app ping spfn-postgres
Build Cache Issues
Terminal# Clear Docker build cache docker builder prune -af # Rebuild without cache docker-compose build --no-cache # Remove all containers and volumes docker-compose down -v
✅ Success: Next Steps
Your Superfunction application is now deployed! Consider adding:
- Monitoring with Sentry or similar tools
- Automated backups for PostgreSQL
- Load balancing for horizontal scaling
- CDN for static assets