DEV Community

Cover image for FirebaseError: Expected first argument to collection() — Fix
Mahdi BEN RHOUMA
Mahdi BEN RHOUMA

Posted on Originally published at iloveblogs.blog

FirebaseError: Expected first argument to collection() — Fix

TL;DR

I hit FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore while writing a Next.js page that queried Firestore. The fix is passing db as the first argument to collection(), where db is the return value of getFirestore() from firebase/firestore.

If that doesn't work, scroll to verify the fix — there are two common variants this guide also covers.

  • Symptom: FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
  • Root cause: The v9 modular SDK requires the Firestore instance (db) as the first argument to collection(); legacy v8 code or missing initialization passes an invalid reference.
  • Fix: Ensure you call getFirestore(app) once, store the result, and always pass it as the first argument.
  • Verification: After the fix, collection(db, 'cities') returns a CollectionReference without error, and you can chain .get() or onSnapshot() as expected.

What you'll see

FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
    at collection (index.mjs:…)
    at …
Enter fullscreen mode Exit fullscreen mode

It happens when your Next.js component or API route tries to call collection() (or any function that depends on it, like getDocs, onSnapshot, etc.) after migrating from the namespaced (v8) Firebase API to the modular (v9) one. The behavior is the same across development (next dev), production builds, and even in Cloud Functions if you've switched to the new tree-shakeable API.

The error, decoded

The error message says the first argument you passed to collection() is not a Firestore instance, a CollectionReference, or a DocumentReference. In the v9 modular SDK, collection() expects two arguments:

  1. A Firestore instance (the thing returned by getFirestore())
  2. A path string (or a reference chain)

If you omit the first argument — or pass something else, like the module default export — you'll see this error.

I first ran into this after upgrading from the old firebase/firestore namespace where you could just write db.collection('cities'). The new tree-shakeable API separates functions from the instance, so a direct call like collection('cities') is ambiguous: the SDK doesn't know which database you're targeting.

Why Firestore v9 doesn't auto‑resolve the database

Under the hood, the v9 SDK decouples functions from a single, global Firestore object. In v8, firebase.firestore() returned a Firestore instance and all calls like collection() were methods on that instance. In v9, collection() is a standalone function imported from firebase/firestore. To be tree-shakeable, it cannot rely on an implicit database — you must hand it the database explicitly.

The code that triggers the error typically looks like this:

// ❌ Broken: missing db argument
import { collection, getDocs } from 'firebase/firestore';

const citiesCol = collection('cities');
const snapshot = await getDocs(citiesCol);
Enter fullscreen mode Exit fullscreen mode

Here, collection('cities') calls the function with a single string argument. Firebase expects a Firestore instance as the first argument, not a string, so it throws the error.

The fix: always pass the Firestore instance as the first argument

The corrected version is:

// ✅ Fixed
import { collection, getDocs, getFirestore } from 'firebase/firestore';
import { initializeApp } from 'firebase/app';

// Initialize Firebase
const app = initializeApp(yourConfig);
const db = getFirestore(app);

// Now collection() knows which Firestore instance to use
const citiesCol = collection(db, 'cities');
const snapshot = await getDocs(citiesCol);
Enter fullscreen mode Exit fullscreen mode

That single change — adding db as the first argument — resolves the error because the function now receives a valid FirebaseFirestore object.

Step by step in a Next‑js project

If you're inside a Next.js app, the cleanest way to avoid this error is to centralize your Firebase initialization.

  1. Create lib/firebase.js and export the db instance.
  2. In your page or component, import db and pass it to every Firestore function.
  3. Replace any old-style collection('path') calls with collection(db, 'path').

A typical Next.js setup file:

// lib/firebase.js
import { initializeApp, getApps, getApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  // ... other config
};

const app = !getApps().length ? initializeApp(firebaseConfig) : getApp();
const db = getFirestore(app);

export { db };
Enter fullscreen mode Exit fullscreen mode

Then in a page:

// pages/index.js
import { collection, getDocs } from 'firebase/firestore';
import { db } from '../lib/firebase';

export async function getServerSideProps() {
  const citiesCol = collection(db, 'cities');
  const snapshot = await getDocs(citiesCol);
  const cities = snapshot.docs.map(doc => doc.data());

  return { props: { cities } };
}
Enter fullscreen mode Exit fullscreen mode

Two patterns that still trip you up

