Apprenez à ajouter Meilisearch à votre backend pour une recherche rapide et tolérante aux fautes : installation, indexation, règles de classement, filtres, sécurité et notions de montée en charge.

La recherche côté serveur signifie que la requête est traitée sur votre serveur (ou un service de recherche dédié), pas dans le navigateur. Votre application envoie une requête de recherche, le serveur l'exécute contre un index, et renvoie des résultats classés.
Ceci est important quand votre jeu de données est trop volumineux pour être envoyé au client, quand vous avez besoin d'une pertinence cohérente entre plateformes, ou quand le contrôle d'accès est non négociable (par exemple, des outils internes où les utilisateurs ne doivent voir que ce qui leur est permis). C’est aussi le choix par défaut quand vous voulez des analytics, des logs et des performances prévisibles.
Les utilisateurs ne pensent pas aux moteurs de recherche — ils jugent l'expérience. Un bon flux de recherche “instantanée” signifie généralement :
Si un de ces points manque, les utilisateurs compensent en essayant d'autres requêtes, en faisant plus de défilement, ou en abandonnant la recherche complètement.
Cet article est une marche à suivre pratique pour construire cette expérience avec Meilisearch. Nous verrons comment le configurer en toute sécurité, comment structurer et synchroniser vos données indexées, comment ajuster la pertinence et les règles de classement, comment ajouter filtres/tri/facettes, et comment penser à la sécurité et à la montée en charge pour que la recherche reste rapide à mesure que votre application grandit.
Meilisearch est particulièrement adapté à :
L'objectif : des résultats qui paraissent immédiats, précis et fiables — sans transformer la recherche en un projet d'ingénierie majeur.
Meilisearch est un moteur de recherche que vous exécutez à côté de votre application. Vous lui envoyez des documents (produits, articles, utilisateurs, tickets de support), et il construit un index optimisé pour la recherche rapide. Votre backend (ou frontend) interroge ensuite Meilisearch via une API HTTP simple et obtient des résultats classés en millisecondes.
Meilisearch se concentre sur les fonctionnalités attendues d'une recherche moderne :
Il est conçu pour être réactif et indulgent, même quand la requête est courte, légèrement erronée ou ambiguë.
Meilisearch ne remplace pas votre base de données principale. Votre base reste la source de vérité pour les écritures, les transactions et les contraintes. Meilisearch conserve une copie des champs que vous choisissez de rendre recherchables, filtrables ou affichables.
Un bon modèle mental : base de données pour stocker et mettre à jour les données, Meilisearch pour les retrouver rapidement.
Meilisearch peut être extrêmement rapide, mais les résultats dépendent de quelques facteurs pratiques :
Pour des jeux de données petits à moyens, vous pouvez souvent l'exécuter sur une seule machine. À mesure que votre index grandit, vous devrez être plus sélectif sur ce que vous indexez et comment vous maintenez la synchronisation — sujets abordés dans les sections suivantes.
Avant d'installer quoi que ce soit, décidez ce que vous allez réellement rechercher. Meilisearch donnera une impression d'“instantanéité” seulement si vos index et documents correspondent à la façon dont les gens naviguent dans votre application.
Commencez par lister vos entités recherchables — typiquement produits, articles, utilisateurs, docs d'aide, lieux, etc. Dans beaucoup d'apps, l'approche la plus propre est un index par type d'entité (par ex. products, articles). Cela garde les règles de classement et les filtres prévisibles.
Si votre UX recherche plusieurs types dans une même zone (“tout rechercher”), vous pouvez conserver des index séparés et fusionner les résultats dans votre backend, ou créer plus tard un index « global » dédié. N'obligez pas tout dans un seul index sauf si les champs et filtres sont vraiment alignés.
Chaque document a besoin d'un identifiant stable (clé primaire). Choisissez quelque chose qui :
id, sku, slug)Pour la forme du document, privilégiez les champs plats quand c'est possible. Les structures plates sont plus faciles à filtrer et à trier. Les champs imbriqués conviennent quand ils représentent un paquet étroit et immuable (par ex. un objet author), mais évitez les imbrications profondes qui reflètent tout votre schéma relationnel : les documents de recherche doivent être optimisés pour la lecture, pas pour la base de données.
Une manière pratique de concevoir les documents est d'attribuer à chaque champ un rôle :
Cela évite une erreur courante : indexer un champ “au cas où” puis se demander pourquoi les résultats sont bruyants ou pourquoi les filtres sont lents.
La “langue” peut signifier différentes choses dans vos données :
lang: "en")Décidez tôt si vous utiliserez des index séparés par langue (simple et prévisible) ou un index unique avec des champs de langue (moins d'index, plus de logique). La bonne réponse dépend de si les utilisateurs recherchent dans une seule langue à la fois et comment vous stockez les traductions.
Exécuter Meilisearch est simple, mais « sûr par défaut » demande quelques choix délibérés : où le déployer, comment persister les données, et comment gérer la clé master.
Stockage : Meilisearch écrit son index sur disque. Placez le répertoire de données sur un stockage persistant et fiable (pas le stockage éphémère des conteneurs). Prévoir la capacité pour la croissance : les index peuvent s'étendre rapidement avec de grands champs texte et de nombreux attributs.
Mémoire : allouez suffisamment de RAM pour garder la recherche réactive sous charge. Si vous voyez du swap, les performances souffriront.
Sauvegardes : sauvegardez le répertoire de données Meilisearch (ou utilisez des snapshots au niveau du stockage). Testez la restauration au moins une fois ; une sauvegarde que vous ne pouvez pas restaurer n'est qu'un fichier.
Monitoring : suivez CPU, RAM, utilisation disque et I/O disque. Surveillez aussi la santé du processus et les erreurs dans les logs. Au minimum, alertez si le service s'arrête ou si l'espace disque devient faible.
Exécutez toujours Meilisearch avec une clé master pour tout environnement au-delà du développement local. Stockez-la dans un gestionnaire de secrets ou un magasin d'environnement chiffré (pas dans Git, pas dans un .env en clair versionné).
Exemple (Docker) :
docker run -d --name meilisearch \\
-p 7700:7700 \\
-v meili_data:/meili_data \\
-e MEILI_MASTER_KEY="$(openssl rand -hex 32)" \\
getmeili/meilisearch:latest
Pensez aussi aux règles réseau : liez sur une interface privée ou restreignez l'accès entrant pour que seul votre backend puisse atteindre Meilisearch.
curl -s http://localhost:7700/version
L'indexation dans Meilisearch est asynchrone : vous envoyez des documents, Meilisearch met la tâche en file, et ce n'est qu'après le succès de cette tâche que ces documents deviennent recherchables. Traitez l'indexation comme un système de jobs, pas comme une requête unique.
id).curl -X POST 'http://localhost:7700/indexes/products/documents?primaryKey=id' \\
-H 'Content-Type: application/json' \\
-H 'Authorization: Bearer YOUR_WRITE_KEY' \\
--data-binary @products.json
taskUid. Poller jusqu'à succeeded (ou failed).curl -X GET 'http://localhost:7700/tasks/123' \\
-H 'Authorization: Bearer YOUR_WRITE_KEY'
curl -X GET 'http://localhost:7700/indexes/products/stats' \\
-H 'Authorization: Bearer YOUR_WRITE_KEY'
Si les comptes ne correspondent pas, n'improvisez pas — vérifiez d'abord les détails d'erreur de la tâche.
Le batching consiste à garder les tâches prévisibles et récupérables.
addDocuments fonctionne comme un upsert : les documents avec la même clé primaire sont mis à jour, les nouveaux sont insérés. Utilisez cela pour les mises à jour normales.
Faites une réindexation complète lorsque :
Pour les suppressions, appelez explicitement deleteDocument(s) ; sinon les anciens enregistrements peuvent persister.
L'indexation doit être réessivable. La clé est des ids de document stables.
taskUid renvoyé avec l'identifiant de lot/job, et réessayez en fonction du statut de la tâche.Avant les données de production, indexez un petit jeu (200–500 items) qui correspond à vos champs réels. Exemple : un set products avec id, name, description, category, brand, price, inStock, createdAt. C'est suffisant pour valider le flux de tâches, les comptes, et le comportement update/delete — sans attendre un import massif.
La “pertinence” de la recherche, c'est simplement : qu'est-ce qui apparaît en premier, et pourquoi. Meilisearch permet d'ajuster cela sans vous forcer à créer votre propre scoring.
Deux settings déterminent ce que Meilisearch peut faire avec votre contenu :
searchableAttributes : les champs que Meilisearch consulte quand un utilisateur tape une requête (par ex. : title, summary, tags). L'ordre compte : les champs placés plus tôt sont considérés comme plus importants.displayedAttributes : les champs renvoyés dans la réponse. Cela compte pour la confidentialité et la taille de la payload — si un champ n'est pas affiché, il ne sera pas renvoyé.Une bonne base pratique : rendre quelques champs à signal élevé recherchables (titre, texte clé), et limiter les champs affichés à ce dont l'UI a besoin.
Meilisearch trie les documents correspondants en utilisant des règles de classement — une pipeline de “désambiguïsation”. Conceptuellement, il préfère :
Vous n'avez pas à mémoriser les détails internes pour le régler efficacement ; vous choisissez surtout quels champs comptent le plus et quand appliquer un tri personnalisé.
Objectif : “Les correspondances dans le titre doivent gagner.” Mettez title en premier :
{
"searchableAttributes": ["title", "subtitle", "description", "tags"]
}
Objectif : “Le contenu plus récent doit apparaître en premier.” Ajoutez un attribut triable et triez au moment de la requête (ou définissez un classement personnalisé) :
{
"sortableAttributes": ["publishedAt"],
"rankingRules": ["sort", "typo", "words", "proximity", "attribute", "exactness"]
}
Puis demandez :
{ "q": "release notes", "sort": ["publishedAt:desc"] }
Objectif : “Promouvoir les éléments populaires.” Rendez popularity triable et triez par ce champ quand c'est approprié.
Choisissez 5–10 requêtes réelles que les utilisateurs tapent. Sauvegardez les meilleurs résultats avant les changements, puis comparez après.
Exemple :
"apple" → Apple Watch band, Pineapple slicer, Apple iPhone case"apple" → Apple iPhone case, Apple Watch band, Pineapple slicerSi la liste “après” correspond mieux à l'intention utilisateur, gardez les réglages. Si ça nuit à des cas limites, ajustez une chose à la fois (ordre des attributs, puis règles de tri) pour savoir ce qui a causé l'amélioration.
Une bonne barre de recherche n'est pas seulement “tapez des mots, obtenez des correspondances.” Les gens veulent aussi restreindre les résultats (“seulement les articles disponibles”) et les ordonner (“le moins cher d'abord”). Dans Meilisearch, vous le faites avec des filtres, du tri et des facettes.
Un filtre est une règle appliquée au jeu de résultats. Une facette est ce que vous montrez dans l'UI pour aider l'utilisateur à construire ces règles (souvent des cases à cocher ou des comptes).
Exemples non techniques :
Un utilisateur peut rechercher “running” puis filtrer par category = Shoes et status = in_stock. Les facettes peuvent afficher des comptes comme “Shoes (128)” et “Jackets (42)” pour indiquer ce qui est disponible.
Meilisearch a besoin que vous autorisiez explicitement les champs utilisés pour le filtrage et le tri.
category, status, brand, price, created_at (si vous filtrez par durée), tenant_id (pour isoler des clients).price, rating, created_at, popularity.Gardez cette liste serrée. Rendre tout filtrable/triable peut augmenter la taille de l'index et ralentir les mises à jour.
Même si vous avez 50 000 correspondances, les utilisateurs ne voient que la première page. Utilisez des pages petites (souvent 20–50 résultats), définissez un limit sensé, et paginez avec offset (ou les nouvelles fonctionnalités de pagination si vous préférez). Calez aussi une profondeur de page maximale dans votre app pour éviter des requêtes coûteuses “page 400”.
Une façon propre d'ajouter une recherche côté serveur est de traiter Meilisearch comme un service de données spécialisé derrière votre API. Votre app reçoit une requête de recherche, appelle Meilisearch, puis renvoie une réponse organisée au client.
La plupart des équipes adoptent un flux comme :
GET /api/search?q=wireless+headphones&limit=20).Ce pattern rend Meilisearch remplaçable et empêche le frontend de dépendre des détails internes des index.
Si vous construisez une nouvelle app (ou reconstruisez un outil interne) et voulez implémenter rapidement ce pattern, une plateforme de vibe-coding comme Koder.ai peut aider à générer le flow complet — UI React, backend Go, PostgreSQL — puis intégrer Meilisearch derrière un unique endpoint /api/search pour garder le client simple et les permissions côté serveur.
Meilisearch supporte les requêtes côté client, mais interroger via le backend est généralement plus sûr car :
Le querying côté client peut convenir pour des données publiques avec des clés restreintes, mais si vous avez la moindre règle de visibilité par utilisateur, routez la recherche via votre serveur.
Le trafic de recherche a souvent des répétitions (“iphone case”, “return policy”). Ajoutez du caching à votre couche API :
Traitez la recherche comme un endpoint public :
limit maximal et une longueur maximale de requête.Meilisearch est souvent placé « derrière » votre app car il peut renvoyer rapidement des données sensibles. Traitez-le comme une base : verrouillez-le et n'exposez que ce que chaque appelant doit voir.
Meilisearch a une clé master qui peut tout faire : créer/supprimer des index, mettre à jour des settings, lire/écrire des documents. Gardez-la côté serveur uniquement.
Pour les applications, générez des clés API avec actions limitées et index limités. Un pattern courant :
Le moindre privilège signifie qu'une clé divulguée ne peut pas supprimer de données ni lire d'index non autorisés.
Si vous servez plusieurs clients (tenants), vous avez deux options principales :
1) Un index par tenant.
Simple à raisonner et réduit le risque d'accès croisé entre tenants. Inconvénients : plus d'index à gérer, et les mises à jour de settings doivent être appliquées partout.
2) Index partagé + filtre tenant.
Stockez un champ tenantId sur chaque document et exigez un filtre tenantId = "t_123" pour toutes les recherches. Cela peut bien scaler, mais seulement si vous assurez que chaque requête applique toujours le filtre (idéalement via une clé restreinte pour empêcher la suppression du filtre).
Même si la recherche est correcte, les résultats peuvent exposer des champs que vous ne vouliez pas montrer (emails, notes internes, prix de revient). Configurez ce qui est récupérable :
Faites un test “pire scénario” : cherchez un terme courant et confirmez qu'aucun champ privé n'apparaît.
Si vous hésitez à exposer une clé côté client, supposez « non » et gardez la recherche côté serveur.
Meilisearch est rapide quand vous gardez en tête deux charges de travail : indexation (écritures) et requêtes de recherche (lectures). La plupart des lenteurs mystérieuses proviennent de l'une de ces charges qui rivalise pour le CPU, la RAM ou le disque.
La charge d'indexation peut monter en flèche lors d'import massifs, de mises à jour fréquentes, ou si vous ajoutez beaucoup de champs recherchables. L'indexation est en tâche de fond, mais elle consomme CPU et bande passante disque. Si votre file de tâches grandit, les recherches peuvent devenir plus lentes même si le volume de requêtes n'a pas changé.
La charge de requêtes augmente avec le trafic, mais aussi avec les fonctionnalités : plus de filtres, plus de facettes, jeux de résultats plus grands, et une tolérance aux fautes plus agressive peuvent augmenter le travail par requête.
L'I/O disque est souvent le coupable silencieux. Des disques lents (ou des voisins bruyants sur des volumes partagés) peuvent transformer “instantané” en “finalement”. Un stockage NVMe/SSD est la base typique pour la production.
Commencez par un dimensionnement simple : donnez à Meilisearch assez de RAM pour garder les index en chaud et assez de CPU pour gérer le QPS pic. Séparez ensuite les préoccupations :
Suivez un petit ensemble de signaux :
Les backups doivent être routiniers. Utilisez la fonctionnalité de snapshot de Meilisearch selon un planning, stockez les snapshots hors-site, et testez périodiquement les restaurations. Pour les upgrades, lisez les notes de version, faites un staging de l'upgrade en non-prod, et prévoyez du temps de réindexation si une version affecte le comportement d'indexation.
Si vous utilisez déjà des snapshots d'environnement et des rollbacks sur votre plateforme (par ex. via le workflow snapshots/rollback de Koder.ai), alignez votre déploiement de recherche sur la même discipline : snapshot avant les changements, vérifiez les health checks, et gardez un chemin rapide vers un état connu bon.
Même avec une intégration propre, les problèmes de recherche tombent souvent dans quelques catégories récurrentes. La bonne nouvelle : Meilisearch vous donne assez de visibilité (tâches, logs, settings déterministes) pour déboguer rapidement — si vous procédez méthodiquement.
filterableAttributes, ou les documents le stockent dans une forme inattendue (string vs tableau vs objet imbriqué).sortableAttributes/rankingRules manquant poussent de mauvais éléments en haut.Commencez par vérifier si Meilisearch a appliqué votre dernier changement.
filter, puis sort, puis facets.Si vous ne pouvez pas expliquer un résultat, réduisez temporairement la configuration : retirez les synonymes, diminuez les modifications des règles de classement, et testez avec un dataset minuscule. Les problèmes complexes de pertinence sont bien plus faciles à repérer sur 50 documents que sur 5 millions.
your_index_v2 en parallèle, appliquez les settings, et rejouez un échantillon de requêtes de prod.filterableAttributes et sortableAttributes correspondent aux besoins de l'UI.Guides liés : /blog (fiabilité de la recherche, patterns d'indexation et conseils de déploiement en production).
La recherche côté serveur signifie que la requête s'exécute sur votre backend (ou un service de recherche dédié), et non dans le navigateur. C’est le bon choix quand :
Les utilisateurs remarquent immédiatement quatre choses :
Si l’un d’eux manque, les gens retapent les requêtes, font défiler plus ou abandonnent la recherche.
Considérez Meilisearch comme un index de recherche, pas comme votre source de vérité. Votre base de données gère les écritures, les transactions et les contraintes ; Meilisearch stocke une copie des champs sélectionnés optimisée pour la recherche rapide.
Un bon modèle mental :
Un choix par défaut courant est une index par type d'entité (par exemple products, articles). Cela permet de garder :
Si vous avez besoin d’un « tout rechercher », vous pouvez interroger plusieurs index et fusionner les résultats côté serveur, ou ajouter plus tard un index global dédié.
Choisissez une clé primaire qui :
id, sku, slug)Des IDs stables rendent l'indexation idempotente : si vous relancez un upload, vous ne créerez pas de doublons car les mises à jour deviennent des upserts sûrs.
Classez chaque champ par rôle pour éviter la surfacturation :
Rendre ces rôles explicites réduit les résultats bruyants et empêche des index lents ou gonflés.
L'indexation est asynchrone : l'upload de documents crée une tâche, et les documents deviennent consultables uniquement après la réussite de cette tâche.
Un flux fiable est :
succeeded ou failedSi les résultats semblent obsolètes, vérifiez d'abord le statut de la tâche avant de déboguer autre chose.
Préférez beaucoup de petits batchs plutôt qu'un gros upload. Points de départ pratiques :
Les petits batchs sont plus faciles à réessayer, à déboguer (repérer les enregistrements défaillants) et moins susceptibles de dépasser le délai.
Deux leviers à fort impact :
searchableAttributes : quels champs sont recherchés et dans quel ordre prioritairepublishedAt, price ou popularityApproche pratique : prenez 5–10 requêtes réelles, enregistrez les meilleurs résultats “avant”, changez un paramètre, puis comparez “après”.
La plupart des problèmes de filtre/tri viennent d'une configuration manquante :
filterableAttributes pour pouvoir être filtrésortableAttributes pour pouvoir être triéVérifiez également la forme et les types des champs dans les documents (string vs array vs objet imbriqué). Si un filtre échoue, inspectez le dernier statut de settings/task et confirmez que les documents indexés contiennent bien les valeurs attendues.