Live flag updates, downtime protection and more

We’ve made a number of improvements to the Node SDK:

Live flag updates

When you change a flag, the update is now propagated immediately to backend services running our Node SDK. Since version 1.6.0, @reflag/node-sdk opens a persistent connection to our servers and receives flag updates in real time.

This improves debuggability and makes it faster to roll back faulty features.

Downtime protection

We’ve also introduced fallback providers. This reliability feature lets the SDK persist the latest successfully fetched raw flag definitions to fallback storage such as a local file, Redis, S3, GCS, or a custom storage like your database.

Reflag servers remain the source of truth. During initialize(), the SDK always tries to fetch a live copy of the flag definitions first, and continues receiving updates from Reflag over time.

If that initial fetch fails, the SDK can load the most recent snapshot from fallback storage instead. This allows new processes to start even in the exceedingly rare event of a Reflag outage.

If Reflag becomes unavailable after the SDK has already been initialized successfully, the SDK continues using the last successfully fetched definitions already held in memory. In other words, fallback providers help new processes start during an outage; they are not needed to keep an already running process alive.

New Testing API

We’ve introduced a new API to make testing easier. You can define base overrides with setFlagOverrides() and then layer additional overrides on top with pushFlagOverrides().

This works especially well in Jest or Vitest, where tests often use nested describe() blocks:

export const flag = function (name: string, enabled: boolean): void {
  let remove: (() => void) | undefined;

  beforeEach(function () {
    remove = reflagClient.pushFlagOverrides({ [name]: enabled });
  });

  afterEach(function () {
    remove?.();
    remove = undefined;
  });
};

describe("foo", () => {
  describe("with new search ranking enabled", () => {
    flag("search-ranking-v2", true);

    describe("with summaries enabled", () => {
      flag("smart-summaries", true);

      // ...
    });
  });
});