The new Firebase JS SDK is now GA

You’ve asked for it, and now it’s here! We’re excited to announce that version 9 of the Firebase SDK is now generally available. This new version adopts a module first format that is optimized for elimination of unused code. The result is a potential significant reduction of Firebase library code in JavaScript bundles, up to 80% in some scenarios.

Image of code snippet with text that says A smaller Firebase
Image of code snippet with text that says A smaller Firebase

As of today running npm install firebase will download the version 9 library. This new API is a major release and introduces several breaking changes. Upgrading to the new version can be done all at once or at your own pace with our compatibility library (more on that below). This post covers everything you need to know to get started. Check out our upgrade guide as well as our guide to using the new SDK with module bundlers for detailed guidance.

What’s new?

API changes for reduced size

Version 9 introduces a functional approach. In previous versions the API was organized into a traditional object-oriented structure. Using individual functions instead of structured objects allows JavaScript module bundlers such as webpack and Rollup to remove any unused code from the library. This is a concept known as tree shaking.

Image of code snippet with text that says Optimized for tree-shaking. Unused code elimination with bundlers like webpack, Rollup, esbuild, Parcel
Image of code snippet with text that says Optimized for tree-shaking. Unused code elimination with bundlers like webpack, Rollup, esbuild, Parcel
import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged, getRedirectResult } from 'firebase/auth';

const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth();
onAuthStateChanged(auth, user => { console.log(user); });

While this library organization is new, we have kept in place many familiar API concepts.

Image of code snippet with text that says A different, yet familiar API. Same functionality, lines of code, but 72 percent smaller.
Image of code snippet with text that says A different, yet familiar API. Same functionality, lines of code, but 72 percent smaller.
// 9.0.0
import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';

const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth();
onAuthStateChanged(auth, user => { console.log(user); });

// 8.8.1
import firebase from 'firebase/app';
import 'firebase/auth';

const firebaseApp = firebase.initializeApp({ /* config */ });
const auth = firebaseApp.auth();
auth.onAuthStateChanged(user => { console.log(user); });

The sample above compares the same functionality, has the same amount of lines of code, and a similar API. The version 9 code however is 72% smaller than the version 8 example.

Keep in mind that while our functional approach is beneficial for tree shaking, this does not require you to write your code functionally. This new format provides an “import only what you need” approach. You can still structure your code in the ways that work best for you and your team.

import { getApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';

class AuthService {
  constructor(firebaseApp) {
     this.auth = getAuth(firebaseApp);
  }
  waitForUser(callback) {
     onAuthStateChanged(this.auth, user => {
       if(user != null) { callback(user) }
     });
  }
}

const authService = new AuthService(getApp())
authService.waitForUser(user => { });
import { getApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';

function waitForUser(auth, callback) {
  onAuthStateChanged(auth, user => {
    if(user != null) { callback(user) }
  });
}

const auth = getAuth(getApp());
waitForUser(auth, user => { });

The samples above follow different structures. However, they have nearly the same bundle size. This is because they import the same pieces of functionality from the Firebase SDK.

A compatibility library for an easier upgrade

We understand that having to update code can be a lot of work. While your end users will experience real benefits in terms of bundle size and therefore page load performance, we want to make sure you can upgrade with minimal friction.

To simplify the upgrade process we have provided a compatibility library that ships with the version 9 npm package and is also available via a CDN script. To use the compatibility library via npm, you only need to update the import path.

Image of code snippet with text saying Upgrade easily with compat
Image of code snippet with text saying Upgrade easily with compat
import { initializeApp } from 'firebase/compat/app';
import 'firebase/compat/auth;
import { onAuthStateChanged } from 'firebase/auth';

const firebaseApp = firebase.initializeApp({ /* config */ });
const auth = firebaseApp.auth();
onAuthStateChanged(auth, user => { console.log(user); });

This library mirrors the version 8 API while using the version 9 library under-the-hood. It does not work with tree shaking, but it allows you to use the old and new APIs together. We refer to this as interop-mode.

Once your code is fully upgraded, you can remove the compatibility library and begin to see any potential tree shaking benefits.

Introducing Firestore Lite

We’re also excited to announce our newest library, Firestore Lite. Firestore Lite provides a REST based API for Firestore at a fraction of the bundle size. The library does not have support for realtime reads or any offline abilities. It is ideal for users who use Firestore for one-time reads.

Image of code snippet with text saying Firestore Lite
Image of code snippet with text saying Firestore Lite
import { initializeApp } from 'firebase/app';
import { getFirestore, collection, getDocs } from 'firebase/firestore/lite';

const firebaseApp = initializeApp({ /* config */ });
const db = getFirestore();
const snapshot = await getDocs(collection('cities'));

Another benefit of Firestore Lite is that it can be used with the fully featured Firestore package. Some pages may only require single reads whereas some may need realtime streams. You have the option of using either (or both) in your web app where needed.

Moving away from the browser’s global window object

Another significant development in the new SDK is the move towards JavaScript modules (ESM) and away from the browser’s global window object.

Historically libraries have been loaded and managed via a namespace on the window, such as window.firebase. This technique does not allow for tree shaking and lacks other benefits of the JavaScript module system.

This release prioritizes usage of Firebase via JavaScript modules. We still provide support for the window via a CDN script for the compatibility library. However, we only recommend using it as a path to upgrading to the module based SDK.

Get started today

We are really excited about the new JavaScript SDK and we want to hear from you as well. We’ll be watching and responding to our GitHub discussion board for any questions or comments. If you’ve seen any size reductions in your codebase and want to share, let us know!