On June 8, 2026, firebase-admin 14 shipped and removed the namespaced API: admin.firestore(), admin.auth(), admin.messaging() and friends are gone. Every call has to move to the modular entry points (getFirestore(), getAuth(), getMessaging()…).
Four months later, I looked at the npm registry's per-version download counts for the last week.
Out of 8,995,732 downloads that week:
| Major | Share |
|---|---|
| v14 (current) | 26.9% |
| v13 | 47.7% |
| v12 | 19.6% |
| v11 | 4.1% |
| v10 and older | 1.7% |
So 73% of installs are still on v13 or older. v13 alone is downloaded almost twice as often as the version that replaced it.
A caveat before anyone jumps in: npm downloads are not projects. Most of these come from CI pipelines reinstalling dependencies, so one busy repository counts many times. But that also means these are builds that run every day on a version line that no longer gets new features.
What actually changed
The modular API has existed since v10, so most of the migration is mechanical:
// v13 and older (namespaced)
import * as admin from "firebase-admin";
admin.initializeApp();
const db = admin.firestore();
await db.collection("orders").add({
createdAt: admin.firestore.FieldValue.serverTimestamp(),
});
const user = await admin.auth().getUser(uid);
// v14 (modular)
import { initializeApp } from "firebase-admin/app";
import { getFirestore, FieldValue } from "firebase-admin/firestore";
import { getAuth } from "firebase-admin/auth";
initializeApp();
const db = getFirestore();
await db.collection("orders").add({
createdAt: FieldValue.serverTimestamp(),
});
const user = await getAuth().getUser(uid);
Two things make it less trivial than it looks:
-
Node.js 22 is required. If your
engines.nodestill allows Node 18 or 20, the upgrade is not just a code change, it is a runtime change for your servers, functions and CI images. -
Peer dependencies. If you use Cloud Functions,
firebase-functions6.x does not acceptfirebase-admin14 in its peer range. You needfirebase-functions7.x at the same time.
And a few patterns cannot be migrated by search-and-replace at all:
- an
adminnamespace exported and used by other modules (module.exports = { admin }); -
admin.firestorepassed around as a value, or used both as a function and as a namespace in the same file; - dynamic access like
admin[service]().
Those are exactly the places where a bulk regex breaks a codebase silently.
Why teams stay behind
From the projects I looked at, the reasons are boringly human:
- Nothing is broken today. v13 still works, so the upgrade never wins against feature work.
-
The diff touches many files. Every file that imports
firebase-adminchanges, which makes the pull request scary to review. - The runtime bump is the real blocker. Node 22 means touching deployment config, not just code.
One example that encouraged me: I opened an issue on an open-source project explaining exactly which calls had to move. Three days later, the maintainer opened a pull request upgrading to v14 and Node 22, and merged it the next day (crowdcad#129). The hard part was never the code. It was knowing precisely what to change and trusting that nothing else would break.
How to migrate without guessing
Whatever tool you use, the safe sequence is:
- Upgrade Node.js to 22 first, in CI and production, while still on v13.
- Move imports to the modular entry points file by file; v13 supports both styles, so you can ship this before bumping the version.
- Search for the patterns above (exported namespace,
admin[...],admin.firestoreused as a value) and fix them by hand. - Bump
firebase-adminto^14(andfirebase-functionsto^7if you use it), regenerate the lockfile, then run your type checker and tests.
Full disclosure: I built a tool for this
I'm Ivan, a backend developer in Cameroon. I got tired of doing these upgrades by hand, so I built UpstreamFix, an open-source (MIT) CLI that does steps 2 and 3 for you and refuses to guess:
npx upstreamfix migrate firebase-admin@14
It reads your code through the TypeScript AST, shows a preview of every change, and lists anything it cannot migrate safely (like an exported admin namespace) as a manual finding instead of rewriting it. Nothing is written unless you ask for it, and it never merges anything.
The source is on GitHub: ivanDev237/upstreamfix. Feedback and bug reports are very welcome, especially on code it gets wrong.
Your turn
If you are still on v13 (or v12), what is actually keeping you there: the Node 22 bump, firebase-functions, the size of the diff, or just time? I'm curious whether the blocker is the same for everyone.

Top comments (0)