Node.js Feature Flags: a Practical Getting Started Guide with an Express.js Example

By
Geshan Manandhar
on
October 29, 2021

Feature flags help us turn a feature on or off without the need to deploy any code. Node.js feature flags also enable the same. In this guide, we will go through a practical example in a Node.js express application to show and hide some footer icons depending on a Flagsmith feature flag. Let’s get rolling!

Prerequisites

Before jumping to the code, below are some of the prerequisites for getting started with the flags:

  1. A Flagsmith account will be used to create a feature flag so register now if you haven’t already, it’s free! 
  2. Prior general knowledge of Node.js and Express.js
  3. Any knowledge of Git and GitHub would be really helpful
  4. You will need a GitHub account to clone the demo repository and deploy code to Railway.app

Example: Express single-page application for Node.js feature flags

Time to dive into the code!

For this hands-on guide, we will use a pre-built Express application. This Node.js application was built as a demo to build a single-page website. This step-by-step tutorial explains how to build a single-page website with Express.js and Pug as the templating library. The demo website looks like the below:

Podcast homepage

It is a mock “Coming Soon” page with a form to collect email addresses (though it doesn’t really collect the email addresses at this point.)

The goal here is to show/hide the four icons; Twitter, Instagram, GitHub, and Email, using a feature flag. We will create the feature flag on Flagsmith and use Node.js to show or hide those icons depending on whether the feature flag is enabled or not. Hypothetically we want the user to focus on giving us their email address vs. being diverted to the social channels. But if we change our minds we want to be able to get the icons in the footer back without the need to deploy any code.

After doing the code change we will deploy the application to Railway.app free plan. In the following section, we will set up the feature flag on Flagsmith.

Set Up Feature Flags in Flagsmith

To create a feature flag for toggling the visibility of the social icons on the footer, we will first need to create a project after logging into Flagsmith. This can be done by clicking the “Create Project” button found at the top right side of the Projects page as seen below:

GIF of creating a flagsmith project

I have named id `eventually-podcast` but it is up to you to name it as you like. The project page looks like the following after the project is successfully created:

Flagsmith application feature setup

Now we will create a new feature flag by hitting the “Create Your First Feature” button and filling in the details as follows:

Creating a new feature in Flagsmith

So, we will create our first feature flag named `show_footer_icons` which is enabled by default, and has no value, and we have added a description to help us know in the future what it is used for. It will look like the following when the feature flag is created:

managing features in flagsmith screenshot

Note: We have two environments - development and production. We will make use of them later.

In the next section, we will clone (or fork) the open-source Node.js express application and add Flagsmith Node.js SDK to it to use the feature flag we just created as part of this Node.js feature flags tutorial.

Install Flagsmith Node.js Client

To proceed further with this tutorial you can clone the open-source repository that has the “Eventually Podcast” landing page running. To do that we will need to run the following command:

 
git clone git@github.com:geshan/nodejs-express-tutorial.git

Then we will go into the directory, install the NPM dependencies and run the app to test by running:

 
cd nodejs-express-tutorialnpm installnpm start

It will start the server on the master branch and if you go to http://localhost:3000 in your favorite browser you will see something like the below:

Eventually podcast homepage

Consequently, you can stop the server and install two new NPM packages with:


npm i --save flagsmith-nodejs node-cache

It will result in something like below:


npm WARN eventually-podcast@1.0.0 No repository field.

+ node-cache@5.1.2
+ flagsmith-nodejs@1.1.0
updated 2 packages and audited 98 packages in 1.845s

6 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

So at this point, we have installed flagsmith-nodejs (the Flagsmith Node.js SDK), and node-cache NPM modules. The Flagsmith Node.js SDK is used to communicate with the Flagsmith API from our Node.js application. The node-cache NPM module is installed to keep the communication smoother with fewer calls to the Flagsmith API. In the next section, we will see how we can integrate the feature flag we have created with our code.

Use Flagsmith Node.js Client with Some Caching

To show or hide the social icons on the footer of our mock podcast’s landing page after installing the needed NPM modules, we will change the index.json the root of the project to look like below:


const express = require('express');
const path = require('path');
const flagsmith = require('flagsmith-nodejs');
const nodecache = require('node-cache');

const app = express();
const port = process.env.PORT || '3000';

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));

flagsmith.init({
  environmentID: process.env.FLAGSMITH_ENVIRONMENT_ID || 'LKfXyih5yqZxL3huZ5LraP',
  cache: new nodecache({stdTTL : 10, checkperiod: 10}),
});

