Node.js is a great platform for rapid application development using the same language (JavaScript) on the server that is used on the client, as well as using the JSON format to exchange data. One issue I have run into with Node is it can be cumbersome when building full-featured web applications. This is where Sails.js enters the picture, as it sits on top of Node and provides an MVC framework analogous to what Rails brings to Ruby. It provides seamless database integration with default support and much more.

Setting sail

Sails.js is easily installed from the command line using the Node package manager (npm) as shown in the following command — note, the g switch signals a global install on the system, thus easily used from a command line. If you’re running on non-Windows, you may need to use sudo to run with elevated privileges.

npm install sails -g

Once installed, you can quickly generate the skeleton for a Sails.js application with the sails new command followed by the project name (Figure A); this creates a directory with the project name that contains all of the assets for the new application. Once a project is created, it can be launched by issuing the lift command in the project directory (Figure B). Figure C shows the application open in the Chrome browser.

Figure A

Creating a new Sails.js application using the new command.

Figure B

Launching Sails.js is simple with the lift command.

Figure C

Viewing a sample application in Chrome.

Sails components

The phrase “convention over configuration” is used a lot when reading about Sails.js (as well as Ruby on Rails), and it basically means fewer decisions for the developer, which theoretically means it’s simpler. Sails.js accomplishes this by providing basic application assets and the plumbing to make everything work. In the MVC paradigm, the user sees the view and uses controllers. Furthermore, the controller manipulates the model that is used to update the view.

  • Model: Data models are backend/database agnostic. They are implemented via the Waterline ORM. It uses adapters to connect to data stores, so you can build your own adapter or use adapters readily available for popular systems including MySQL and Mongo. You are not restricted to one system, as you can have one model use something like MySQL while another uses Mongo or any combination desired.
  • View: These utilize templates via EJS (Embedded JavaScript). This allows you to have static HTML with dynamic content generated via embedded JavaScript.
  • Controllers: Controllers are implemented by way of Express. This is good, as Express is battle tested and popular with great support in the community. The Express middleware simplifies routing, whether it is static files or dynamic content.

A good way to get a feel for how Sails.js works is to look at the files included in an application. Figure D shows the file structure for the example I generated earlier with the most important directories outlined below.

  • api: Contains subdirectories for controllers, models, policies, responses, and services.
  • assets: Contains files and subdirectories of files (JavaScript, CSS, images, ..) to be loaded at runtime. This is where you should place other libraries like jQuery.
  • config: Contains configuration files used by Sails.js. These are very important to the application, as Sails.js promotes flexibility afforded via easily changed configuration files.
  • public: Contains publicly available files such as images and favicon.
  • tasks: Stores grunt tasks and configurations. (Grunt is a workflow system.)
  • tests: Stores unit test files and configurations.
  • views: Contains the application’s views, which are defined in EJS files. Figure D shows this directory expanded with EJS files for the home page as well as error pages (403, 404, and 500) and a standard layout file used by all application pages.

Figure D

Directory structure for a sample Sails.js application.

Controlling what is displayed

A key Sails.js feature is defining routes via controllers that tell the system what to display when certain URLs are entered; this can be accomplished with custom or automatic routes. A good example of a custom route is the home page displayed when my test application was loaded. The routes.js file is displayed in Figure E where it shows that a home page request (the forward slash indicates root) is handled by the homepage view with its details shown in Figure F. You can change what is displayed for home page requests by changing the route defined in the routes.js file as well as adding more routes for other requests.

Figure E

The routes.js file defines how requests are handled by the application.

Figure F

The homepage template file is used to format the default home page.

Routes can also be created automatically with the Blueprint API via the generate command. The following command shows how to generate the API scaffolding for /techrepublic requests.

sails generate api techrepublic

This generates the full range of CRUD operations that use JSON data as well as full WebSockets support. As an example, the following command adds data to the model (by default the disk is used for data storage):

The contents of the data model can be viewed (as JSON) via the base model URL ( in this example) as shown in Figure G.

Figure G

Sample data model loaded in browser.

Off and running

Sails.js was easy to get up and running, and there were plenty of online resources to cover key features. Creating views and controllers were straightforward, but working with a database backend presented a steeper learning curve. Sails.js has a great community including an active Google Group, an IRC Channel (#sailsjs), and plenty of online resoures, so there is plenty of help when you have questions.

This is only the tip of the iceberg with Sails.js, but hopefully it gives you an idea of what it brings to the plate with regards to Node development.