Even after adding the db argument, developers sometimes hit the same error because of a subtle misconfiguration. Here are the two most common variants I see.

Pattern 1 — Passing getFirestore instead of calling it

// ❌ Passing the function reference, not an instance
import { collection, getFirestore } from 'firebase/firestore';
const col = collection(getFirestore, 'cities');
Enter fullscreen mode Exit fullscreen mode

The error occurs because getFirestore is a function, not a Firestore instance. The fix is to invoke it:

const db = getFirestore(app);
const col = collection(db, 'cities');
Enter fullscreen mode Exit fullscreen mode

Pattern 2 — Using the admin SDK incorrectly in Next.js API routes

If you use firebase-admin for server‑side Firestore access (e.g., inside API routes), the admin.firestore() call returns a Firestore instance that behaves differently. A similarly‑named error can appear if you accidentally mix the client SDK’s collection function with the admin SDK’s namespace. For example:

// ❌ Mixing admin and client functions
const { collection } = require('firebase/firestore');
const admin = require('firebase-admin');
const db = admin.firestore();
const col = collection(db, 'cities'); // still works, but be careful with environment
Enter fullscreen mode Exit fullscreen mode

It works if db is a plain object that matches the expected interface, but on some setups the admin SDK’s Firestore object doesn't share the same prototype, causing a cryptic type‑error variation. The safer route is to use the admin SDK’s own method:

const col = db.collection('cities');
Enter fullscreen mode Exit fullscreen mode

However, for client‑side Next.js pages, stick to the modular client SDK as described in the fix above.

Verify the fix

After applying the change, run your dev server:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Visit the page that queries Firestore. You should see the data rendered without the error. If you want a minimal sanity check, add a console.log to confirm the returned reference type:

import { collection, getFirestore } from 'firebase/firestore';
import { app } from '../lib/firebase';

const db = getFirestore(app);
const col = collection(db, 'test');
console.log(col.type); // -> 'collection'
Enter fullscreen mode Exit fullscreen mode

The type property prints 'collection', proving that you now have a valid CollectionReference.

If you are still seeing the error, double‑check that your db export is indeed the result of getFirestore(app). A common oversight in Next.js is that lib/firebase.js might export a promise if the Firebase init is lazy‑loaded. Use a synchronous pattern or a module‑level init guard as shown above.

Keep it from coming back

Add TypeScript types to catch the mistake at compile time. If you define your db export with the correct type, passing a wrong argument will produce a diagnostic:

// lib/firebase.ts
import { getFirestore, Firestore } from 'firebase/firestore';
import { initializeApp, getApps, getApp } from 'firebase/app';

let db: Firestore;

const app = !getApps().length ? initializeApp(config) : getApp();
db = getFirestore(app);

export { db };
Enter fullscreen mode Exit fullscreen mode

Now any call to collection(db, '...') will be type‑checked. If you accidentally write collection(getFirestore, '...'), TypeScript will complain that a function is not assignable to Firestore.

For an additional layer, you can wrap the Firestore calls in a custom hook or utility that always expects db as a parameter, avoiding ad‑hoc calls in components.


FAQ

1. Can I still use the old syntax with firebase/firestore/compat?

Yes, Firebase provides a compat library that mimics v8 behavior. If you stick to the compat layer you can continue writing db.collection('cities'). However, you lose the tree‑shaking benefits and the compat layer is not recommended for new projects. The modular API is the forward path, and understanding how collection() expects an instance avoids almost all errors you'll hit in Next.js and modern frontend frameworks. I cover this trade‑off in Cloud Firestore vs Realtime Database in 2026, where the modular improvement is particularly noticeable for bundle size.

2. Does this error also happen if I use doc() instead of collection()?

Yes, the same principle applies. doc() expects a DocumentReference, a string path starting from the Firestore root, or a Firestore instance followed by a path. In v9, doc(db, 'cities/LA') works, but doc('cities/LA') fails with a similar message. Always pass the database instance as the first argument.

3. What if I’m using Firebase’s React Native SDK?

The error is identical. React Native uses the same modular Firestore package. Initialize Firebase in your app’s entry point, call getFirestore(app), and pass the returned db to all Firestore functions. If you’re migrating from a React Native project that relied on an older version, the fix is exactly the same. The only difference is that you might need to configure persistence first, but the argument requirement remains unchanged.


Related


Originally published at https://www.iloveblogs.blog

Top comments (0)