Firebase: Applying Feature Flag using Remote Config
Tags: firebase, gcp, googlecloud, javascript
Published: 2022-12-18 13:56:42

Firebase Remote Config is a powerful tool for app developers that allows them to easily modify the appearance and behavior of their app without requiring users to download an update. This can save time and resources, and make it easier to roll out changes to an app quickly and efficiently.

## What is a feature flag?

A feature flag is a process in software development to manage the availability of a feature. Dev people or anyone who have access to the configuration can **enable** or **disable** the feature using this flag remotely without deploying the code again.

Let's say, I have a NextJS app and I want to deploy a new button, I realized that the button is not working as I expected. Instead of rolling back to the previous button version, I just can disable the new button flag and the site will show the old button again.

Before we head to the use case, you can look at the very simple getting started code below.


```javascript
// Initialize Firebase
firebase.initializeApp({
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  databaseURL: "YOUR_DATABASE_URL",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID"
});

// Get a reference to the Remote Config service
const config = firebase.remoteConfig();

// Set default values
config.defaultConfig = ({
  "welcome_message": "Welcome to our app!"
});

// Fetch the config values
config.fetch()
  .then(() => {
    // Activate the fetched config
    return config.activate();
  })
  .then(() => {
    // Get the welcome message from the config
    const welcomeMessage = config.getValue("welcome_message").val();

    // Update the UI with the welcome message
    document.getElementById("welcome-message").textContent = welcomeMessage;
  })
  .catch((error) => {
    // There was an error fetching the config
    console.error(error);
  });

```
> Just FYI, the code above is the old version of Firebase SDK (version 8), I will tell you the latest code that uses SDK version 9.

You see `config.activate();` here is purposed for getting the latest value. 

If you don't have `activate()`, your `getValue()` will only return an empty value.

### Why it matters

The activate method is used to apply the fetched set of parameter values to your app. When you call fetch, the Remote Config API retrieves the latest set of parameter values from the server and stores them locally. These values are not applied to your app until you call activate.

Okay, now I will show you how I do it in NextJS.

What you need to prepare is to have a Firebase App ready and NextJS ready too. I will not tell you how to setup NextJS and Firebase, I expect you to understand about setting up NextJS including the config like `dotenv`.

Then go to Firebase project settings to see the API and secret key.


![Firebase Project Setting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hauiloykflih2xry3dd0.png)

Now in NextJS root dir create `.env` with content like the below.

```
NEXT_PUBLIC_FIREBASE_APP_ID=
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_MESSAGE_ID=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_GA_ID=
```

To make it neat, create a global config in `/src/config/index.ts`

```javascript
export const firebaseApiKey = process.env.NEXT_PUBLIC_FIREBASE_API_KEY || '';
export const firebaseAppId = process.env.NEXT_PUBLIC_FIREBASE_APP_ID || '';
export const firebaseProjectId =
  process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID || '';
export const messagingSenderId =
  process.env.NEXT_PUBLIC_FIREBASE_MESSAGE_ID || '';
export const googleAnalyticId = process.env.NEXT_PUBLIC_FIREBASE_GA_ID || '';
```

The next step is to create Firebase config. Create a file in `/src/utils/firebaseConfig.ts`.

You can follow my style or use yours also can.

```javascript
// Import the functions you need from the SDKs you need
import { initializeApp } from 'firebase/app';
import { getRemoteConfig } from 'firebase/remote-config';

import {
  firebaseApiKey,
  firebaseAppId,
  firebaseProjectId,
  messagingSenderId,
  googleAnalyticId,
} from '@/config';
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: firebaseApiKey,
  authDomain: `${firebaseProjectId}.firebaseapp.com`,
  projectId: firebaseProjectId,
  storageBucket: `${firebaseProjectId}.appspot.com`,
  messagingSenderId,
  appId: firebaseAppId,
  measurementId: googleAnalyticId,
};

// Initialize Firebase
export const app = initializeApp(firebaseConfig);

let remoteConfigVar;
if (typeof window !== 'undefined') {
  remoteConfigVar = getRemoteConfig(app);
  remoteConfigVar.settings.minimumFetchIntervalMillis = 600000;
}
export const remoteConfig = remoteConfigVar;
```

I will highlight this line `typeof window !== 'undefined'`. Since our NextJS is running in the server side, Remote Config won't be able to be initialized so we need to check if `window` is not `undefined`.

Also, we have this `  remoteConfigVar.settings.minimumFetchIntervalMillis = 600000;`. By default, Firebase will cache the config for 12 hours, so any changes won't be applied before 12 hours, but we can add a minimum fetch interval as low as 10 minutes.

Then in NextJS, let's say in the `index.ts` page.

```
import { getValue, fetchAndActivate } from 'firebase/remote-config';
import { remoteConfig } from '@/utils/firebaseConfig';
```
Then

```javascript
  const [showBtn, setShowBtn] = useState(false);

  const getConfigValue = () => {
    const firebaseRemoteConfig = remoteConfig;
    if (firebaseRemoteConfig) {
      fetchAndActivate(firebaseRemoteConfig).then(() => {
        setShowBtn(getValue(firebaseRemoteConfig, 'show_button').asBoolean());
    }
  };

  useEffect(() => {
    getConfigValue();
  }, []);
```
And in JSX,

```HTML
<div className="p-16 text-white">
  {showBtn ? (
    <Button type="primary">New Button</Button>
   ) : (
    <Button type="primary">Old Button</Button>
   )}
</div>
```

Don't forget to have the config set in Firebase dashboard.


![Create config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fz4hgwmzvhgyfdoi4mtx.png)

Next, I will try to cover up another Firebase topic, see ya!