A Simple Website in Node.js with Express, Jade and Stylus

A Simple Website in Node.js with Express, Jade and Stylus

Update: You might like to know that I’ve written a follow up to this post – A Simple Website in Node.js – 2016 Edition

Do you feel like you've missed the boat on Node? Perhaps you're not a superstar web app developer, but a humble builder of websites. Maybe you're a fledging front-end developer: you've got your head around JavaScript and you want to build a site yourself, but you don't know PHP, Python or Ruby. Fear not. This post will use the popular Express framework to show you how you can build simple websites in Node. If you're looking for real-time webapp action, then take your hipster boots and move along… this is a websites in Node 101.

In this post we will:

  • Download and install Node and npm
  • Create a basic website

Getting started

First of all, we need Node. Get pre-compiled binaries for Mac & Windows from http://nodejs.org/#download . (If you run Linux, you'll need fly solo for a bit and compile it yourself). Node comes with a package manager called 'npm', which is used to install modules. From here on in, I am going to write from the point of view for a Mac user, simply because that is what I use. The process on Linux should be near identical. It will be a similar process on Windows as Node and npm have a consistent interface, but things will definitely vary. Hopefully you can still follow along.

Open up a terminal and type node -v and npm -v to ensure it's installed ok.

Creating project skeleton

Create a folder anywhere you like, and call it anything you like, e.g.:

cd ~/Projects
mkdir MySite
cd MySite

