Node.js feature flags: a practical getting started guide with Express.js example

Flagsmith
11 min readNov 15, 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 post, we will discuss 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!

Feature flags in JavaScript illustration

Prerequisites

Before jumping to the code, below are some of the things that would be great to know:

  1. Prior general knowledge of Node.js and express would be expected.
  2. Some experience of NPM and how to add new packages with NPM would be needed.
  3. Any knowledge of Git and GitHub would be really helpful.
  4. A Flagsmith account will be used to create a feature flag so register now if you have not. There is a free plan available.
  5. You will need a Github account to clone the demo repository and deploy code to Railway.app

In the next section, we will elaborate on the example Express.js application we will use for this practical getting started guide. Time to dive into the code:

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

For this hands-on getting started 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 get the email address which doesn’t really collect the email addresses at this point.

The goal here is to show/hide the 4 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 flag on 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:

Create project GIF

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 home section

Now we will create a new feature flag hitting the “Create Your First Feature” button and fill 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, 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:

Flagsmith application home with feature

Note that we have 2 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-tutorial
npm install
npm 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.js` on 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.
<br>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 &copy; 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 Node.js feature flag

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

npm start

And then hit the browser again at http://localhost:3000, it will render an output like:

Eventually podcast homepage

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

Flagsmith application homepage

After turning off the flag and confirming 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 plan to deploy applications for up to $5 a month. 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 (<email>@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:

Eventually podcast homepage with social icons

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

Flagsmith application with ‘show icons’ toggle ‘off’

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. Depending on what you want to do Railway.app free plan also supports custom domain. 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 saw how we can 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 environment when deploying the app on Railway.app. Don’t forget to use the best open-source feature flag product, Flagsmith, for your next Node.js project. Flagsmith also has on-premise and cloud-hosted solutions with great pricing plans.

--

--

Flagsmith

Ship features with confidence. Flagsmith lets you manage features flags and remote config across web, mobile and server side applications.