app.get('/', async (req, res) => {
  let showFooterIcons = false;
  try {
    showFooterIcons = await flagsmith.hasFeature('show_footer_icons');
  } catch (e) {
    console.log(`Error connecting to flagsmith - ${e.getMessage} `, e);
  }

  console.log(`show footer icons: ${showFooterIcons}`);
  res.render(
    'index', 
    { 
      title: 'Coming Soon!', 
      mainText: 'Eventually Podcast', 
      subText: `Drop your email address below and we will let you know when we launch the Eventually podcast. 
     
Brought to you by amazing people`,
      showFooterIcons,
    }
  );
});

app.listen(port, () => {
  console.log(`Listening to requests on http://localhost:${port}`);
});

The main changes here are that we have required the Flagsmith SDK and the node cache module. Just above the `app.get` route definition line, we are initializing the Flagsmith SDK with the environment ID. To make it more efficient we are also using Node cache. The cache is set to 10 seconds, meaning it will reuse the values from the Flagsmith API for 10 seconds before making another call.

The main part here is the environmentID that we can get from the `Initialising your project` section of the feature flag we created in the previous step as seen below:

Where to get Environment ID in Flagsmith

For testing and development, we will use the Development environment. We will use the Production environment when we deploy our application. The environment ID is pulled in from the process.env. If the FLAGSMITH_ENVIRONMENT_ID is not available as an environment variable then the given string is used. We have a fallback string in place so that even if the environment ID is not set that application will still work.

The other change is in the route definition, where we initialize a variable named showFooterIcons as false. So if we hit an issue while contacting Flagsmith we will not show the footer icons. Then we try to get if the feature is available on Flasmith with:


showFooterIcons = await flagsmith.hasFeature('show_footer_icons');

If the feature is enabled it will return a true else it will be false, this is wrapped in a try catch to make it more resilient. After that the `showFooterIcons` variable is passed on to the “index” view in the res.render call.

The view file located at views/index.pug looks like the following to make the rendering of the social icon in the footer dynamic as follows:


extends layout

block body-content
  // Header
  header#header
    h1 #{mainText} 
    p
      | !{subText}
  // Signup Form
  form#signup-form(method='post' action='#')
    input#email(type='email' name='email' placeholder='Email Address')
    input(type='submit' value='Sign Up')
  // Footer
  footer#footer
    if showFooterIcons
      ul.icons
        li
          a.icon.brands.fa-twitter(href='#')
            span.label Twitter
        li
          a.icon.brands.fa-instagram(href='#')
            span.label Instagram
        li
          a.icon.brands.fa-github(href='#')
            span.label GitHub
        li
          a.icon.fa-envelope(href='#')
            span.label Email
    ul.copyright
      li © Untitled.
      li
        | Credits: 
        a(href='http://html5up.net') HTML5 UP
  // Scripts
  script(src='/assets/js/main.js')
 

The main change here is in the `footer#footer` section, where the `ul.icon` list is only rendered if the `showFooterIcons` is true which depends on the feature flag we created in the previous step being enabled. All the above code changes are available as a pull request for your reference. In the next section, we will do a quick test of the above changes.

Test the Node.js Feature Flag

To test our change we will re-run the application with:


npm start

Then hit the browser again at http://localhost:3000. It will render an output like this:

Eventually podcast homepage

Next up we will first turn off the feature flag on the Flagsmith interface and it will look like this:

Flagsmith feature management screenshot

After turning off the flag and confirming the changes, if we refresh our application it will not show the footer icons and look like the below:

Eventually podcast homepage without social icons

Great! The footer icons are gone and to bring them back it is as easy as turning on the flag, waiting for 10 seconds for the cache lifetime, and hitting refresh. As the next step, we will deploy our application to Railway.app, a simple and elegant way to deploy a Node.js app or any dockerized application.

Deploy to Railway.app

Railway.app has a free starter plan to deploy applications and trial the platform (after that, there are paid pricing plans available). To deploy the application to Railway we will first install the railway CLI, to do this we will run:


npm i -g @railway/cli

This will install the railway CLI and will result in the following:


npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
> @railway/cli@0.2.45 preuninstall /some/path/node_modules/@railway/cli
> go-npm uninstall
> @railway/cli@0.2.45 postinstall /some/path/node_modules/@railway/cli
> go-npm install
Downloading from URL: https://github.com/railwayapp/cli/releases/download/v0.2.45/railway_0.2.45_darwin_amd64.tar.gz
+ @railway/cli@0.2.45
updated 1 package in 10.009s

Now as we have the railway CLI we will log in to Railway using Github, to do this we will run the following on the project root:


railway login

It will first ask us to open the browser and take us to the login screen like below:

Railway application login

After we click GitHub and authenticate, it will confirm the authentication as follows:

Railway application login successful screen

The CLI will look like the below after the authentication is successful:


