Apps currently using Firebase Web SDK version 8 or earlier should consider migrating to version 9 using the instructions in this guide.
This guide assumes that you are familiar with version 8 and that you will take advantage of a module bundler such as webpack or Rollup for upgrading and ongoing version 9 development.
Using a module bundler in your development environment is strongly recommended. If you don't use one, you won't be able to take advantage of version 9's main benefits in reduced app size. You'll need npm or yarn to install the SDK.
The upgrade steps in this guide will be based around an imaginary web app that uses the Authentication and Cloud Firestore SDKs. By working through the examples, you can master the concepts and practical steps required to upgrade all supported Firebase Web SDKs.
About the compat libraries
There are two types of libraries available for Firebase Web SDK version 9:
- Modular - a new API surface designed to facilitate tree-shaking (removal of unused code) to make your web app as small and fast as possible.
- Compat - a familiar API surface which is fully compatible with the version 8 SDK, allowing you to upgrade to version 9 without changing all of your Firebase code at once. Compat libraries have little to no size or performance advantages over their version 8 counterparts.
This guide assumes that you will take advantage of the version 9 compat libraries to facilitate your upgrade. These libraries allow you to continue using version 8 code alongside code refactored for version 9. This means you can compile and debug your app more easily as you work through the upgrade process.
For apps with a very small exposure to the Firebase Web SDK – for example, an app that makes only a simple call to the Authentication APIs – it may be practical to refactor version 8 code without using the version 9 compat libraries. If you are upgrading such an app, you can follow the instructions in this guide for "version 9 modular" without using the compat libraries.
About the upgrade process
Each step of the upgrade process is scoped so that you can finish editing the source for your app and then compile and run it without breakage. In summary, here's what you'll do to upgrade an app:
- Add the version 9 libraries and the compat libraries to your app.
- Update import statements in your code to v9 compat.
- Refactor code for a single product (for example, Authentication) to the modular style.
- Optional: at this point, remove the Authentication compat library and compat code for Authentication in order to realize the app size benefit for Authentication before continuing.
- Refactor functions for each product (for example, Cloud Firestore, FCM, etc.) to the modular style, compiling and testing until all areas are complete.
- Update initialization code to the modular style.
- Remove all remaining version 9 compat statements and compat code from your app.
Get the version 9 SDK
To get started, get the version 9 libraries and compat libraries using npm:
npm i firebase@9.22.1 # OR yarn add firebase@9.22.1
Update imports to v9 compat
In order to keep your code functioning after updating your dependency from v8 to v9 beta, change your import statements to use the "compat" version of each import. For example:
Before: version 8
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
After: version 9 compat
// v9 compat packages are API compatible with v8 code
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
Refactor to the modular style
While the version 8 APIs are based on a dot-chained namespace and service
pattern, version 9's modular approach means that your code will be organized
principally around functions. In version 9, the firebase/app
package and
other packages do not return a comprehensive export that contains all the
methods from the package. Instead, the packages export individual functions.
In version 9, services are passed as the first argument, and the function then uses the details of the service to do the rest. Let's examine how this works in two examples that refactor calls to the Authentication and Cloud Firestore APIs.
Example 1: refactoring an Authentication function
Before: version 9 compat
The version 9 compat code is identical to the version 8 code, but the imports have changed.
import firebase from "firebase/compat/app";
import "firebase/compat/auth";
const auth = firebase.auth();
auth.onAuthStateChanged(user => {
// Check for user status
});
After: version 9 modular
The getAuth
function takes firebaseApp
as its first parameter.
The onAuthStateChanged
function is not chained from the auth
instance as it would be
in version 8; instead, it's a free
function which takes auth
as its first parameter.
import { getAuth, onAuthStateChanged } from "firebase/auth";
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
// Check for user status
});
Update handling of Auth method getRedirectResult
Version 9 introduces a breaking change in getRedirectResult
. When no redirect operation is called, Version 9 returns null
as opposed to Version 8, which returned a UserCredential
with a null
user.
Before: version 9 compat
const result = await auth.getRedirectResult()
if (result.user === null && result.credential === null) {
return null;
}
return result;
After: version 9 modular
const result = await getRedirectResult(auth);
// Provider of the access token could be Facebook, Github, etc.
if (result === null || provider.credentialFromResult(result) === null) {
return null;
}
return result;
Example 2: refactoring a Cloud Firestore function
Before: version 9 compat
import "firebase/compat/firestore"
const db = firebase.firestore();
db.collection("cities").where("capital", "==", true)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
After: version 9 modular
The getFirestore
function takes firebaseApp
as its first parameter, which
was returned from initializeApp
in an earlier example. Note how the
code to form a query is very different in version 9; there is no chaining, and
methods such as query
or where
are now exposed as free functions.
import { getFirestore, collection, query, where, getDocs } from "firebase/firestore";
const db = getFirestore(firebaseApp);
const q = query(collection(db, "cities"), where("capital", "==", true));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
Update references to Firestore DocumentSnapshot.exists
Version 9 introduces a breaking change in which the property
firestore.DocumentSnapshot.exists
has been changed to a method. The
functionality is essentially the same (testing whether a document exists)
but you must refactor your code to use the v9 method as shown:
Before: version 9 compat
if (snapshot.exists) {
console.log("the document exists");
}
After: version 9 modular
if (snapshot.exists()) {
console.log("the document exists");
}
Example 3: combining version 8 and version 9 code styles
Using the compat libraries during upgrade allows you to continue using version 8 code alongside code refactored for version 9. This means you can keep existing version 8 code for Cloud Firestore while you refactor Authentication or other Firebase SDK code to the version 9 style, and still successfully compile your app with both code styles. The same is true for version 8 and version 9 code within a product such as Cloud Firestore; new and old code styles can coexist, as long as you are importing the compat packages:
import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import { getDoc } from 'firebase/firestore'
const docRef = firebase.firestore().doc();
getDoc(docRef);
Keep in mind that, although your app will compile, you won't get the app size benefits of the modular code until you fully remove the compat statements and code from your app.
Update initialization code
Update your app's initialization code to use new modular version 9 syntax. It is
important to update this code after you have completed refactoring all the
code in your app; this is because firebase.initializeApp()
initializes global
state for both the compat and modular APIs, whereas the modular
initializeApp()
function initializes only the state for modular.
Before: version 9 compat
import firebase from "firebase/compat/app"
firebase.initializeApp({ /* config */ });
After: version 9 modular
import { initializeApp } from "firebase/app"
const firebaseApp = initializeApp({ /* config */ });
Remove compat code
To realize the size benefits of the version 9 modular SDK, you should eventually
convert all invocations to the modular style shown above and remove all of the
import "firebase/compat/*
statements from your code. When you are done, there
should be no more references to the firebase.*
global namespace or any other
code in the version 8 SDK style.
Using the compat library from the window
The version 9 SDK is optimized to work with modules rather than the browser's
window
object. Previous versions of the library allowed the loading and
management of Firebase by using the window.firebase
namespace. This is not
recommended going forward as it does not allow for unused code elimination.
However, the compat version of the JavaScript SDK does work with the window
for developers who prefer not to immediately begin the modular upgrade path.
<script src="https://www.gstatic.com/firebasejs/9.22.1/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.1/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.1/firebase-auth-compat.js"></script>
<script>
const firebaseApp = firebase.initializeApp({ /* Firebase config */ });
const db = firebaseApp.firestore();
const auth = firebaseApp.auth();
</script>
The compatibility library uses the modular version 9 code under the hood and provides it with the same API as the version 8 SDK; this means you can refer to the version 8 API reference and version 8 code snippets for details. This method is not recommended for long term use, but as a start to upgrade to the fully modular version 9 library.
Benefits and limitations of version 9
The fully modularized version 9 has these advantages over earlier versions:
- Version 9 enables a dramatically reduced app size. It adopts the modern JavaScript Module format, allowing for "tree shaking" practices in which you import only the artifacts your app needs. Depending on your app, tree-shaking with version 9 can result in 80% less kilobytes than a comparable app built using version 8.
- Version 9 will continue to benefit from ongoing feature development, while version 8 will be frozen at a point in the future.