API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)
—
Sails.js includes 18+ built-in hooks that provide core framework functionality, from HTTP server management to automatic API generation. Hooks follow a standardized lifecycle and can be extended or customized to modify framework behavior.
All hooks inherit from a common base class with standardized lifecycle methods:
// Hook constructor factory
function Hook(definition: Dictionary): Hook
// Hook lifecycle methods
Hook.defaults(): Dictionary
Hook.configure(): void
Hook.loadModules(cb: Function): void
Hook.initialize(cb: Function): voidHooks execute in a specific sequence during application startup:
hook.identity // String - Hook name/identifier
hook.config // Dictionary - Hook-specific configuration
hook.middleware // Dictionary - Hook middleware functions
hook.routes // Dictionary - Hook route definitions
hook.routes.before // Routes bound before app routes
hook.routes.after // Routes bound after app routesPurpose: HTTP server and middleware management
Location: /lib/hooks/http/index.js
// Default configuration
{
port: 1337,
explicitHost: undefined,
ssl: {},
paths: { public: '.tmp/public' },
http: {
middleware: {
order: ['cookieParser', 'session', 'bodyParser', 'compress', 'faveicon', 'router', 'www', 'methodOverride']
},
cache: 1, // 1ms in development, ~1 year in production
trustProxy: false
}
}Key Features:
Configuration Example:
// config/http.js
module.exports.http = {
port: 3000,
middleware: {
order: ['cookieParser', 'session', 'myCustomMiddleware', 'bodyParser', 'router'],
myCustomMiddleware: (req, res, next) => {
console.log('Custom middleware executed');
next();
}
},
trustProxy: true
};Purpose: Automatic REST API generation for models
Location: /lib/hooks/blueprints/index.js
// Default configuration
{
blueprints: {
actions: false, // Action shadow routes
shortcuts: true, // GET-only CRUD shortcuts
rest: true, // RESTful routes
prefix: '', // Route prefix
restPrefix: '', // REST-specific prefix
pluralize: false, // Pluralize model names in URLs
autoWatch: true // Auto-subscribe to model changes
}
}Generated Actions:
create - Create new recordfind - Find records with filteringfindOne - Find single record by IDupdate - Update existing recorddestroy - Delete recordpopulate - Populate associationsadd - Add to collection associationremove - Remove from collection associationreplace - Replace collection associationRoute Generation Examples:
// For User model, generates:
// RESTful routes (rest: true)
'GET /user' → UserController.find
'POST /user' → UserController.create
'GET /user/:id' → UserController.findOne
'PUT /user/:id' → UserController.update
'DELETE /user/:id' → UserController.destroy
// Shortcut routes (shortcuts: true)
'GET /user/find' → UserController.find
'GET /user/create' → UserController.create
'GET /user/update/:id' → UserController.update
'GET /user/destroy/:id' → UserController.destroy
// Action routes (actions: true)
'GET /user/customAction' → UserController.customActionPurpose: CORS and CSRF protection
Location: /lib/hooks/security/index.js
Sub-hooks:
Configuration Example:
// config/security.js
module.exports.security = {
cors: {
allRoutes: true,
allowOrigins: ['http://localhost:3000', 'https://myapp.com'],
allowCredentials: false,
allowRequestMethods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
allowRequestHeaders: 'content-type'
},
csrf: {
grantTokenViaAjax: true,
origin: 'https://myapp.com'
}
};Purpose: View engine configuration and rendering
Location: /lib/hooks/views/index.js
Key Features:
Configuration Example:
// config/views.js
module.exports.views = {
engine: 'ejs',
layout: 'layouts/layout',
extension: 'ejs',
// View locals available to all templates
locals: {
siteName: 'My Sails App',
title: 'Welcome'
}
};Purpose: Session management and storage
Location: /lib/hooks/session/index.js
Key Features:
Configuration Example:
// config/session.js
module.exports.session = {
secret: 'your-session-secret',
adapter: 'redis',
host: 'localhost',
port: 6379,
db: 0,
cookie: {
secure: false, // Set true for HTTPS
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}
};Purpose: Logging system setup
Location: /lib/hooks/logger/index.js
// Default configuration
{
log: {
level: 'info' // silly, verbose, info, warn, error, silent
}
}
// Available log methods
sails.log.error() // Error level
sails.log.warn() // Warning level
sails.log.info() // Info level (default)
sails.log.verbose() // Verbose level
sails.log.silly() // Debug level
sails.log.ship() // ASCII art ship (special method)Features:
Purpose: Policy enforcement middleware
Location: /lib/hooks/policies/index.js
Key Features:
api/policies/Configuration Example:
// config/policies.js
module.exports.policies = {
'*': 'isLoggedIn', // Apply to all controllers
UserController: {
'*': 'isLoggedIn', // All actions
'create': ['isLoggedIn', 'isAdmin'], // Multiple policies
'find': true // Open access
},
'user/profile': 'isOwnerOrAdmin' // Standalone action policy
};Purpose: Service auto-loading and global exposure
Location: /lib/hooks/services/index.js
Key Features:
api/services/Service Example:
// api/services/EmailService.js
module.exports = {
sendWelcomeEmail: async function(userEmail, userName) {
// Email sending logic
console.log(`Sending welcome email to ${userEmail}`);
return { sent: true };
},
sendPasswordReset: async function(userEmail, resetToken) {
// Password reset email logic
return { sent: true, token: resetToken };
}
};
// Usage anywhere in the app
await EmailService.sendWelcomeEmail('user@example.com', 'John');Purpose: Helper function loading and management
Location: /lib/hooks/helpers/index.js
Key Features:
api/helpers/Helper Example:
// api/helpers/format-date.js
module.exports = {
friendlyName: 'Format date',
description: 'Format a date for display',
inputs: {
date: {
type: 'ref',
required: true
},
format: {
type: 'string',
defaultsTo: 'YYYY-MM-DD'
}
},
fn: async function(inputs) {
const moment = require('moment');
return moment(inputs.date).format(inputs.format);
}
};
// Usage
const formatted = await sails.helpers.formatDate(new Date(), 'MMM DD, YYYY');Purpose: Internationalization and localization support
Location: /lib/hooks/i18n/index.js
Key Features:
Configuration Example:
// config/i18n.js
module.exports.i18n = {
locales: ['en', 'es', 'fr'],
defaultLocale: 'en',
directory: './config/locales',
// Request locale detection
requestLocaleProperty: 'locale',
queryParameter: 'lang'
};Purpose: User configuration loading
Location: /lib/hooks/userconfig/index.js
Features:
Purpose: Custom user hook loading
Location: /lib/hooks/userhooks/index.js
Features:
api/hooks/Purpose: Dynamic module loading infrastructure
Location: /lib/hooks/moduleloader/index.js
Features:
Purpose: Request object enhancement
Location: /lib/hooks/request/index.js
Features:
Purpose: Response method injection
Location: /lib/hooks/responses/index.js
Features:
api/responses/Default Response Methods:
res.ok() // 200 - Success
res.created() // 201 - Created
res.badRequest() // 400 - Bad Request
res.unauthorized() // 401 - Unauthorized
res.forbidden() // 403 - Forbidden
res.notFound() // 404 - Not Found
res.serverError() // 500 - Internal Server ErrorPurpose: Publish/Subscribe functionality
Location: /lib/hooks/pubsub/index.js
Features:
Usage Example:
// Subscribe to model updates
User.subscribe(req, [userId]);
// Publish model changes
User.publishUpdate(userId, { status: 'active' });
// Room-based messaging
sails.sockets.join(req, 'chatroom1');
sails.sockets.broadcast('chatroom1', { message: 'Hello!' });Custom hooks are created in the api/hooks/ directory:
// api/hooks/my-hook/index.js
module.exports = function myHook(sails) {
return {
// Hook configuration defaults
defaults: {
myHook: {
enabled: true,
customSetting: 'default-value'
}
},
// Configuration normalization
configure: function() {
// Validate and normalize config
if (!sails.config.myHook.enabled) {
console.log('MyHook is disabled');
}
},
// Module loading
loadModules: function(cb) {
// Load additional modules if needed
return cb();
},
// Hook initialization
initialize: function(cb) {
console.log('MyHook initialized');
// Add custom functionality to sails
sails.myCustomMethod = function() {
return 'Custom functionality';
};
return cb();
},
// Custom hook routes
routes: {
before: {
'GET /hook-test': function(req, res) {
return res.json({ hook: 'MyHook responding' });
}
}
}
};
};Custom hooks can be installed via npm:
npm install sails-hook-my-custom-hookOr developed locally in api/hooks/my-hook/.
Hook behavior can be controlled through configuration:
// config/my-hook.js
module.exports.myHook = {
enabled: true,
customSetting: 'production-value',
// Environment-specific settings
environments: {
development: {
enabled: true,
debugMode: true
},
production: {
enabled: true,
debugMode: false
}
}
};Hooks can be configured to load only in specific environments:
module.exports = function(sails) {
return {
// Only load in development
configure: function() {
if (sails.config.environment !== 'development') {
return;
}
}
};
};Hooks can specify dependencies on other hooks:
module.exports = function(sails) {
return {
dependencies: ['orm', 'http'],
initialize: function(cb) {
// This hook will only initialize after orm and http hooks
return cb();
}
};
};The Sails.js hook system provides a powerful and flexible architecture for extending framework functionality, with comprehensive built-in hooks covering all core web application needs and extensive customization capabilities.
Install with Tessl CLI
npx tessl i tessl/npm-sails