« Back to blog posts

Using Firebase with GatsbyJS

Using Firebase with GatsbyJS

Integrating the Firebase Web SDK into a website is usually straightforwards; install the firebase NPM package, import it and off you go! Doing this with Gatsby JS will cause some issues.

When building your project for production, Gatsby creates static files which are built on a machine. This build environment has no access to the window object. The Firebase Web SDK is not server friendly, and assumes its environment always has access to the window. If you simply import Firebase and expect it to work out of the box, you'll hit a bunch of issues when during the static build process. So how do you overcome this?

Exporting a Firebase instance

Firstly, we need to export a Firebase instance in our project. However we only want this to happen when the window is available, otherwise we skip the initialisation of Firebase.

In your project, install Firebase via NPM (npm install firebase), then create a firebase.js file using your project credentials from the Firebase Console:

import firebase from 'firebase/app';
import 'firebase/auth'; // importing the auth module as an example

// Firebase web config
const config = {
  // apiKey: '',
  // authDomain: '',
  // databaseURL: '',
  // projectId: '',
  // storageBucket: '',
  // messagingSenderId: '',
  // appId: '',
  // measurementId: '',
}

let instance = null;

export default function getFirebase() {
  if (typeof window !== 'undefined') {
    if (instance) return instance;
    instance = firebase.initializeApp(config);
    return instance;
  }

  return null;
}

What's happening here? We're exporting a function called getFirebase which creates a new Firebase instance when called, only if the window object is available (on the client). If the window is available and an instance has already been created, we return the cached one (for example if multiple components require Firebase usage).

Great; we can now initialise Firebase during build time with no errors!

Accessing Firebase from a component

The next problem we have is being able to access Firebase within a component & being able to use it. Luckily, we can take advantage of React Hooks to make the accessing of the exported Firebase instance simple.

Create a new hook in your project, for example a file called useFirebase.js:

import { useEffect, useState } from 'react';
import getFirebase from './firebase'; // import our getFirebase function

export default function useFirebase() {
  const [instance, setInstance] = useState(null);

  useEffect(() => {
    setInstance(getFirebase());
  }, []);

  return instance;
} 

This hook allows us to subscribe to whenever the Firebase instance is available. On the server, null will be returned however once the client is available the instance is passed back.

To use this within a component, we can import the hook and use the hook useEffect to synchronise with the Firebase instance:

import React, { useEffect } from 'react';
import useFirebase from './useFirebase';

function App() {
  const firebase = useFirebase();

  useEffect(() => {
   if (!firebase) return;
   return firebase.auth().onAuthStateChanged((user) => {
     console.log('User:', user);
   });
  }, [firebase]);

  ...
}

Now we can use Firebase functionality whenever the instance is available, only on the client.

Summary

The following approach is as cleanest I've found when working with both Firebase & GatsbyJS - it removes most of the "hacking" aspect away from core logic, not having to worry about whether the window is available.

If anyone has found a better way to integrate the two together, please reach out to me on Twitter - I'd love to make the integration as seamless as possible!


Share this blog post: