Node.js Feature Flags: a Step-by-Step Implementation Guide with an Express.js Example

Feature flags help engineers, developers, and product teams turn a feature on or off without the need to deploy any code. Node.js feature flags enable this functionality in the Node.js environment.

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.

Before we get started, though, let's quickly cover what Node.js and feature flags are.

What is Node.js?

Node.js is an open-source, cross-platform runtime environment that lets developers and engineers run JavaScript server-side, rather than in a browser.

Node.js enables efficient, scalable, and event-driven programming, making it well-suited for handling side-by-side operations and real-time applications. The environment is widely used for web development, API services, and microservices, and it has a vast ecosystem of libraries and frameworks available through npm (Node Package Manager).

What are feature flags?

Feature flags, also known as feature toggles, let developers turn features in their software on or off without deploying new code.

Think of them as switches built into an application that let you control what users see or experience. They enable teams to roll out new features gradually, test them with specific user groups, or easily disable a feature if something goes wrong—without needing a full redeployment.

Feature flags provide flexibility in development, making it easier to experiment, manage risks, and respond quickly to issues, all while keeping things running smoothly for most users. They're like a safety net and a testing tool wrapped into one.

By integrating feature flagging software into a Node.js application, developers can enable or disable specific features dynamically based on user segments, environments (like development, staging, or production), geographic locations, and more.

Why use feature flags in Node.js?

Toggling feature flags is what makes them useful day-to-day, but it helps to understand why development teams reach for Node feature flags in the first place.

A feature flag is a software development technique built around decoupling feature releases from code deployment. Rather than merging a new feature straight into the main branch and shipping it to your entire user base in one go, you wrap it in a flag and ship the hidden feature alongside your other code changes.

With a feature flag in place, you can:

  • Release new features to a small subset of users first, based on user roles.
  • Roll larger groups in gradually, through progressive delivery, once you're confident in your deployment.
  • Use the flag as a kill switch and disable it instantly if something breaks.
  • Run A/B testing on different versions of a feature before it's fully rolled out to everyone.

You get trunk-based development out of this too: new code merges to the main branch behind a flag instead of sitting in long-lived branches for experimental features, so you can cut down on the technical debt that comes with branches that live for weeks.

For product managers, this means more flexibility to control software releases without waiting on a developer to deploy. For developers, it means monitoring performance and user feedback on a new feature once it's live, then enabling or disabling it across multiple features at once, without touching your continuous integration pipeline.

Prerequisites

Before jumping to the code, below are some of the prerequisites for getting started with 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 log in to Railway.app, where we'll deploy the code (Google and email logins also work)
  5. [Optional] You may want to check out our feature flagging best practices article either before or after you read this guide

If you don't have some or any of these prerequisites, then an AI tool like Claude or ChatGPT could be able to guide you through difficult stages.

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 one below:

Eventually Podcast coming soon page built with Node.js and Express

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 using a feature flag: Twitter, Instagram, GitHub, and Email.

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 making the code change, we will deploy the application to Railway.app using its free trial. In the following section, we set up the feature flag on Flagsmith.

Set up feature flags in Flagsmith

To create a feature flag that lets you toggle the visibility of the social icons on the footer, we will first need to create a project after logging into Flagsmith. Click "Create Project", the first card on the Projects page, as seen below:

Flagsmith Projects page with the Create Project button

If you've just signed up, Flagsmith's welcome page will have already created a project for you, and free accounts are limited to one project. Instead of creating a new one, rename that project to eventually-podcast using the pencil icon next to its name, click the option to skip onboarding, and carry on from creating the feature flag below.

I have named it 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:

New eventually-podcast project page in Flagsmith

Now we will create a new feature flag by clicking the "Create Feature" button and filling in the details as follows:

Flagsmith New Feature form for the show_footer_icons flag

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:

show_footer_icons feature flag switched on in Flagsmith’s Development environment

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 the 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 https://github.com/geshan/nodejs-express-tutorial.git

Then we will go into the directory, install the NPM dependencies, and run the app to test it 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 app running locally at localhost:3000

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

