Vous développez avec Firestore ? Ces 15 règles vous éviteront les pièges les plus courants. Que vous démarriez votre premier projet Firebase ou que vous mettiez à l'échelle un projet existant, ces bonnes pratiques couvrent tout, de la modélisation de données à l'optimisation des coûts — tirées d'applications de production réelles.
Règles de modélisation de données
La façon dont vous structurez vos données détermine tout le reste — performances des requêtes, coûts et maintenabilité. Commencez par bien faire cela.
1. Préférez les collections plates aux imbrications profondes
Les sous-collections profondément imbriquées rendent les requêtes plus difficiles et créent un couplage fort. Gardez votre hiérarchie de collections peu profonde — généralement 1 à 2 niveaux. Utilisez des collections au niveau racine avec des références de documents au lieu de tout imbriquer sous un parent. Par exemple, stockez orders comme collection racine avec un champ userId plutôt que de les imbriquer sous users/{id}/orders — sauf si vous interrogez uniquement les commandes par utilisateur.
2. Dénormalisez les données pour les performances de lecture
En SQL, vous normalisez pour éviter la duplication. Dans Firestore, vous dénormalisez pour éviter plusieurs lectures. Si votre interface affiche le nom d'un utilisateur à côté de chaque commentaire, stockez authorName directement dans chaque document de commentaire — ne forcez pas une lecture séparée vers la collection users. Acceptez le compromis : les écritures sont plus complexes, mais les lectures sont rapides et peu coûteuses.
3. Utilisez des sous-collections pour les relations un-à-plusieurs illimitées
Lorsqu'un document peut avoir des centaines ou des milliers d'éléments liés (messages dans un chat, commandes pour un utilisateur), utilisez des sous-collections. Contrairement aux tableaux dans les documents, les sous-collections peuvent contenir un nombre illimité d'éléments et supportent des requêtes efficaces avec pagination. Exemple : chats/{chatId}/messages/{messageId}.
4. Gardez les documents sous 20 Ko pour des performances optimales
La limite stricte de Firestore est de 1 Mo par document, mais visez moins de 20 Ko. Les grands documents gaspillent de la bande passante lorsque vous n'avez besoin que de quelques champs — et Firestore facture par lecture de document quelle que soit la taille. Si un document grossit, divisez-le en sous-collections ou en une collection séparée.
5. Évitez les tableaux pour les données interrogeables
Les tableaux dans Firestore ont des limitations : vous ne pouvez pas mettre à jour des éléments individuels, les requêtes array-contains ne supportent qu'une seule par requête, et les tableaux ne passent pas bien à l'échelle au-delà de quelques centaines d'éléments. Pour les tags ou catégories, utilisez array-contains, mais pour les relations ou les listes croissantes, utilisez plutôt des sous-collections ou des champs de type map.
Optimisation des requêtes
Les requêtes Firestore sont rapides par conception, mais seulement si vous travaillez avec ses contraintes — pas contre elles.
6. Créez des index composites de manière proactive
Firestore nécessite un index pour chaque modèle de requête unique. Au lieu d'attendre des messages d'erreur, planifiez vos index à l'avance. Définissez-les dans firestore.indexes.json et déployez avec firebase deploy --only firestore:indexes. Chaque combinaison where + orderBy nécessite son propre index composite.
7. Utilisez la pagination basée sur curseur, pas les offsets
N'utilisez jamais la pagination basée sur offset dans Firestore — elle lit (et facture) toujours tous les documents sautés. Utilisez plutôt startAfter() avec le dernier document de la page précédente. C'est à la fois plus rapide et moins cher, car Firestore ne lit que les documents dont vous avez réellement besoin.
8. Limitez explicitement les résultats de requête
Ajoutez toujours .limit() à vos requêtes. Sans cela, Firestore renvoie chaque document correspondant — ce qui pourrait être des millions. Même si vous pensez qu'une collection est petite aujourd'hui, elle ne le sera pas dans six mois. Une bonne valeur par défaut est de 20 à 50 documents par requête.
9. Évitez de lire des collections entières
Si vous vous retrouvez à faire collection('users').get() sans filtres, votre modèle de données nécessite une refonte. Utilisez des requêtes d'agrégation (count(), sum()) pour les analyses, et filtrez toujours avec where() pour les requêtes d'affichage. La lecture de tous les documents est la cause n°1 de factures Firestore inattendues.
Modèles de règles de sécurité
Les règles de sécurité Firestore sont votre seule validation côté serveur. Si vous vous trompez, toute votre base de données est exposée.
10. Validez toujours les types de champs dans les règles
Ne vérifiez pas seulement si un champ existe — validez son type. Un client malveillant pourrait envoyer age: "not a number" si vous ne vérifiez que request.resource.data.age != null. Utilisez is string, is number, is bool pour imposer les types au niveau des règles de sécurité.
11. Utilisez des règles granulaires par collection
N'utilisez jamais allow read, write: if true au niveau de la base de données. Écrivez des règles spécifiques pour chaque collection : qui peut lire, qui peut créer, qui peut mettre à jour, qui peut supprimer. Commencez avec tout refusé et ouvrez l'accès progressivement. Utilisez des modèles match pour les sous-collections.
12. Ne faites jamais confiance aux données côté client
Le client peut envoyer n'importe quelles données. Validez les champs obligatoires, vérifiez les types de données, imposez les valeurs d'énumération et vérifiez que les champs de référence pointent vers de vrais documents. Utilisez request.auth pour vérifier que l'utilisateur est bien qui il prétend être, et resource.data pour comparer avec les valeurs existantes.
Optimisation des coûts
La tarification Firestore est basée sur les lectures, les écritures et le stockage. De petits changements dans votre façon d'interroger peuvent avoir un gros impact sur votre facture.
13. Groupez les écritures pour réduire les opérations
Utilisez writeBatch() ou runTransaction() pour combiner plusieurs écritures en une seule opération. Un lot de 500 écritures coûte le même prix que 500 écritures individuelles en termes d'opérations, mais réduit les allers-retours réseau et garantit l'atomicité. Limitez les lots à 500 opérations maximum.
14. Mettez en cache les documents fréquemment lus
Le SDK client de Firestore a une persistance hors ligne intégrée — activez-la. Pour les applications côté serveur, implémentez une couche de cache (Redis, en mémoire) pour les documents qui changent rarement mais sont lus constamment, comme la configuration de l'application ou les profils utilisateur. Chaque lecture mise en cache est une lecture que vous ne payez pas.
15. Utilisez des requêtes d'agrégation au lieu de lire tous les documents
Besoin d'un décompte de documents ? Utilisez countQuery() au lieu de récupérer tous les documents et de compter côté client. Les requêtes d'agrégation Firestore (count(), sum(), average()) lisent les entrées d'index au lieu de documents complets, coûtant environ 1/1000ème par entrée.
Bonus : Documentez la structure de votre base de données
Toutes ces bonnes pratiques sont inutiles si votre équipe ne peut pas les trouver. Au fur et à mesure que votre base de données Firestore grandit, garder une trace des structures de collections, des types de champs et des règles de validation devient un défi. JSON Schema vous offre un moyen standard de décrire la structure de votre base de données — et des outils comme FireSchema transforment ces schémas en documentation interactive et navigable que toute votre équipe peut consulter.
💡 Astuce : Créez un fichier .schema.json pour chaque collection documentant ses champs, types et règles de validation. Cela devient la source unique de vérité pour votre équipe.
Prochaines étapes
Continuez à apprendre sur Firestore et la documentation de base de données :