Skip to main content
This guide covers deploying the AdonisJS Starter Kit to production servers using Docker and other deployment strategies.

Pre-Deployment Checklist

1

Environment Configuration

Ensure all production environment variables are set correctly.
  • NODE_ENV=production
  • APP_KEY is set (use node ace generate:key)
  • Database credentials configured
  • Email service configured (Resend or SMTP)
  • OAuth credentials for Google login
2

Database Setup

Prepare your production database.
# Run migrations
node ace migration:run --force

# Run seeders (if needed)
node ace db:seed
3

Build Application

Build the production bundle.
# Build application
node ace build

# Test the build
cd build
node bin/server.js
4

Security Review

Review security settings.
  • CORS settings configured
  • Rate limiting enabled
  • CSRF protection enabled
  • Secure cookies enabled (HTTPS)
  • Database connections use SSL

Docker Production Deployment

Building the Production Image

The production Dockerfile is optimized for size and security:
FROM node:22-alpine

# Install compatibility libraries
RUN apk add --no-cache libc6-compat

WORKDIR /app

# Enable pnpm
RUN npm install -g corepack@latest
RUN corepack enable pnpm

COPY . .

# Install dependencies
ENV CI=true
RUN pnpm install --force --frozen-lockfile

# Build application
WORKDIR /app/apps/web
RUN node ace build --ignore-ts-errors

WORKDIR /app/apps/web/build

EXPOSE 3333

CMD ["node", "bin/server.js"]
Key Features:
  • Alpine Linux base (minimal size)
  • Multi-stage build considerations
  • Frozen lockfile for reproducibility
  • Production build optimization

Deploy with Docker Compose

# Build and start all services
docker compose -f docker-compose.prod.yaml up -d --build

# Check service status
docker compose -f docker-compose.prod.yaml ps

# View logs
docker compose -f docker-compose.prod.yaml logs -f web

Production Stack Architecture

The production setup includes:
1

Nginx Reverse Proxy

