Fix "Default condition should be last one" (Firebase)
One Firebase release put "default" before "browser" in the package.json exports map of 30 packages, and webpack's resolver refuses that. Here is the exact error, the diff that caused it, the release that fixed it, and how to find any other package in node_modules doing the same thing.
On 2 February 2023, a routine yarn add firebase started failing Next.js and
Create React App builds on the very first Firebase import:
Module not found: Default condition should be last one
> 1 | import { initializeApp, getApps, getApp } from 'firebase/app';
2 | import { getAnalytics, isSupported } from 'firebase/analytics';
3 | import { getAuth } from 'firebase/auth';That is the report in
the GitHub issue firebase/firebase-js-sdk#7005,
filed against [email protected] about an hour after it was published. The
reporter noted that the import order did not matter and that rolling back to
9.16.0 made the error disappear; dozens of people confirmed the same within
hours, on projects that had not changed a line. A maintainer reproduced it,
merged a fix, and shipped 9.17.1 as an emergency release the next day.
The error still turns up in 2026: on projects with an old lockfile, on
toolchains pinned to an older webpack, and from packages other than Firebase
that made the same mistake. This article explains the resolver rule the
message refers to, shows the exact exports diff between 9.17.0 and 9.17.1,
and gives the fixes in the order you should try them.
Root cause: "default" is a wildcard, and it was not last#
Node's conditional exports
let a package map one specifier to different files depending on the
environment. The rule that matters here is stated in the Node docs: within
an exports object, conditions are matched in object order, and "default"
is the condition that always matches. Anything written after "default" can
never be selected.
Here is firebase/app in the broken release, read from the published
tarball (the npm registry's metadata reorders keys, so npm view firebase exports is not a reliable way to see this; inspect
node_modules/firebase/package.json instead):
"./app": {
"types": "./app/dist/app/index.d.ts",
"node": {
"require": "./app/dist/index.cjs.js",
"import": "./app/dist/index.mjs"
},
"default": "./app/dist/esm/index.esm.js",
"browser": {
"require": "./app/dist/index.cjs.js",
"import": "./app/dist/esm/index.esm.js"
}
}And the same entry in 9.17.1, after PR #7007 "Fix exports fields" moved the key:
"./app": {
"types": "./app/dist/app/index.d.ts",
"node": {
"require": "./app/dist/index.cjs.js",
"import": "./app/dist/index.mjs"
},
"browser": {
"require": "./app/dist/index.cjs.js",
"import": "./app/dist/esm/index.esm.js"
},
"default": "./app/dist/esm/index.esm.js"
}The regression came from PR #6981, which reshaped the exports maps to add
node/browser splits and left default in the middle. Checking every
tarball in the dependency tree, 9.17.0 shipped the wrong order in the
firebase package itself (28 subpath entries) and in ten @firebase/*
packages: auth, auth-compat, database, database-compat, firestore,
firestore-compat, functions, functions-compat, storage and util.
9.17.1 has zero, and so does the current [email protected].
Why webpack throws and Node does not#
Node applies the ordering rule quietly: it walks the keys, hits default,
and returns that file. The browser block below it is simply dead.
webpack delegates resolution to enhanced-resolve, and up to version
5.16.1 that library asserted the rule instead of tolerating it:
// enhanced-resolve/lib/util/entrypoints.js (<= 5.16.1)
// assert default. Could be last only
if (i !== last) {
if (condition === "default") {
throw new Error("Default condition should be last one");
}
}webpack wraps the thrown error as a Module not found failure, which is why
the message points at your import line rather than at Firebase's
package.json. enhanced-resolve 5.17.0 (4 June 2024, release note:
"Allow default condition to be anywhere") dropped the assertion and now
behaves like Node. That is why a fresh Next.js 16 project compiles
[email protected] without complaint under both webpack and Turbopack, and
why the error you are seeing today means your build resolves modules with a
copy of enhanced-resolve from before June 2024: either your lockfile pins
it at 5.16.1 or lower, or your framework embeds its own webpack (Next.js
does, so there the Next.js version decides).
Either way, the offending package is still misconfigured; a newer resolver
just hides it by picking default early. Fix the package, not only the
resolver.
Fix 1: upgrade Firebase and reinstall cleanly#
For Firebase specifically, any version from 9.17.1 onwards is correct. In 2026 that means the current major:
npm install firebase@latestThen follow the maintainer's advice from the thread, because this is where
most "I upgraded and it still fails" reports came from: package managers do
not always overwrite the nested node_modules/@firebase/**/package.json
files on an upgrade or downgrade.
rm -rf node_modules package-lock.json # or yarn.lock / pnpm-lock.yaml
npm installVerify the installed tree before rebuilding:
node -e "console.log(require('firebase/package.json').version)"If the version printed is still 9.17.0, a lockfile or a transitive dependency is holding it; go to Fix 3.
Moving from 9.x to 12.x is otherwise uneventful for the modular API, but two
follow-up errors from the thread are worth knowing. export 'default' (imported as 'firebase') was not found in 'firebase/app' means the file uses
the v8 namespace import; switch to named imports
(import { initializeApp } from 'firebase/app') or, for legacy code,
firebase/compat/app. And FirebaseError: Expected first argument to collection() after the upgrade is an initialisation-order problem, covered in
the collection() fix.
Fix 2: pin an exact version when you cannot upgrade today#
The thread's most-upvoted workaround was to remove the caret. "firebase": "^9.16.0" allows 9.17.0; "firebase": "9.16.0" does not:
{
"dependencies": {
"firebase": "9.16.0"
}
}Reinstall afterwards. If you want every future npm install <pkg> to pin
exact versions, add a .npmrc at the project root:
save-exact=trueTreat this as a stop-gap. 9.16.0 predates the fix, so it only works because it also predates the bug; you still want 9.17.1 or later for the security and Auth fixes that followed.
Fix 3: override a transitive dependency#
When a library you depend on declares [email protected] itself (or a package
with the same exports mistake), force the version from your root
package.json:
{
"overrides": {
"firebase": "12.18.0"
}
}Yarn Classic uses "resolutions" with the same shape; pnpm uses
"pnpm": { "overrides": { ... } }. Delete the lockfile and reinstall so the
override is applied to the whole tree, then rerun the version check above.
Fix 4: find the package that is actually at fault#
If the import in the error is not Firebase, or the error persists after Firebase is fixed, scan the tree. This is a trimmed version of the script a commenter shared in the thread, updated for nested conditions:
// scripts/check-exports-order.mjs
import { readFileSync, globSync } from 'node:fs'
function violations(map, path = '') {
if (!map || typeof map !== 'object') return []
const keys = Object.keys(map)
const i = keys.indexOf('default')
const out = i !== -1 && i !== keys.length - 1 ? [`${path}: [${keys.join(', ')}]`] : []
for (const k of keys) out.push(...violations(map[k], `${path}/${k}`))
return out
}
for (const file of globSync('node_modules/**/package.json')) {
try {
const pkg = JSON.parse(readFileSync(file, 'utf8'))
const bad = violations(pkg.exports, pkg.name ?? file)
if (bad.length) console.log(`${pkg.name}@${pkg.version}\n ${bad.join('\n ')}`)
} catch {
// ignore unreadable or partial package.json files
}
}Run it with node scripts/check-exports-order.mjs on Node 22 or later, where
fs.globSync exists (on older Node, swap in the glob package). Against a
tree with [email protected] installed it prints exactly the eleven packages
listed above. Every line it prints is a package that a
pre-5.17 resolver will reject and a post-5.17 resolver will resolve to
default regardless of your target. Upgrade or override each one, and open
an issue upstream with the output; it is a one-line fix for the maintainer.
What not to do#
- Do not delete or hand-edit
node_modules/firebase/package.json. It works until the next install and hides the problem from teammates and CI. - Do not switch the whole project to
firebase/compatto dodge the error.compatshipped the same broken exports in 9.17.0; the thread's "compat fixed it" report coincided with the downgrade, not the import style. - Do not blame Next.js. The message links to the generic Module not found page, but none of the usual causes on that page (aliases, case sensitivity, missing installs) apply here. The resolver is telling you about a third party's metadata.
- Do not leave the Firebase API key work half done while you are in
here. If the upgrade touched your
initializeAppconfig, re-read whether the key can be public and make sure the Security Rules are what protects the project.
Production notes#
- Pin Firebase to an exact version in applications and let Dependabot or Renovate propose bumps. 9.17.0 was live for 22 hours; a caret range pulled it into every CI run in that window.
- Keep your bundler's resolver current. A lockfile that still resolves
enhanced-resolvebelow 5.17.0 will keep throwing on any package with this mistake, while everyone else's build passes. If a Vercel or Cloudflare build fails with a resolver error your laptop does not reproduce, compare the two lockfiles first; the encoding module error is the same class of "works locally, fails in CI" mismatch. - If Firebase is a small part of the stack, this incident is a reasonable moment to re-evaluate; the Supabase vs Firebase comparison covers the trade-offs for an EU-hosted Postgres backend against the Firebase suite.
Summary#
Default condition should be last one means a package's exports map lists
"default" before another condition, which makes that condition unreachable.
Firebase shipped that mistake in 9.17.0 and fixed it in 9.17.1 within a day;
webpack's resolver stopped throwing on it in June 2024 but still resolves the
wrong file. Upgrade to a current Firebase, reinstall with a clean lockfile,
override transitive pins, and scan node_modules for any other package
carrying the same ordering bug.
Related#
Frequently Asked Questions
One email a month — no fluff
RLS gotchas, Next.js cache debugging, and the one Supabase setting that bit me last month.
Continue Reading
Firebase Auth IDBDatabase Transaction Error: 2026 Fix
Firebase Auth stores its session in an IndexedDB database called firebaseLocalStorageDb. When that connection closes mid-session, sign-in throws InvalidStateError. Here is the cause, the SDK version that changed the behaviour, and a Next.js App Router setup that degrades gracefully.
FirebaseError: Expected first argument to collection() — Fix
When Firestore throws 'Expected first argument to collection()', it's almost always a missing Firestore instance. Learn the exact fix for Next.js and v9 modular SDK.
Fix ChunkLoadError: Loading Chunk Failed in Next.js
"ChunkLoadError: Loading chunk 5760 failed" almost always means a user has an old tab open after you shipped a new deploy. The fix is configuration — deploymentId, build IDs, and CDN headers — not a try/catch.
Browse by Topic
Find stories that matter to you.
