All skills

Sails.js framework patterns for The Boring JavaScript Stack - actions, helpers, routes, policies, hooks, configuration, security, middleware, file uploads, deployment, and more. Use this skill when building, reviewing, or debugging any server-side code in a Sails.js application.

Use this Skill: https://skilld.dev/gh/sailscastshq/boring-stack/sails

This session only. Nothing lands on disk.

rulesdeployment.md

≈1.7k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Deployment

Production Configuration

Production settings go in config/env/production.js. This file is loaded when NODE_ENV=production:

// config/env/production.js
module.exports = {
  // Increase hook timeout for slower startup in production
  hookTimeout: 80000,

  datastores: {
    default: {
      adapter: 'sails-postgresql',
      url: process.env.DATABASE_URL,
      ssl: { rejectUnauthorized: false } // Required for managed databases
    }
  },

  models: {
    migrate: 'safe' // NEVER auto-migrate in production
  },

  blueprints: {
    shortcuts: false // Disable shortcut routes in production
  },

  security: {
    cors: {
      allRoutes: true,
      allowOrigins: [process.env.APP_URL],
      allowCredentials: true
    }
  },

  session: {
    cookie: {
      secure: true, // HTTPS only
      maxAge: 24 * 60 * 60 * 1000 // 24 hours
    }
  },

  http: {
    cache: 365.25 * 24 * 60 * 60 * 1000, // Cache static assets for 1 year
    trustProxy: true // Behind load balancer/reverse proxy
  },

  custom: {
    baseUrl: process.env.APP_URL
  },

  log: {
    level: 'warn' // Less verbose logging in production
  }
}

Migration Strategy

Development: migrate: 'alter' -- Automatically adjusts tables when models change. May lose data on column type changes.

Production: migrate: 'safe' -- Never auto-migrate. You must manage schema changes manually with database migrations.

// config/models.js (development default)
module.exports.models = {
  migrate: 'alter'
}

// config/env/production.js
module.exports = {
  models: {
    migrate: 'safe'
  }
}

Redis Session Store

In-memory sessions don't persist across restarts or scale across multiple processes. Use Redis for production:

npm install @sailshq/connect-redis
// config/env/production.js
module.exports = {
  session: {
    adapter: '@sailshq/connect-redis',
    url: process.env.REDIS_URL,
    cookie: {
      secure: true,
      maxAge: 24 * 60 * 60 * 1000
    }
  }
}

Environment Variables

Use environment variables for all secrets and environment-specific configuration:

# Required in production
NODE_ENV=production
SESSION_SECRET=your-random-session-secret
DATABASE_URL=postgresql://user:pass@host:5432/dbname
APP_URL=https://myapp.com

# Optional
REDIS_URL=redis://user:pass@host:6379
DATA_ENCRYPTION_KEY=base64-encoded-key
STRIPE_SECRET_KEY=sk_live_...

Access in config files:

// config/custom.js
module.exports.custom = {
  baseUrl: process.env.APP_URL || 'http://localhost:1337',
  stripeSecretKey: process.env.STRIPE_SECRET_KEY || ''
}

// config/session.js
module.exports.session = {
  secret: process.env.SESSION_SECRET || 'development-secret'
}

config/local.js

The config/local.js file is gitignored and used for developer-specific overrides:

// config/local.js (gitignored)
module.exports = {
  port: 1338, // Use a different port locally
  datastores: {
    default: {
      url: 'postgresql://localhost/myapp_dev'
    }
  },
  custom: {
    stripeSecretKey: 'sk_test_my_personal_key'
  }
}

Port and Host Configuration

// config/env/production.js
module.exports = {
  port: process.env.PORT || 1337
  // explicitHost: '0.0.0.0'  // Listen on all interfaces (for Docker)
}

Most hosting platforms set PORT automatically (Heroku, Render, Railway, etc.).

Logging Levels

// config/env/production.js
module.exports = {
  log: {
    level: 'warn' // Only warnings and errors
    // Options: 'verbose', 'info', 'debug', 'warn', 'error', 'silent'
  }
}
Level Shows
verbose Everything (very noisy)
info Info, debug, warnings, errors
debug Debug messages, warnings, errors
warn Warnings and errors only (recommended for production)
error Errors only
silent Nothing

Production Security Checklist

  1. migrate: 'safe' -- Never auto-migrate production databases
  2. Session secret -- Use a strong, unique SESSION_SECRET env var
  3. HTTPS -- Set cookie.secure: true in session config
  4. CSRF enabled -- Keep csrf: true in config/security.js
  5. CORS restricted -- Only allow your domain in allowOrigins
  6. Redis sessions -- Use Redis instead of in-memory sessions
  7. Environment variables -- No hardcoded secrets in config files
  8. Data encryption key -- Set via env var, not in source
  9. trustProxy: true -- Enable when behind a reverse proxy
  10. Static asset caching -- Set long cache headers

Process Management

Run Sails in production with a process manager:

# Using PM2
pm2 start app.js --name "myapp" -i max

# Using Node directly (for Docker)
NODE_ENV=production node app.js

Docker Deployment

FROM node:20-slim

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

ENV NODE_ENV=production
EXPOSE 1337

CMD ["node", "app.js"]

Health Check Endpoint

Add a simple health check route for load balancers:

// config/routes.js
'GET /api/health': { action: 'health-check' }

// api/controllers/health-check.js
module.exports = {
  exits: {
    success: { responseType: '' }  // Raw JSON
  },
  fn: async function () {
    return {
      status: 'ok',
      timestamp: Date.now(),
      uptime: process.uptime()
    }
  }
}

Scaling

Sails apps scale horizontally. Key requirements for multiple processes:

  1. Shared sessions -- Use Redis session store (not in-memory)
  2. Shared uploads -- Use cloud storage (S3) instead of local filesystem
  3. No in-process state -- Store everything in the database or Redis
  4. Sticky sessions -- Not required if using Redis sessions

Database Configuration for Production

PostgreSQL

// config/env/production.js
datastores: {
  default: {
    adapter: 'sails-postgresql',
    url: process.env.DATABASE_URL,
    ssl: process.env.DATABASE_SSL === 'true'
      ? { rejectUnauthorized: false }
      : false
  }
}

MySQL

datastores: {
  default: {
    adapter: 'sails-mysql',
    url: process.env.DATABASE_URL
  }
}

SQLite (Development/Small Apps)

// config/datastores.js (default in Boring Stack)
datastores: {
  default: {
    adapter: 'sails-sqlite'
    // Uses ./db/local.db by default
  }
}

Source: SKILL.md on GitHub

1 alert17d4 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides comprehensive documentation and coding patterns for the Sails.js framework as used in The Boring JavaScript Stack. It includes detailed guides on application anatomy, security best practices, and production deployment. No malicious patterns or security vulnerabilities were detected.

  • Socket17d

    2 alerts: gptSecurity

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    13/20 files flagged

Signed by skilld at bf19e10. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 8 months ago
Other metadata
metadata
{
  "author": "sailscastshq",
  "version": "2.1.0",
  "tags": "sails, sailsjs, backend, mvc, actions, helpers, routes, policies, hooks, middleware, deployment, boring-stack"
}

README badge

README badge for sailscastshq/boring-stack/sails