Handles incoming HTTP/HTTPS traffic on ports 80/443.
server {
  listen 80;
  server_name example.com;
  client_max_body_size 100M;
  
  location / {
    proxy_pass http://web:3333;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}
2

AdonisJS Application

The web service runs the Node.js application on port 3333.
web:
  restart: always
  environment:
    HOST: web
    NODE_ENV: production
    DB_HOST: pgsql
3

PostgreSQL Database

Internal database with no exposed ports.
pgsql:
  restart: always
  ports: []  # No external access

Traditional Server Deployment

Server Requirements

Minimum Specs

  • 1 CPU core
  • 1GB RAM
  • 10GB storage
  • Ubuntu 22.04 or later

Recommended Specs

  • 2+ CPU cores
  • 2GB+ RAM
  • 20GB+ storage
  • Load balancer ready

Manual Deployment Steps

1

Install Dependencies

# Update system
sudo apt update && sudo apt upgrade -y

# Install Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs

# Install pnpm
corepack enable pnpm

# Install PostgreSQL
sudo apt install -y postgresql postgresql-contrib
2

Setup Application

# Clone repository
git clone <your-repo-url> /var/www/app
cd /var/www/app

# Install dependencies
pnpm install --prod

# Build application
cd apps/web
node ace build
3

Configure Environment

# Copy environment file
cp apps/web/.env.example apps/web/.env

# Edit with production values
nano apps/web/.env
Never commit .env files to version control. Use secret management tools.
4

Setup Process Manager

Use PM2 to manage the Node.js process:
# Install PM2
npm install -g pm2

# Start application
cd /var/www/app/apps/web/build
pm2 start bin/server.js --name "adonisjs-app"

# Save PM2 configuration
pm2 save

# Setup startup script
pm2 startup
5

Configure Nginx

server {
  listen 80;
  server_name example.com;
  
  location / {
    proxy_pass http://localhost:3333;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_cache_bypass $http_upgrade;
  }
}
# Enable site
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

SSL/TLS Setup with Let’s Encrypt

# Install Certbot
sudo apt install -y certbot python3-certbot-nginx

# Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com

# Auto-renewal is configured automatically
sudo certbot renew --dry-run

Platform-as-a-Service Deployments

Deploying to Railway

1

Connect Repository

  1. Create a new project on Railway
  2. Connect your GitHub repository
  3. Select the apps/web directory as root
2

Configure Services

Add services:
  • PostgreSQL database (from Railway marketplace)
  • Redis (optional, for caching)
3

Set Environment Variables

Configure in Railway dashboard:
NODE_ENV=production
APP_KEY=${{ railway.secret }}
DB_HOST=${{ Postgres.PGHOST }}
DB_PORT=${{ Postgres.PGPORT }}
DB_USER=${{ Postgres.PGUSER }}
DB_PASSWORD=${{ Postgres.PGPASSWORD }}
DB_DATABASE=${{ Postgres.PGDATABASE }}
4

Deploy

Railway automatically deploys on git push.
git push origin main

Deploying to Render

1

Create Web Service

  1. Go to Render Dashboard
  2. New → Web Service
  3. Connect repository
2

Configure Build

# Build Command
cd apps/web && pnpm install && node ace build

# Start Command
cd apps/web/build && node bin/server.js

# Root Directory
./
3

Add PostgreSQL

  1. Create PostgreSQL database from Render dashboard
  2. Copy connection details
  3. Add to environment variables
4

Deploy

Render auto-deploys on push to main branch.

Deploying to Fly.io

1

Install Fly CLI

curl -L https://fly.io/install.sh | sh
fly auth login
2

Initialize App

cd apps/web
fly launch
3

Create Database

fly postgres create
fly postgres attach <db-name>
4

Deploy

fly deploy

Database Management

Migrations

# Production migrations
node ace migration:run --force

# Check status
node ace migration:status

# Rollback (careful!)
node ace migration:rollback --force

Backup Strategy

# Backup database
pg_dump -h localhost -U root -d app > backup-$(date +%Y%m%d).sql

# Restore database
psql -h localhost -U root -d app < backup-20260303.sql

Monitoring and Logging

Application Logs

# Follow logs
docker compose logs -f web

# Last 100 lines
docker compose logs --tail=100 web

# Export logs
docker compose logs web > app.log

Health Checks

Implement health check endpoint:
// routes/health.ts
import router from '@adonisjs/core/services/router'

router.get('/health', async ({ response }) => {
  return response.json({
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
  })
})
Configure in Docker:
web:
  healthcheck:
    test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3333/health"]
    interval: 30s
    timeout: 10s
    retries: 3
    start_period: 40s

Performance Monitoring

Consider integrating:

Application Monitoring

Infrastructure Monitoring

Scaling Considerations

Horizontal Scaling

1

Stateless Application

Ensure your application is stateless:
  • Use database for sessions (not memory)
  • Store uploads in S3/cloud storage
  • Use Redis for cache and queues
2

Load Balancer

Configure load balancer (Nginx, HAProxy, or cloud LB):
upstream backend {
  least_conn;
  server web1:3333;
  server web2:3333;
  server web3:3333;
}
3

Database Connection Pooling

Configure in config/database.ts:
postgres: {
  pool: {
    min: 2,
    max: 10,
  },
}

Vertical Scaling

Adjust resource limits:
web:
  deploy:
    resources:
      limits:
        cpus: '2.0'
        memory: 2G
      reservations:
        cpus: '1.0'
        memory: 1G

Troubleshooting

  1. Check environment variables:
    docker compose exec web env | grep NODE_ENV
    
  2. Verify build completed:
    ls -la apps/web/build
    
  3. Check for missing dependencies:
    docker compose exec web pnpm install
    
  1. Verify database is running:
    docker compose ps pgsql
    
  2. Test connection:
    docker compose exec web node ace db:check
    
  3. Check credentials in .env
  1. Check Node.js memory limit:
    NODE_OPTIONS="--max-old-space-size=2048"
    
  2. Review database query performance
  3. Implement caching strategy
  1. Enable query logging:
    postgres: {
      debug: true,
    }
    
  2. Add database indexes
  3. Implement Redis caching
  4. Use CDN for static assets

Security Checklist

  • APP_KEY is unique and secret
  • Database uses strong password
  • HTTPS/SSL enabled
  • CORS configured for production domains
  • Rate limiting enabled
  • CSRF protection active
  • Security headers configured
  • Secrets stored in environment variables (not code)
  • Regular security updates applied
  • Database backups automated
  • Monitoring and alerts configured

Next Steps

Docker Setup

Learn about Docker configuration

Environment Variables

Configure environment variables

Build docs developers (and LLMs) love