Getting Started with Hapi.js

Draft updated on Invalid Date

    Shreyansh Pandey

    Getting Started with Hapi.js

    This tutorial is out of date and no longer maintained.


    Separation of Concerns is the in thing these days, and with the introduction of RESTful architecture, it has been a cakewalk; however, new developers often face the dilemma of choosing their weapons. The frameworks, and the suite of tools they will use to develop their next killer application.

    Not long ago, I was one of them, and then I came across this excellent talk by Eran Hammer from WalmartLabs and decided that Hapi.js was the way to go. The problem with Hapi.js is that it is simple and complicated at the same time. Honestly, I find it cleaner and easier than Express.js, and you will see why I say that once we’re done with this segment.

    Our goal

    Everyone hates a tutorial that just contains some incoherent code and expects you to follow along. And hence, we will actually make something; by the end of this series, we will have a fully functional application to add pictures of cute cats. (Really, this is the kind of application I want to work on.)

    Since covering everything in one long post will be anything but smart (and because we love a “modular approach”), I have broken this tutorial in 2 parts. In sequence, the following will be the outline:

    • Part 1 - a gentle introduction to Hapi.js; we set up the environment and all the dependencies; simple Hello World;
    • Part 2 - creating a fully blown RESTful API using Hapi.js

    Note: The second part is up at Making a RESTful API with Hapi.js.

    After deployment, we will have a fully functional and consumable API with all the goodies. So, what are we waiting for? Let’s get started.

    What is Hapi.js?

    hapi.js Website

    Hapi (pronounced “happy”) is a web framework for building web applications, APIs, and services. It’s extremely simple to get started with and extremely powerful at the same time. The problem arises when you have to write performant, maintainable code.

    Let’s Start

    With that said, let’s dive straight in. But before we get to coding, let me explain what our development environment will look like.

    I am a fan of ES6, and really, I can’t write code in the old ES5 syntax. I will show you a really quick way to get started with ES6 without the transpiling part. That’s great: it means that you don’t have to run gulp build:development every time you make a change.

    We’ll use Babel for on-the-fly transpilation of the ES6 code. I say on the fly simply because there is no direct output; if you’re familiar with CoffeeScript’s require hook, it’ll be just like that. If you are not, then don’t worry because this is really, really simple.

    Directory Structure

    For starting out, we’ll have a fairly simple directory structure with just one src folder, and all of the program files will reside in that folder. In the root folder, we’ll have all other build toolchain files.

    Start by finding the directory of your choice, and point your terminal to it. I love the command line, so I do:

    1. mkdir getting-started-with-hapi-js-part-1 && cd $_
    2. mkdir src
    3. touch .babelrc .gitignore .jshintrc src/server.js

    Notice the $_. This means, use the last argument of the last command. So, this will turn to cd getting-started-with-hapi-js-part-1 An interesting shorthand.

    Let’s examine the dotfiles I have created:

    • .gitignore – tell Git what all to ignore;
    • .babelrc – tell the BabelJS transpiler which presets and/or plugins to use;
    • .jshintrc – tell our linter (JSHint) what all we expect from it.

    With that done, execute in the root directory:

    1. npm init

    Fill in all the details; it should look something like the following:

      "name": "getting-started-with-hapi-js-part-1",
      "version": "1.0.0",
      "description": "Getting started with Hapi.js -- Part 1",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      "repository": {
        "type": "git",
        "url": "git+https://github.com/labsvisual/getting-started-with-hapi-js-part-1.git"
      "author": "Shreyansh Pandey",
      "license": "MIT",
      "bugs": {
        "url": "https://github.com/labsvisual/getting-started-with-hapi-js-part-1/issues"
      "homepage": "https://github.com/labsvisual/getting-started-with-hapi-js-part-1#readme"

    Oh, before I forget, all of the code is available at the GitHub repository.

    Now, open your favorite text editor in the root directory. Your directory structure should look something like the following:


    Perfect. Now, let’s install the dependencies. We’ll go with the real basics which are required to spin up a simple Hello World along with some decoration to that. Right now, we’ll just install babel-core, babel-preset-es2015, and hapi.

    For those that don’t know, Babel is a transpiler that helps us convert ES6 JS code to ES5 code.

    Run in the root directory:

    1. npm install --save babel-core babel-preset-es2015 hapi

    And wait for the dependencies to finish installing.

    Then, let’s prepare our .babelrc, .gitignore, and our .jshintrc files. The configuration here is really simple, but you can always tweak it to your requirement.

    In the .babelrc file, we need to tell Babel we are using the es-2015 preset. A preset is a set of transformations which something should go through so that it’s converted to something else. Here, for example, the es-2015 preset includes all the transforms to convert the fancy ES6 functions to their respective ES5 equivalent.

    Add the following to the .babelrc file:

        "presets": [ "es2015" ]

    Yeah, really! That’s it.

    In the .gitignore file, we want to exclude the node_modules folder, so adding node_modules to that file will do the job.

    Lastly, .jshintrc needs to know just one thing: we’re using ES2015. For that, add the following snippet to the file:

        "esnext": true

    And that’s it. We’re done with our initial configuration. Now let’s write some code.

    Bootstrapping for ES6

    Lastly, we need to create a bootstrap.js file which will require the babel-core’s registering module, and the main module from our code: in this case server.js. And, we’ll also create a very simple shortcut in the package.json file so that we can just run npm start to fire up our Hapi.js project.

    Start by creating a bootstrap.js file in the root folder, and add the following two lines:

    require( 'babel-core/register' );
    require( './src/server' );

    The first line calls for the babel register module, which then loads the server module. This helps Babel in transpiling on the fly. Simple, eh?

    Getting Lazy with package.json

    Node has a concept of scripts; you can define them in the scripts section of the package.json file. Modify the existing scripts section to look something like this:

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "node bootstrap.js"

    Now, run in the command line:

    1. npm start

    And your output should resemble something like below:

    1. getting-started-with-hapi-js-part-1@1.0.0 start /path/to/getting-started-with-hapi-js-part-1
    1. node bootstrap.js

    Nothing happened? Well, that’s because we don’t have any code, don’t worry. However, if there is some error, be sure to check and see if you have followed all the steps outlined here.

    Introduction to the Terms

    Before we get Hapi-specific, let’s have a look at the terms the framework throws at us. Don’t worry, there are only three main terms.

    • server – the root object which contains everything about the web application;
    • connection – an instance of a connection, usually a host and a port where the requests will come to;
    • route – a URI within a connection telling the server which function to execute when;

    Create a Simple Hello World server

    Alright, now we come to the best part: creating the actual server. In this part, we’ll only create a few example routes to see what all Hapi has to offer; we’ll modify this in the next parts and soon, it’ll start looking like our application.

    So, start by importing Hapi into the server.js file:

    import Hapi from 'hapi';

    Perfect. Now, we’ll create a new server instance, and attach a new connection to it. Add the following bit to create a new server instance:

    const server = new Hapi.Server();
    server.connection( {
        port: 8080

    Now, I have skipped the host field because that’s a known bug. I can’t find a link right now, but I will update the post once I find the official link to the bug.

    Cool! Now, run your server by typing from the command line:

    1. npm start

    And yet again, there is no output. That’s because we haven’t yet started the server, nor have we defined a route. Let’s define a simple hello route:

        method: 'GET',
        path: '/hello',
        handler: ( request, reply ) => {
            reply( 'Hello World!' );

    The block here is self-explanatory, apart from maybe the handler. The handler is the function that is executed when the specific path is hit. So, in this case, the anonymous function will be executed if the user visits the path /hello.

    The request parameter represents the entire request: it has the query strings, the URL parameters, and the payload (if it’s a POST/PUT request; we’ll see this later).

    The reply object helps in sending a reply back to the client. Here, we’re just sending back a simple Hello World! reply. Nothing special.

    Lastly, let’s write the code to start the server.

    server.start(err => {
        if (err) {
            // Fancy error handling here
            console.error( 'Error was handled!' );
            console.error( err );
        console.log( `Server started at ${ server.info.uri }` );

    The server.info property contains an object which contains the following information:

    • created - the time the server instance was created;
    • started - the time the server instance was started;
    • host - the hostname of the machine;
    • port - the port to which the server the server is listening ;
    • protocol - the protocol on which the server is operating;
    • id - a unique ID of the server instance;
    • uri - the complete URI of the current server instance;
    • address - the address the server is bound to

    Now, run npm start; the console will say something like

    Server started at http://example.local:8080

    If that’s the case, then point your browser to localhost:8080/hello and hit enter. You’ll see a page something like the following:


    If you see errors like the following:

    Error was handled!
    {[Error: listen EADDRINUSE]
      code: 'EADDRINUSE',
      errno: 'EADDRINUSE',
      syscall: 'listen',
      address: '',
      port: 8080 }

    It means that some application is using port 8080, try a different port and your application should work flawlessly.

    You can play around with it, but when you are done, hit CTRL+C to exit out of the server.


    I guess that got your feet wet, and you are excited to try out this exciting framework. In the upcoming tutorials, we’ll have a look at all the goodies in the request object; try out different request verbs, and use Paw to test our URLs.

    If you get stuck, be sure to check the API documentation; they have some really good explanations there.

    Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

    Learn more about us

    About the authors
    Default avatar
    Shreyansh Pandey


    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
    Leave a comment

    This textbox defaults to using Markdown to format your answer.

    You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Featured on Community

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more
    DigitalOcean Cloud Control Panel