Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Get Document ID in Firestore

To get a document ID in Firestore, access the id property on a DocumentSnapshot or QueryDocumentSnapshot. When querying with getDocs, iterate over the snapshot and read doc.id for each document. When adding with addDoc, the returned DocumentReference contains the auto-generated ID. You can also use the documentId() sentinel in queries to filter by document ID directly.

What you'll learn

  • How to access the document ID from query results and single document reads
  • How to get the auto-generated ID after adding a document with addDoc
  • How to use documentId() to filter queries by document ID
  • How to choose between auto-generated and custom document IDs
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read10-15 minFirebase (Spark and Blaze plans), firebase v9+ modular SDKMarch 2026RapidDev Engineering Team
TL;DR

To get a document ID in Firestore, access the id property on a DocumentSnapshot or QueryDocumentSnapshot. When querying with getDocs, iterate over the snapshot and read doc.id for each document. When adding with addDoc, the returned DocumentReference contains the auto-generated ID. You can also use the documentId() sentinel in queries to filter by document ID directly.

Getting Document IDs in Firestore Queries and Writes

Every Firestore document has a unique ID within its collection. This tutorial covers all the ways to access and use document IDs: reading IDs from query results, getting the auto-generated ID after creating a document, querying by document ID, and deciding when to use custom IDs instead of auto-generated ones.

Prerequisites

  • A Firebase project with Firestore enabled
  • The firebase npm package installed (v9 or later)
  • Firebase initialized in your app with a valid config object
  • At least one collection with documents in Firestore

Step-by-step guide

1

Get document IDs from a query result

When you call getDocs on a query or collection reference, you get a QuerySnapshot containing an array of QueryDocumentSnapshot objects. Each snapshot has an id property that contains the document's ID within its collection. Use forEach or the docs array to iterate over results and access both the ID and the data.

typescript
1import { collection, getDocs, getFirestore } from 'firebase/firestore'
2
3const db = getFirestore()
4
5async function getAllUsers() {
6 const querySnapshot = await getDocs(collection(db, 'users'))
7
8 querySnapshot.forEach((doc) => {
9 console.log('Document ID:', doc.id)
10 console.log('Document data:', doc.data())
11 })
12
13 // Or use the docs array for mapping:
14 const users = querySnapshot.docs.map((doc) => ({
15 id: doc.id,
16 ...doc.data(),
17 }))
18
19 return users
20}

Expected result: Each document's ID and data are logged, and the users array contains objects with the id property.

2

Get the document ID from a single document read

When you use getDoc to read a single document by reference, the returned DocumentSnapshot also has the id property. Check snapshot.exists() first to confirm the document exists before accessing data. The document ID matches the last segment of the reference path.

typescript
1import { doc, getDoc, getFirestore } from 'firebase/firestore'
2
3const db = getFirestore()
4
5async function getUserById(userId: string) {
6 const docRef = doc(db, 'users', userId)
7 const docSnap = await getDoc(docRef)
8
9 if (docSnap.exists()) {
10 console.log('ID:', docSnap.id) // Same as userId
11 console.log('Data:', docSnap.data())
12 return { id: docSnap.id, ...docSnap.data() }
13 } else {
14 console.log('Document not found')
15 return null
16 }
17}

Expected result: The document ID and data are returned if the document exists, or null if not found.

3

Get the auto-generated ID after adding a document

When you use addDoc to create a document, Firestore auto-generates a unique 20-character ID. The returned DocumentReference contains this ID in its id property. You can use this ID immediately to update the document or store it as a reference in another document.

typescript
1import { collection, addDoc, getFirestore } from 'firebase/firestore'
2
3const db = getFirestore()
4
5async function createPost(title: string, content: string) {
6 const docRef = await addDoc(collection(db, 'posts'), {
7 title,
8 content,
9 createdAt: new Date(),
10 })
11
12 console.log('New document created with ID:', docRef.id)
13 return docRef.id
14}

Expected result: The new document is created and its auto-generated ID is returned.

4

Generate an ID before writing with doc()

Sometimes you need the document ID before writing the data, for example to include the ID as a field inside the document or to reference it in another document in the same batch. Call doc() on a collection reference without arguments to generate a new DocumentReference with an auto-generated ID. Then use setDoc to write data to that reference.

typescript
1import { collection, doc, setDoc, getFirestore } from 'firebase/firestore'
2
3const db = getFirestore()
4
5async function createUserWithKnownId() {
6 // Generate a reference with an auto-ID (no network call yet)
7 const newUserRef = doc(collection(db, 'users'))
8 const userId = newUserRef.id
9
10 console.log('Pre-generated ID:', userId)
11
12 // Write the document, including its own ID as a field
13 await setDoc(newUserRef, {
14 id: userId,
15 name: 'Alice',
16 email: 'alice@example.com',
17 createdAt: new Date(),
18 })
19
20 return userId
21}

Expected result: A document is created with a known ID that is also stored as a field within the document.

5

Query documents by their ID using documentId()

Firestore provides the documentId() sentinel for querying by document ID in where clauses. This is useful for fetching a set of documents by their IDs (for example, from a list of references stored in another document). Use the 'in' operator to fetch up to 30 documents by ID in a single query.