npm i --save @flagsmith/nodejs node-cache

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 in the footer of our mock podcast's landing page, after installing the needed NPM modules, we will change the index.js in the root of the project to look like this:

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')));
const nodeCache = new NodeCache({ stdTTL: 10, checkperiod: 10 });
const flagsmith = new Flagsmith({
  environmentKey: process.env.FLAGSMITH_ENVIRONMENT_ID || 'YOUR_ENVIRONMENT_KEY',
  cache: {
    get: async (key) => nodeCache.get(key),
    set: async (key, value) => nodeCache.set(key, value),
  },
});
app.get('/', async (req, res) => {
  let showFooterIcons = false;
  try {
    const flags = await flagsmith.getEnvironmentFlags();
    showFooterIcons = flags.isFeatureEnabled('show_footer_icons');
  } catch (e) {
    console.log(`Error connecting to flagsmith - ${e.message}`, 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 our environmentKey, plus a small cache object that wraps node-cache in the async get and set methods the SDK expects. 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 environmentKey, which we can get by clicking "Code example: 2: Initialising your project" below the Features list and choosing Node JS from the dropdown, as seen below:

Flagsmith Node.js initialisation code showing the Development environment key

For testing and development, we will use the Development environment. We will use the Production environment when we deploy our application. The environmentKey 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 key is not set, the application will still work. For local testing, replace YOUR_ENVIRONMENT_KEY with your Development environment key.

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 fetch the environment's flags and check if the feature is enabled with:

const flags = await flagsmith.getEnvironmentFlags();
showFooterIcons = flags.isFeatureEnabled('show_footer_icons');

If the feature is enabled, isFeatureEnabled returns true; otherwise, it returns false, and the whole thing is wrapped in a try...catch to make it more resilient. After that, the showFooterIcons variable is passed to the index view in the res.render call.

The view file at views/index.pug looks like the following, which makes the social icons in the footer render dynamically:

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 showFooterIcons is true, which requires the feature flag we created in the previous step.

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:

Node.js app showing footer social icons while the feature flag is on

Next up, we will turn off the feature flag by clicking its toggle on the Flagsmith interface, which asks us to confirm the change:

Flagsmith confirmation box turning show_footer_icons off for Development

After turning off the flag and confirming the change, if we wait 10 seconds for the cache to expire and refresh our application, it will not show the footer icons and will look like the below:

Node.js app without footer social icons after the feature flag is switched off

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 offers a free trial with $5 of credit for 30 days, which is plenty for this application (after that, there are paid 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

On a Mac, this may fail with a permission error. If it does, run sudo npm i -g @railway/cli instead and enter your Mac password. Once installed, it will show something like the following:

added 16 packages in 1s

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

Now, as we have the Railway CLI, we will log in to Railway using GitHub. To do this, we will run the following in the project root:

railway login

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

Railway login screen with GitHub and Google sign-in options

After we click "Continue with GitHub" and authenticate, Railway will ask us to approve the CLI's access. Click "Accept and Connect CLI":

Railway permissions page for connecting the Railway CLI

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

→ Opening your browser to sign in — finish there.
✓ Signed in as you@example.com

Subsequently, we can initialize the project on Railway with:

railway init

It will select our workspace and ask for a project name, where we'll enter eventually-podcast:

> Select a workspace Your Name's Projects
> Project Name eventually-podcast
Created project eventually-podcast on Your Name's Projects
https://railway.com/project/your-project-id

The next step is to deploy the application by running:

railway up

As the application is already dockerized, it will build the Docker image and deploy the application. If it were not dockerized, Railway would detect that it is a Node.js application and deploy it using Railpack, Railway's own build system.

It will upload the code and show us a link to the deployment:

Indexed
Compressed [====================] 100%
Uploaded
Deployment: https://railway.com/project/your-project-id/service/your-service-id?id=your-deployment-id

Opening that link shows the project with its eventually-podcast service, which changes to Online once the build finishes:

Railway project page showing the eventually-podcast service online

Next, we need to add our FLAGSMITH_ENVIRONMENT_ID environment variable from Flagsmith's Production environment:

Flagsmith Node.js initialisation code showing the Production environment key

Click the service, open the Variables tab, and click "New Variable". We will add it as follows, since we want to use the Production environment, not the Development one, for Railway:

Adding the FLAGSMITH_ENVIRONMENT_ID variable in Railway

To save the variable, we will click "Add", then click "Deploy" in the banner that appears, so Railway redeploys the app with the new variable.

Railway doesn't give the app a public web address automatically. In the service's Settings tab, scroll down to Networking and click "Generate Domain". Railway will create an address like eventually-podcast-production.up.railway.app. If we go to that URL, we should see our application working as follows:

Eventually Podcast app live on Railway with footer icons showing

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

Flagsmith confirmation box turning show_footer_icons off for Production

And it does work:

Eventually Podcast app live on Railway without footer icons after the flag is switched off

I will leave the feature flag on.

A few things to consider now:

  • Railway.app also supports custom domains, using the "Custom Domain" button next to "Generate 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 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.

Managing Node.js feature flags in continuous deployment pipelines

Once you've got a feature flag or two live in your Node.js app, the next question is how to manage feature flags with Node.js once you're shipping changes every day, not just for a single demo.

Follow a few best practices to make this easier:

  • Keep the environment variable for your environment key separate per environment, exactly as we did above with FLAGSMITH_ENVIRONMENT_ID, so a bad flag change in development can never reach production by accident.
  • Treat every flag as a kill switch first. If you can disable a feature in seconds from the Flagsmith dashboard, you've already got most of the safety benefit of feature flags in your pipeline, even before you touch A/B testing or staged rollouts.
  • Monitor performance and user feedback after enabling a feature for a larger group, rather than deleting the flag the moment the code deploys.
  • Clean up flags once a feature is fully rolled out. A Node.js feature flag still in your source code six months later is technical debt with an on/off switch.

Feature flag management like this is what makes Flagsmith a good fit for continuous deployment pipelines: your Node.js application keeps deploying on every merge to the main branch, while a flag—not a deployment—decides when users actually see the feature.

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:

Node.js feature flags FAQs

How do I implement feature flags in Node.js applications?

Install a feature flag SDK such as @flagsmith/nodejs, initialize it with your environment key, then wrap the code paths you want to control in a check like flags.isFeatureEnabled('your_flag_name')—or, in a smaller script, const featureFlags = await flagsmith.getEnvironmentFlags();. The walkthrough above does exactly this with an Express.js app, and the same works just as well in Fastify, NestJS, or a plain Node.js script.

What is the best way to manage feature flags with Node.js?

Keep your environment key in an environment variable rather than hardcoding it, use a short cache so you're not calling the Flagsmith API on every request, and treat each flag as disposable. Once a feature is fully rolled out, remove the flag and the old code path rather than letting it sit in your source code as technical debt.

What is a good Node.js feature flag solution for continuous deployment pipelines?

Look for a solution that toggles functionality at runtime without a redeploy, supports separate environments with proper permissions and access control, and gives non-developers—product managers, for example—a dashboard to enable or disable features themselves.

Flagsmith covers all three, with the security benefits of keeping that access limited to the right people, which is why it pairs naturally with the continuous integration and deployment setup this guide uses on Railway.

Quote