HTTP/2 server-push for hapi
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.


HTTP/2 server-push for hapi

Build Status Coverage Status

Lead Maintainer - Devin Ivy


See also the API Reference

Underdog brings HTTP/2 server-push to hapi v17+. The way it works is that you specify paths to resources that you'd like to push alongside a particular response. This is achieved with a call to the response toolkit decoration h.push(). Before hapi responds to the original request, those push-requests will be made internally and their results will be streamed to the client as push-responses. Even pushed resources can specify additional resources to push. You can't make this stuff up!


const Fs = require('fs');
const Http2 = require('http2');
const Hapi = require('hapi');
const Underdog = require('underdog');

(async () => {

    const listener = Http2.createSecureServer({
        // See tests for a key/cert that you can use to try this out
        key: Fs.readFileSync(`${__dirname}/localhost.key`),
        cert: Fs.readFileSync(`${__dirname}/localhost.cert`)

    const server = Hapi.server({
        tls: true,
        port: 3000

    await server.register(Underdog);

            method: 'get',
            path: '/',
            handler: (request, h) => {

                const response = h.response('<script src="/push-me.js"></script>');

                h.push(response, 'push-me.js');

                return response;
            method: 'get',
            path: '/push-me.js',
            handler: (request) => {

                return 'document.write(\'I was definitely pushed!\');';                
            // To demonstrate that it must have been pushed, not requested directly
            config: { isInternal: true }

    await server.start();

    console.log(`Check-out ${} in your favorite HTTP/2-supporting client`);


Underdog is compatible with nodejs's Http2Server and Http2SecureServer under the Compatibility API. Using any other HTTP server will simply disable server-push; h.push() will no-op and return { response, allowed: false } and h.pushAllowed() will return false.


  • The HTTP/2 spec (here)
  • For debugging HTTP/2 in Chrome, see chrome://net-internals/#http2
  • Nodejs's HTTP/2 docs (here)
  • Shout-out to the original userland spdy and http2 modules.