typescript
1import { collection, query, where, getDocs, documentId, getFirestore } from 'firebase/firestore'
2
3const db = getFirestore()
4
5async function getUsersByIds(userIds: string[]) {
6 // 'in' operator supports up to 30 values
7 const q = query(
8 collection(db, 'users'),
9 where(documentId(), 'in', userIds)
10 )
11
12 const snapshot = await getDocs(q)
13 return snapshot.docs.map((doc) => ({
14 id: doc.id,
15 ...doc.data(),
16 }))
17}

Expected result: Only documents whose IDs match the provided list are returned.

Complete working example

firestore-document-ids.ts
1import {
2 getFirestore,
3 collection,
4 doc,
5 addDoc,
6 setDoc,
7 getDoc,
8 getDocs,
9 query,
10 where,
11 documentId,
12} from 'firebase/firestore'
13
14const db = getFirestore()
15
16export interface UserDoc {
17 id: string
18 name: string
19 email: string
20 createdAt: Date
21}
22
23// Get all documents with their IDs
24export async function getAllUsers(): Promise<UserDoc[]> {
25 const snapshot = await getDocs(collection(db, 'users'))
26 return snapshot.docs.map((doc) => ({
27 id: doc.id,
28 ...(doc.data() as Omit<UserDoc, 'id'>),
29 }))
30}
31
32// Get a single document by ID
33export async function getUserById(userId: string): Promise<UserDoc | null> {
34 const docSnap = await getDoc(doc(db, 'users', userId))
35 if (!docSnap.exists()) return null
36 return { id: docSnap.id, ...(docSnap.data() as Omit<UserDoc, 'id'>) }
37}
38
39// Create a document and get the auto-generated ID
40export async function createUser(name: string, email: string): Promise<string> {
41 const docRef = await addDoc(collection(db, 'users'), {
42 name,
43 email,
44 createdAt: new Date(),
45 })
46 return docRef.id
47}
48
49// Pre-generate ID before writing
50export async function createUserWithKnownId(
51 name: string,
52 email: string
53): Promise<string> {
54 const newRef = doc(collection(db, 'users'))
55 await setDoc(newRef, { name, email, createdAt: new Date() })
56 return newRef.id
57}
58
59// Query multiple documents by their IDs
60export async function getUsersByIds(ids: string[]): Promise<UserDoc[]> {
61 if (ids.length === 0) return []
62 const chunks: string[][] = []
63 for (let i = 0; i < ids.length; i += 30) {
64 chunks.push(ids.slice(i, i + 30))
65 }
66 const results: UserDoc[] = []
67 for (const chunk of chunks) {
68 const q = query(collection(db, 'users'), where(documentId(), 'in', chunk))
69 const snapshot = await getDocs(q)
70 snapshot.forEach((doc) => {
71 results.push({ id: doc.id, ...(doc.data() as Omit<UserDoc, 'id'>) })
72 })
73 }
74 return results
75}

Common mistakes when getting Document ID in Firestore

Why it's a problem: Trying to access doc.id on the QuerySnapshot instead of individual documents

How to avoid: QuerySnapshot does not have an id property. Iterate over querySnapshot.docs or use querySnapshot.forEach to access each document's id individually.

Why it's a problem: Spreading doc.data() before setting the id, allowing a data field named 'id' to overwrite the document ID

How to avoid: Always put the id field first: { id: doc.id, ...doc.data() }. Or use a different property name for any id field stored in the document data.

Why it's a problem: Passing more than 30 values to the 'in' operator with documentId(), causing a runtime error

How to avoid: Split the ID array into chunks of 30 and run separate queries for each chunk. Merge the results into a single array.

Best practices

  • Always include the document ID when mapping query results to your app's data model
  • Use addDoc for auto-generated IDs and setDoc with doc() for custom or pre-generated IDs
  • When you need the ID before writing, use doc(collection(db, 'collectionName')) to generate it locally
  • Chunk documentId() 'in' queries into groups of 30 to stay within Firestore limits
  • Use TypeScript interfaces that include an id field to keep document types consistent
  • Consider using meaningful custom IDs (like user UIDs) instead of auto-generated IDs when there is a natural key

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

How do I get the document ID from Firestore query results in the modular SDK v9? Show me how to map documents with their IDs, get the auto-generated ID after addDoc, and query by document ID using documentId().

Firebase Prompt

Create a TypeScript module for Firestore that provides functions for getting documents with their IDs, creating documents with auto-generated and pre-generated IDs, and querying multiple documents by ID using documentId() with chunking for large arrays.

Frequently asked questions

What format are Firestore auto-generated document IDs?

Auto-generated IDs are 20-character strings using Base62 encoding (alphanumeric characters). They are designed to be unique and roughly time-ordered, which helps with index locality.

Can I change a document's ID after creating it?

No, document IDs are immutable in Firestore. To change an ID, you must create a new document with the desired ID, copy the data, and delete the old document.

Should I store the document ID as a field inside the document?

It is not required since you can always access it from the snapshot. However, storing it as a field can be convenient when the data is sent to external systems or serialized to JSON where the ID context would be lost.

Is there a performance difference between auto-generated and custom IDs?

Auto-generated IDs are optimized for write throughput because they are roughly time-ordered and distribute writes across the key space. Sequential custom IDs (like 1, 2, 3) can cause write hotspots.

How many document IDs can I pass to the 'in' operator?

The 'in' operator supports up to 30 values per query. For larger lists, split into chunks of 30, run parallel queries, and merge the results.

Can RapidDev help design an efficient Firestore data model?

Yes, RapidDev's engineering team can help design Firestore document structures, ID strategies, and query patterns optimized for your specific use case.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.