Make sure you're inside this folder. This will house all of our files. Create a file called package.json with the following contents:

  "name": "MySite",
  "version": "0.0.1",
  "private": "true",
  "dependencies": {
    "express": "3.0.0alpha4",
    "jade": "^1.0.4",
    "stylus": "^0.49.1",
    "nib": "^1.0.4"

This file tells npm about your project. If you then do npm install in the project root, it will install the dependencies that are listed. The dependencies are listed by name and version. In proper projects, it is good to specify a version, however, the '*' means that any version will do and npm will retrieve the latest; this is ok for now. Update: Since this article has been around a long time, the '*' turned out to be a bad idea. I'd now always recommend specifying a version. Npm installs modules locally in a folder called 'node_modules'. The private flag ensures that our site doesn't get accidentally published to the npm directory.

Here's a little info about our dependencies:


Express is a web framework, inspired by the Ruby project 'Sinatra'. It's one of many web frameworks in Node, but is the the most popular, and in my opinion the most easy to learn. Other frameworks that are worth checking out once you have got to grips with Node include: Flatiron, Geddy, and Taco.


Jade is a templating engine. It is a language that compiles to HTML. It's a really great way of separating your logic from your markup. If you've dabbled in PHP, you'll know the problem I'm talking about. Jade is awesome. Some people are put off its whitespace-significant syntax, but I recommend giving it a go. It's very clean, and you'll never write a malformed HTML document again! (You'll never have to type angle brackets ever again).


Stylus is a CSS-preprocessor. If you're familiar with LESS or SASS, Stylus does very much the same job (if not, Stylus is a language which compiles down to CSS for the browser; it adds new features that make CSS easier to work with). In my opinion, Stylus trumps the other pre-processors out there. It doesn't force a certain syntax upon you (you can use plain CSS syntax if you like, but I prefer the colon, semi-colon and curly brace free option). For more info on what Stylus can do, see the website and a blog post of mine on some of the lesser-know, but very useful features.


Nib is a set of utilities for Stylus. Among other things, it enables going vendor-prefix free, which in my eyes makes it worthwhile alone.

Getting up and running with Express

Express comes with a utility for creating a site skeleton. However, since we're in the business of learning, we'll create everything from scratch.

Create a file called app.js in the project root, and open it up in your favourite text editor. First things first, we need to require our modules that we installed with npm:

 * Module dependencies
var express = require('express')
  , stylus = require('stylus')
  , nib = require('nib')

Next, we want to fire up Express, tell it to use Jade and Stylus, and some other basic functionality:

var app = express()
function compile(str, path) {
  return stylus(str)
    .set('filename', path)
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
  { src: __dirname + '/public'
  , compile: compile
app.use(express.static(__dirname + '/public'))

The app.set() directives tell Express that we want to use Jade, and where we will keep our views. On that note, let's create a folder called 'views' in the project root where we will put our Jade files.

The app.use() calls pass 'middleware' functions for Express to use. Middleware are simply functions that have the signature fn(req, res, next). They take the request object, the response object and next, which will call the next piece of middleware. Express executes them in the order in which they are passed, and any of them may send a repines, preventing the execution of any remaining in the series (by not calling next()).

The first piece of middleware we apply is the Express logger in 'dev' mode. This will simply log incoming requests to the console. Next, the Stylus middleware is applied, which will compile our .styl files to CSS. In order to use nib, we pass in a custom compile function to the Stylus middleware. After that it's the Express static middleware, which is used for serving static files (we tell it that our static files will live in a folder called 'public', so lets create that in the project root now). You might be wondering why we need this. Unlike Apache, the Express server doesn't mimic the filesystem to the visitor. This allows great flexibility for the url structure of your site, but it's quite a useful feature for serving static assets, so the static middleware does exactly this on the directory that we pass. A file 'pic.jpg' in a folder 'images' within 'public' will be available to the client at '/images/pic.jpg'.

By now, you might be eager to run something. Finish off app.js with the following code:

app.get('/', function (req, res) {
  res.end('Hi there!')

This creates a 'route', simply a function which takes the request and response object, and sends the plain-text response 'Hi there!'. We then tell the Express application to listen on port 3000.

If you run node app.js in the terminal, then navigate to http://localhost:3000/ in your browser, you should see the plain-text response.

Creating some content

Now for some actual web content. First up, lets create a template with our site's markup skeleton. Create a file called 'layout.jade' inside the views directory. Open it up and fill it with the following contents:

    title #{title} - My Site
    link(rel='stylesheet', href='/stylesheets/style.css')
      h1 My Site
        block content
        block sidebar
      p Running on node with Express, Jade and Stylus

Even if you're not familiar with Jade, hopefully you'll be able to get an idea of what's going on here. Firstly, the !!!5 part tells Jade to output the HTML5 doctype . Then, each word beginning a line represents a tag. Indentations after that line denote the tag's content, so rather than having to close a tag, you just stop indenting lines. Within the head tag we output the contents of a title variable with #{title} -- you'll see later on where this gets defined. We are also linking to the place we expect our compiled Stylus to be. The only thing left to explain here is block. Since we won't be filling in this file with our page contents, we can denote blocks. Templates which inherit from this one can define their own content to be output within these blocks.

If you're feeling a bit confused or just want to know more about Jade, then head over to the docs .

Next we want to fill in these blocks with some content. Create a file named 'index.jade' inside 'views'. Populate it with this:

extend layout
block content
    | Vivamus hendrerit arcu sed erat molestie
    | vehicula. Sed auctor neque eu tellus
    | rhoncus ut eleifend nibh porttitor. Ut in.
    | Donec congue lacinia dui, a porttitor
    | lectus condimentum laoreet. Nunc eu
    | ullamcorper orci. Quisque eget odio ac
    | lectus vestibulum faucibus eget in metus.
    | In pellentesque faucibus vestibulum. Nulla
    | at nulla justo, eget luctus tortor.
block sidebar
    h1 Widget
      | Sed auctor neque eu tellus rhoncus ut
      | eleifend nibh porttitor. Ut in nulla enim.
      | Vivamus hendrerit arcu sed erat molestie
      | vehicula.

You can see that the first thing we are doing is extending layout. This will output all of the content of layout.jade, and allow us to define content to be output in place of the blocks that we defined.

Lastly we want to hook up our stylesheet. Create a folder called 'stylesheets' within 'public', and create a file called 'style.styl'. The Stylus middleware will compile it into a CSS file of the same name, in the same directory.

Feel free to freestyle on this bit, and style up the content yourself. Otherwise grab the contents of my stylesheet , which has some comments about the Stylus features it's using.

So now we have our view and stylesheet in place, let's revisit 'app.js' and tell it what to render.

Replace the app.get('/', …) part with this:

app.get('/', function (req, res) {
  { title : 'Home' }

There's that title variable we talked about earlier on. The functionres.render() is provided by Express and takes the name of the view to render, followed by an object whose properties the view will have access to (the properties of this object are sometimes known as 'locals').

Now run the app again, using node app.js. If it's still running from before, quit it with ctrl-c. It's worth mentioning here that any change to JS files that Node will run will require a restart of the app. When in development, we use nodemon which will watch for changes and restart the app for us.

If you used my stylesheet, navigating to http://localhost:3000/ should result in something like this:

What the site should look like…

So there we have it. A simple website in Node. Hopefully you've been able to follow along, and were able to get the site running. If not, this project is over on GitHub . You can check that out, run it and have a poke around. In a future blog post, we'll look at the various options for deploying and hosting Node sites. If you have any questions, then give me a shout in the comments.

Want to discuss a project?

Got a question? Want some more detail? We'd love to hear from you, contact Jason on +44 (0)1923 261166 or jason.treloar@clock.co.uk.


Screen Shot 2016-05-13 at 12.44.37.pngRead
16 May 2016

How to build, test, share and publish a javascript Hybrid mobile application using Cordova

Mobile Applications (Apps) are something every developer wants to create, however, not every developer wants to have to learn multiple languages to be able to create an App which works across different types of devices, such as Android and iOS. Learning Objective C (or Swift) and Java is probably enough to put most people off the idea of creating a cross-platform App. However, it’s possible to create one using technologies which most developers are familiar with. Good old HTML, CSS and JavaScript is all you need. Well, that and Apache Cordova, the mobile application development framework that allows you to build Apps for multiple platforms using a single code base.

26 April 2016

MongoDB Performance on ZFS and Linux

Here at Clock we love ZFS, and have been running it in production on our Linux file servers for several years. It provides us with numerous excellent features. With the recent release of Ubuntu Xenial 16.04 official support for ZFS is now here, and we are keen to integrate it fully into our next generation hosting stack.

node blog post.jpgRead
9 March 2016

A Simple Website in Node.js – 2016 Edition

Four years ago I wrote a post on how to build a simple website in Node.js. Seeing as it’s still the most popular article on this blog, I thought I’d take a look at how things have evolved, what I would do differently today, and some additional nuggets of advice.

24 February 2016

JavaScript Frameworks in 2016

As JavaScript's popularity continues to grow and with it, the surrounding ecosystem of modern libraries & tools, it can sometimes be hard to keep-up, leading to what some describe as JavaScript Fatigue. This post will delve into some of the advances we're seeing in the JavaScript community and how such solutions may benefit you and your team, without making you fatigued.

Come and work for Clock

Clock is made up of bright, hard-working and talented people and we're always on the look out for more. You can browse the current jobs below or follow us @clock for the latest vacancies.

View Latest