Skip to main content

Best Practices

Use ReadMeter to spot risky patterns early. These practices help reduce Firestore read costs.

1. Watch the widget during development

Keep the ReadMeter widget visible while you build. When you see "Read Source" or high read counts, that's a signal to optimize before traffic scales.

2. Heed the risk levels

ReadMeter uses simple thresholds:

  • Safe — ≤30 reads per page load
  • Scales with traffic — 31–100 reads
  • High risk — >100 reads

These are intentionally conservative. They exist to change behavior early, not to be perfectly accurate.

3. Client-side filtering over multiple queries

Fetch once, filter many times:

// ❌ Bad: Multiple queries
const admins = await getDocs(query(usersRef, where('role', '==', 'admin')))
const users = await getDocs(query(usersRef, where('role', '==', 'user')))

// ✅ Good: Fetch once, filter client-side
const allUsers = await getDocs(collection(db, 'users'))
const admins = allUsers.docs.filter(d => d.data().role === 'admin')
const users = allUsers.docs.filter(d => d.data().role === 'user')

4. Cache frequently accessed data

If the same collection is read on multiple pages or components, cache it. ReadMeter will show repeated reads — that's your cue to add a cache layer.

5. Avoid queries in render loops

If a query runs on every render, ReadMeter will show high execution counts. Use memoization, move the fetch to a parent, or use a data-fetching library that deduplicates.

6. Use pagination for large lists

Don't fetch entire collections when you only need a subset. Use limit() and cursor-based pagination.

7. Real-time listeners count on initial load

onSnapshot reads everything on first attach. If you have many listeners, the initial page load can be expensive. Consider batching or lazy-loading listeners.

Common pitfalls

  • Fetching all users for simple role checks
  • Querying the same collection from multiple components
  • No cache expiration (stale data)
  • Processing all documents in scheduled functions

Further reading