Powerful Feature Flags in Node Express Server
Feature flags allow you to slowly rollout a feature gradually rather than doing a risky big bang launch and are extremely helpful when used in a continuous integration and continuous delivery environment.
At Optimizely, we commonly use feature flags to reduce the risk of complicated deploys like rolling out new APIs.
However, building a feature flagging system is usually not your company’s core competency and can be a distraction from other development efforts.
I’m Asa, Optimizely’s Developer Advocate. In this 8 step blog post, I’ll show how to get the value of powerful feature flags by rolling out a feature customer-by-customer in Express using Optimizely Rollouts: a completely free product.
Note: If you don’t have an Express application, we recommend creating one with express-generator
Steps to rollout a feature
1. Setup the Feature Flag Interface
Create a free Optimizely Rollouts account here.
In the Rollouts interface, navigate to ‘Features > Create New Feature’ and create a feature flag called ‘hello_world’.
To connect your ‘hello_world’ feature to your application, find your SDK Key. Navigate to ‘Settings > Datafile’ and copy the SDK Key value.
2. Install the Optimizely Rollouts Express Middleware
The Node Express middleware allows you to setup feature toggles from within your codebase using JavaScript.
Using npm:
npm install --save @optimizely/express
or using yarn:
yarn add @optimizely/express
Use the Express middleware by first configuring the SDK at the start of your express server. We recommend placing it near other imports at the top of your app.js or index.js file. Also, remember to replace <Your_SDK_Key> with the SDK key you found above.
express-feature-flags__sdk-initialize.js
- autoUpdate: indicates that your feature flags will get automatically updated from changes made in Optimizely’s user interface.
- updateInterval: indicates how frequently the Optimizely Express middleware will poll for changes. We suggest increasing the polling interval when deploying this code to production.
Use the middleware by adding the following before your express routes:
app.use(optimizely.middleware);
A full example code of your installation should now look something like:
const express = require('express');
const app = express();
const HOST = process.env.HOST || '0.0.0.0';
const PORT = process.env.PORT || 8080;
const optimizelyExpress = require('@optimizely/express');
const optimizely = optimizelyExpress.initialize({
sdkKey: '<Your_SDK_Key>',
datafileOptions: {
autoUpdate: true, // Indicates feature flags will be auto-updated based on UI changes
updateInterval: 1*1000 // 1 second in milliseconds
},
logLevel: 'info', // Controls console logging. Can be 'debug', 'info', 'warn', or 'error'
});
app.use(optimizely.middleware);
app.get('/', function(req, res, next) {
res.send('Optimizely Express Example')
});
app.listen(PORT, HOST);
console.log(`Example App Running on http://${HOST}:${PORT}`);
module.exports = app;
express-feature-flags__installation.js
3. Implement the Feature
In addition to keeping your feature flag configuration up-to-date with changes made in the UI, the above installation adds the following object on every express request object:
req.optimizely = {
datafile: A representation of all of your feature flags and experiments as defined in Optimizely
client: The Optimizely SDK client instance which has methods like for isFeatureEnabled, activate, track, etc.
}
To implement your ‘hello_world’ feature, we’ll use the isFeatureEnabled on the client field of this object:
- Find a route that you would like to add a feature toggle.
- Use the isFeatureEnabled API by passing your feature key ‘hello_world’ to the first parameter of isFeatureEnabled:
app.get('/', function(req, res, next) {
const isEnabled = req.optimizely.client.isFeatureEnabled(
'hello_world', // Feature key connecting feature to UI
'user123', // String ID used for random percentage-based rollout
{
customerId: 123, // Attributes used for targeted audience-based rollout
isVip: true,
}
);
res.send('Optimizely Express Example: ' + (isEnabled ? 'You got the hello world feature!' : 'Feature off.'))
});
express-feature-flags__route-example.js
The parameters to isFeatureEnabled(featureKey, userId, userAttributes) are the following:
- featureKey: name of the feature to connect this method to the Optimizely UI.
- userId: used for rolling out to a random percentage of users, we won’t use this parameter in this post, leave as a non-empty string for now.
- userAttributes: used for a targeted rollout across your users. You will use these attributes to target your feature to specific groups of users starting in step 5.
The return value, isEnabled, is a boolean indicating whether the feature was enabled or not enabled for those inputs.
Your full code sample now looks like the following:
const express = require('express');
const app = express();
const HOST = process.env.HOST || '0.0.0.0';
const PORT = process.env.PORT || 8080;
const optimizelyExpress = require('@optimizely/express');
const optimizely = optimizelyExpress.initialize({
sdkKey: '<Your_SDK_Key>',
datafileOptions: {
autoUpdate: true, // Indicates feature flags will be auto-updated based on UI changes
updateInterval: 1*1000 // 1 second in milliseconds
},
logLevel: 'info', // Controls console logging. Can be 'debug', 'info', 'warn', or 'error'
});
app.use(optimizely.middleware);
app.get('/', function(req, res, next) {
const isEnabled = req.optimizely.client.isFeatureEnabled(
'hello_world', // Feature key connecting feature to UI
'user123', // String ID used for random percentage-based rollout
{
customerId: 123, // Attributes used for targeted audience-based rollout
isVip: true,
}
);
res.send('Optimizely Express Example: ' + (isEnabled ? 'You got the hello world feature!' : 'Feature off.'))
});
app.listen(PORT, HOST);
console.log(`Example App Running on http://${HOST}:${PORT}`);
module.exports = app;
express-feature-flags__full-sample.js
4. Turn the Feature Toggle on!
If you run your server now and open up the route in a browser, you’ll notice that you did not get the feature. This is because the feature is not enabled, which means it’s off for all visitors to your application.
To turn on the feature:
- Navigate to Features
- Click on the ‘hello_world’ feature
- Toggle the feature on and ensure it is set to 100% (see screenshot below)
- Click Save to save your changes
In less than a minute, without restarting your running server, make a new request to your server to see your Optimizely changes take effect. Your application should now show the feature toggled on and you should see “You got the hello_world feature!!”.
You have now successfully launched your feature behind a feature flag, but it’s available to everyone. The next step is to enable targeting to show your feature only to a specific subset of users to enable the true value of rolling a feature out customer-by-customer.
5. Create an attribute for customerId
To target your feature based on the userAttributes you provided to the isFeatureEnabled API in step 3, you’ll have to create those userAttributes in the Rollouts UI. Do that with the attribute ‘customerId’ to start:
- Navigate to Audiences -> Attributes
- Click ‘Create New Attribute…’
- Name the attribute key ‘customerId’
- Click ‘Save Attribute’ to save your changes
6. Create and add a beta audience
Now let’s create an audience to indicate which customerIds will get access to your feature.
- Navigate to Features
- Click on your ‘hello_world’ feature
- Scroll down to Audiences
- Click ‘Create New Audience…’
- Name the Audience ‘[hello_world] Beta Users’
- Drag and Drop your customerId attribute into the Audience conditions
- Change the ‘has any value’ drop-down to “Number equals” with the value 123
- Click ‘Save Audience’
Add the audience to your feature by clicking the + button next to your newly created Audience. Then scroll down and click ‘save’.
Now that you’ve added the audience to your feature, the beta is up and running. At this point your feature is only showing for customers with the customerId 123, which is what you provided to the isFeatureEnabled API in the userAttributes parameter.
As a test to verify, you can change your customerId to 456, save, and watch as the feature will get turned off because you don’t meet the targeting conditions.
7. Add users to the beta
To add more customers into your beta audience, edit the audience definition to add or remove users from the beta:
- Click on the “+” sign and save to add beta users
- Click on the “x” sign and save to remove beta users
In the following screenshot example, three customers have been added to the beta. Customers with ids: 123, 456, and 789, will now have access to the ‘hello_world’ feature.
8. Launch the feature
After enabling your feature for enough customers to enjoy the new user experience, you may decide that it’s safe to launch your feature to all customers.
Once you are ready to launch your feature out of beta, follow these steps:
- Remove the audience from your feature
- Ensure the rollout is configured to 100%
- Save the feature
The feature is now available to everyone and you have successfully rolled out the ‘hello_world’ feature customer-by-customer using free feature flags from Optimizely Rollouts in Node Express!
Next Steps
Although this blog covered customer-by-customer rollouts, feature flags enable additional use cases like not relying on long-lived feature branches, creating a permissioning system, or enabling product-driven A/B testing on the backend.
At Optimizely, we use feature flags for all of these use cases and more.
Hope this was helpful! Give feedback if you have any. I hope I’ve been successful in saving some of your team’s development resources by enabling you to harness the power of feature flags with our free feature flagging product: Optimizely Rollouts.