How to Deploy a Node.js App to Production (2026)
Your Node.js app works locally. Now what? Here's how to deploy it to production with HTTPS, environment variables, monitoring, and zero-downtime updates. Four approaches from simplest to most control.
Option 1: Railway (Simplest)
Railway deploys from GitHub with zero config. Push code → it's live.
Step 1: Connect GitHub
- Go to railway.app → New Project → Deploy from GitHub
- Select your repo
- Railway detects Node.js automatically
Step 2: Add Environment Variables
In the Railway dashboard: Variables tab → add your env vars (DATABASE_URL, API_KEY, etc.)
Step 3: Configure Start Command
Railway reads package.json:
{
"scripts": {
"start": "node dist/index.js",
"build": "tsc"
}
}
Step 4: Add a Domain
Settings → Networking → Generate Domain (or add custom domain).
That's it. Railway handles:
- HTTPS (automatic)
- Build and deploy (on every push)
- Scaling (horizontal and vertical)
- Logs and metrics
Pricing: $5/month + usage (~$5-20/month for small apps). Free trial available.
Best for: Startups, side projects, APIs that need to be live fast.
Option 2: Fly.io (Edge Deployment)
Fly.io deploys your app to servers worldwide. Great for low-latency APIs.
Step 1: Install CLI
curl -L https://fly.io/install.sh | sh
fly auth login
Step 2: Launch
cd your-node-app
fly launch
Fly detects Node.js, creates a fly.toml config:
[build]
[build.args]
NODE_VERSION = "22"
[[services]]
internal_port = 3000
protocol = "tcp"
[services.concurrency]
hard_limit = 250
soft_limit = 200
[[services.ports]]
port = 443
handlers = ["tls", "http"]
Step 3: Set Secrets
fly secrets set DATABASE_URL="postgres://..." API_KEY="sk-..."
Step 4: Deploy
fly deploy
Pricing: Free for small apps (3 shared VMs). Pay-as-you-go after.
Best for: Global APIs needing low latency. Websocket apps.
Option 3: VPS with Docker (Most Control)
Deploy to a VPS (Hetzner, DigitalOcean, Linode) with Docker.
Step 1: Create Dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "dist/index.js"]
Step 2: Set Up VPS
# On your VPS (Ubuntu)
apt update && apt install docker.io docker-compose nginx certbot -y
Step 3: Docker Compose
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
env_file: .env
restart: unless-stopped
Step 4: Nginx Reverse Proxy
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
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;
}
}
Step 5: HTTPS with Certbot
certbot --nginx -d api.yourdomain.com
Step 6: Deploy
docker compose up -d --build
Pricing: VPS from $4/month (Hetzner) to $12/month (DigitalOcean). You manage everything.
Best for: Maximum control, lowest cost at scale, compliance requirements.
Option 4: Coolify (Self-Hosted PaaS)
Coolify gives you Railway-like experience on your own VPS.
Step 1: Install Coolify
curl -fsSL https://cdn.coolify.io/install.sh | bash
Step 2: Connect GitHub
In Coolify dashboard: New Resource → GitHub → Select repo
Step 3: Configure and Deploy
Coolify auto-detects Node.js, sets up HTTPS, and deploys on push. Same experience as Railway but on your $4/month VPS.
Pricing: Free (open source) + VPS cost ($4-20/month)
Best for: Teams who want Railway DX at VPS prices.
Production Checklist
Before going live, ensure:
Security
- Environment variables (not hardcoded secrets)
- HTTPS enabled
- CORS configured properly
- Rate limiting on API endpoints
- Helmet.js for security headers
import helmet from 'helmet'
import cors from 'cors'
app.use(helmet())
app.use(cors({ origin: 'https://yourfrontend.com' }))
Performance
- NODE_ENV=production
- Gzip/Brotli compression
- Database connection pooling
- Response caching where appropriate
Monitoring
- Error tracking (Sentry)
- Uptime monitoring (BetterStack)
- Log aggregation (Axiom or BetterStack)
- Health check endpoint
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() })
})
Reliability
- Graceful shutdown handling
- Auto-restart on crash (Docker restart policy or PM2)
- Database migrations run before deploy
- Rollback plan
process.on('SIGTERM', () => {
server.close(() => {
db.end()
process.exit(0)
})
})
FAQ
Which deployment method is best?
Railway for speed. VPS + Docker for control and cost. Fly.io for global distribution. Coolify for Railway experience on your own hardware.
How much does hosting cost?
Small API: $5-20/month (any platform). Medium SaaS: $20-100/month. Scale beyond that: VPS is cheapest.
Do I need Docker?
Not for Railway or Fly.io (they handle containerization). Yes for VPS deployment. Docker ensures your app runs the same everywhere.
How do I handle zero-downtime deployments?
Railway and Fly.io handle this automatically. For VPS: use Docker rolling updates or blue-green deployment with nginx.
Bottom Line
For most Node.js apps in 2026: Railway for the fastest path to production. Fly.io for global deployment. VPS + Docker for maximum control and lowest cost. Coolify for the best of both worlds.
Start with Railway. Move to VPS when you need to optimize costs or need more control.