Press Enter to open the browser (^C to quit)
? Logging in... No dice? Try railway login --browserless
? Logging in... 
? Logged in as Your Name (@domain.com)

Subsequently, we can initialize the project on Railway with:


railway init

It will ask if we want a starter or an empty project, just select “Empty Project” and give the project a name as follows:


✔ Starting Point: Empty Project 
✔ Enter project name: eventually-podcast
✔ Environment: production
? Created project eventually-podcast

It will also open the browser to show us the project settings as follows:

Eventually podcast in the Railway application

Here we will add our FLAGSMITH_ENVIRONMENT_ID environment variable from the production environment:

Flagsmith application with show icons switch ‘on’

We will add it to the variables page of Railway’s project as follows since we want to use the Production environment not the Development one for Railway:

Adding Flagsmith Environment ID to Railway application

To save the variable we will click “Add”.

The next step in the process to deploy is to run:


railway up

As the application is already dockerized it will build the docker image and deploy the application. If it was not dockerized, Railway.app would detect that it is a Node.js application and deploy it using the build pack. If you are interested, please do check out their docs.

After the deployment is finished it will show us something like the below:


☁️ Build logs available at https://railway.app/project/c4fc117f-d04e-4a61-9788-6216fb5e5596/deployments?id=d43a6572-d418-4506-ae88-c0ce678f5c4d
 
==========================
Using detected Dockerfile!
==========================
Sending build context to Docker daemon  3.394MB
Step 1/9 : FROM node:14-alpine as base
 ---> fe39f43f1d22
Step 2/9 : WORKDIR /src
 
 ---> Running in 6bf8c2cd1fa1
Removing intermediate container 6bf8c2cd1fa1
 ---> 96ae9ce24569
Step 3/9 : COPY package*.json ./
 ---> 82cd9bd661a7
Step 4/9 : EXPOSE 3000
 ---> Running in 89bacb0b1d43
Removing intermediate container 89bacb0b1d43
 ---> 0dfd09862db1
Step 5/9 : FROM base as production
 ---> 0dfd09862db1
Step 6/9 : ENV NODE_ENV=production
 ---> Running in d4ab473be240
Removing intermediate container d4ab473be240
 ---> bbc350ac53b9
Step 7/9 : RUN npm ci
 ---> Running in 2970f701628c
added 98 packages in 1.454s
Removing intermediate container 2970f701628c
 ---> 99b660ab4187
Step 8/9 : COPY . ./
 ---> 036d470ec912
Step 9/9 : CMD ["node", "index.js"]
 ---> Running in 380cf6634c1c
Removing intermediate container 380cf6634c1c
 ---> 6e5936efd6d4
[Warning] One or more build-args [FLAGSMITH_ENVIRONMENT_ID RAILWAY_ENVIRONMENT RAILWAY_STATIC_URL] were not consumed
Successfully built 6e5936efd6d4
Successfully tagged registry.railway.app/d43a6572-d418-4506-ae88-c0ce678f5c4d:latest
======= Build Completed ======
Waiting for Deploy To Finish
☁️ Deployment logs available at https://railway.app/project/c4fc117f-d04e-4a61-9788-6216fb5e5596/deployments?id=d43a6572-d418-4506-ae88-c0ce678f5c4d
OR run `railway logs` to tail them here
☁️ Deployment live at https://eventaully-podcast-production.up.railway.app

We will see the URL for our project that we can hit on the browser of our choice. Now when we go to that URL we should see our application working as follows:

screenshot of eventually podcast

To test the feature flag, we will turn off the flag on the Production environment and see that the footer icons disappear:

screenshot of flagsmith feature flag management ux

And it does work:

Eventually podcast homepage without social icons

I will leave the feature flag on.

If you want to play around with the Node.js feature flags demo link, here it is. A few things to consider now:

  • Depending on what you want to do Railway.app the free plan also supports custom domains.
  • If you want, you can also use the GUI version of Railway.app and connect your own fork of the repository.
  • With their GitHub integration, we can have automatic deployments configured by the git branch.

Conclusion

In this guide, we covered how to implement Node.js feature flags in a relatively simple Express.js application. The use of node-cache helped us cache the feature flag’s value locally for 10 seconds.

We also learned about using an environment variable to store the environment ID, which made it a lot easier to switch between development and production environments when deploying the app on Railway.app.

Using Flagsmith for Node.js Feature Flags

If you’re interested in trying out Flagsmith for your next Node.js project, just create your account here or contact us for the on-prem solution.

More Reading and How-To Guides

If you like this Node.js feature flagging guide, check out our other guides:

Quote

Subscribe

Learn more about CI/CD, AB Testing and all that great stuff

Success!
We'll keep you up to date with the latest Flagsmith news.
Must be a valid email
Illustration Letter