← Back to Tutorials Chapter 10

Deployment

Environment Variables

Environment variables keep configuration separate from code. Never hard-code secrets.

# .env file (never commit this!)
PORT=3000
NODE_ENV=production
DATABASE_URL=mongodb://...
JWT_SECRET=your-secret-key
API_KEY=abc123

// Install: npm install dotenv
// Load in code
require('dotenv').config();

console.log(process.env.PORT);
console.log(process.env.NODE_ENV);

.env.example (commit this)

PORT=3000
NODE_ENV=development
DATABASE_URL=your-database-url
JWT_SECRET=your-secret
API_KEY=your-api-key

Development vs Production

AspectDevelopmentProduction
Error DetailFull stack tracesLimited, user-friendly
Logging LevelVerbose (debug, info)Minimal (warn, error)
Auto-reloadEnabled (nodemon)Disabled
CachingMinimalAggressive
MinificationNoYes

CI/CD Pipeline

A typical CI/CD pipeline for Node.js applications includes linting, testing, building, and deploying.

# .github/workflows/deploy.yml
name: Node.js CI/CD

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm test
      - run: npm run build --if-present

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: |
          # Deploy to your hosting provider
          echo "Deploying..."

Security Best Practices

// Security setup example
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

app.use(helmet());
app.use(rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100,
  message: 'Too many requests, please try again later.'
}));

Deployment Strategies

# Example Dockerfile
FROM node:20-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

EXPOSE 3000
CMD ["node", "src/index.js"]
Exercise: Create a Dockerfile for your Express.js task API. Add a .dockerignore file, multi-stage build, and use a non-root user. Then push it to a container registry and deploy to a cloud provider.