Réponse concise : Oui. Pour les 34 746 communes de France métropolitaine, l'index tient dans 182 kilooctets compressés, se construit en 70 millisecondes au chargement de la page, et répond en moins d'un dixième de milliseconde par frappe. Le coût réel n'est pas le poids des données. Ce sont le travail de normalisation et le composant de saisie, qui n'existent ni l'un ni l'autre en natif.
Source : Sudimédia, relevés du 1er août 2026 dans Firefox sur un poste de bureau, sur le découpage administratif Etalab 6.0.0. Poids mesurés après compression gzip au niveau 6, celui que sert le serveur. Le démonstrateur est ouvert plus bas.
Dans cet article
Un champ de recherche qui propose des résultats pendant la frappe se fait presque toujours en appelant le serveur à chaque caractère. Nous avons mesuré l'autre voie, celle où le catalogue entier part une fois dans le navigateur. Cinq écritures comparées, une optimisation évidente qui s'est révélée coûteuse, et deux correctifs dont le premier en a cassé un troisième.
Un champ qui doit répondre à chaque frappe
Tapez tou dans notre démonstrateur, première version. Voici ce qui remontait :
Huit propositions, et pas Toulouse. Le tri était pourtant raisonnable : les noms les plus courts d'abord, parce que quelqu'un qui tape « belley » veut Belley avant Belleydoux. Personne n'avait vu qu'une ville de cinq cent mille habitants sortirait derrière un village du Gers.
C'est le genre de défaut qu'on ne trouve pas en relisant du code. Et c'est le sujet de cet article, parce que la question posée au départ était toute autre : combien coûte une recherche qui répond à chaque frappe sans appeler le serveur.
La question se pose partout où il y a un catalogue, et la réponse la plus répandue est une requête serveur par caractère tapé. Nous voulions savoir ce que coûte l'autre voie, celle où le catalogue entier part une fois dans le navigateur et n'y revient plus. Nous l'avons mesurée sur les communes de France, parce que le jeu de données est public, stable et assez gros pour que les problèmes apparaissent : 34 746 communes en métropole, réparties dans 96 départements.
Trois écritures du même catalogue
Le premier réflexe est un tableau JSON avec un objet par commune. Voici ce que pèsent cinq écritures des mêmes données, compressées comme les servira le serveur.
| Écriture | Après compression |
|---|---|
| JSON, un objet nommé par commune | 227 022 octets |
| JSON, un tableau de deux valeurs | 206 444 octets |
| Texte, un nom et un département par ligne | 194 402 octets |
| Texte groupé par département | 179 666 octets |
| Texte groupé, avec front-coding | 163 129 octets |
Le front-coding est vieux comme les dictionnaires imprimés : sur une liste triée, chaque entrée ne porte que ce qui la distingue de la précédente. Un chiffre en tête de ligne dit combien de caractères reprendre au nom d'avant.
3ronay Amb + ronay = Ambronay
3utrix Amb + utrix = Ambutrix
3érieu-en-Bugey Amb + érieu-en-Bugey = Ambérieu-en-Bugey
8x-en-Dombes Ambérieu + x-en-Dombes
Un tiers du volume brut disparaît, et 16 kilooctets survivent à la compression. Gzip fait pourtant déjà ce travail, mais sa fenêtre d'analyse ne remonte que sur 32 kilooctets. Sur un fichier de 400, il ne voit pas la moitié des répétitions.
L'autre surprise du tableau est le passage de 194 à 179 kilooctets. Grouper les communes par département, plutôt que de les trier globalement, rapporte 15 kilooctets. Les noms d'un même département partagent davantage de préfixes que ceux du pays entier, et ça se voit dès qu'on regarde le Finistère ou le Bas-Rhin.
Restent les anciens noms des communes fusionnées, 2 501 entrées, pour 19 503 octets de plus. Bellegarde-sur-Valserine mène à Valserhône, Tourlaville à Cherbourg-en-Cotentin, et personne ne devrait avoir à le savoir pour trouver la bonne commune.
Le fichier complet fait 182 172 octets compressés, et le serveur en annonce 182 079 : le module de compression d'Apache ne travaille pas tout à fait comme l'outil en ligne de commande, et l'écart de quatre-vingt-treize octets ne se rattrape pas.
L'optimisation évidente pesait 45 kilooctets de plus
Le raisonnement suivant paraissait imparable, et nous l'avons suivi.
Les noms de communes répètent les mêmes mots par milliers. « Saint » revient 4 067 fois. Or gzip ne regarde en arrière que sur 32 kilooctets, donc il ne peut pas capter une répétition espacée de trois cent mille. Il suffirait de construire un dictionnaire global des mots et de remplacer chaque nom par une suite d'identifiants. Ce que gzip ne voit pas, le dictionnaire le verrait.
Mesuré : 208 086 octets contre 163 129. Quarante-cinq kilooctets de plus, soit 28 % de dégradation par rapport à ce qu'on cherchait à améliorer.
L'explication tient en trois faits qu'il fallait aller chercher. Le vocabulaire compte 27 611 mots distincts pour 34 746 noms, et la plupart n'apparaissent qu'une seule fois : le dictionnaire pèse alors presque autant que les données qu'il devait remplacer. Les 256 mots les plus fréquents ne couvrent que 37,9 % des occurrences, donc l'écrasante majorité des identifiants sortent du domaine tenant sur un octet. Et le flux d'identifiants est binaire, là où le texte front-codé reste du texte : gzip compresse mal le premier et très bien le second.
Nous publions cette impasse parce que personne ne publie les siennes. Un article de performance montre en général le chemin qui a marché, ce qui laisse croire qu'il a été trouvé du premier coup. Trois demi-journées sont parties dans celui-ci, sur un raisonnement dont le mécanisme était exact et l'effet inverse.
La normalisation est le seul poste qu'on ne peut pas acheter
Un utilisateur tape st martin de re. Une comparaison de chaînes ne trouve rien, et il en conclut que le moteur est mauvais. Il a raison.
Chaque nom est donc réduit à une clé de recherche : minuscules, accents retirés, ligatures dépliées, tirets, espaces et apostrophes supprimés, abréviations de Saint étendues. « Saint-Martin-de-Ré », « st martin de re » et « stmartindere » produisent la même chaîne.
Cette réduction a un prix, qui se chiffre. Les communes ne produisent que 32 424 clés distinctes, et 3 831 partagent la leur avec au moins une autre. Douze Sainte-Colombe, onze Saint-Sauveur, dix Saint-Aubin, dix Beaulieu.
D'où une décision d'architecture, et pas un détail d'interface : c'est la proposition choisie qui est validée, jamais le texte tapé. Un catalogue qui valide une chaîne de caractères accepte n'importe quel homonyme, et le jour où deux références portent le même nom, personne ne comprend pourquoi la commande part au mauvais endroit.
Ce travail-là ne s'achète dans aucune bibliothèque. Il dépend de vos données, de votre secteur et de la façon dont vos clients écrivent. Il se voit peu sur un devis, ce qui en fait le premier poste rogné quand le budget se resserre.
Le correctif qui a caché 137 communes
Revenons à Toulouse.
Le correctif tient dans un palier de population par commune, un seul caractère chacun, sept paliers logarithmiques. Le fichier pèse 7 903 octets compressés. Une échelle deux fois plus fine, treize paliers, en coûtait 12 224 pour une distinction que personne ne perçoit : séparer une préfecture d'un village suffit, classer deux villages entre eux n'apporte rien.
Le tri devient palier décroissant, puis longueur du nom. Résultat sur la même saisie :
Cherbourg apparaît parce que l'ancien nom Tourlaville est dans l'index, ce qui justifie à lui seul les 19 kilooctets d'alias.
Le contrôle qui a suivi est celui qui compte. Nous avons cherché chaque commune par son nom complet et compté celles qui ne remontaient pas dans les vingt premières propositions. 137 étaient devenues introuvables, des communes modestes dont le nom est le préfixe de plusieurs grandes villes, poussées hors de la liste par le correctif que nous venions d'écrire.
Correction : une correspondance exacte passe devant tout, palier compris. Le contrôle est revenu à zéro.
La leçon est plus large que ce jeu de données. Un correctif de classement se vérifie par un balayage exhaustif, pas par trois essais à la main. Trois essais auraient validé le premier correctif, puisque Toulouse remontait.
Quand le natif n'existe pas
Nous avons publié il y a peu un démineur jouable entièrement au clavier. Sa grille est faite de vrais boutons HTML, ce qui lui donne le focus, la navigation au clavier et la restitution vocale sans une ligne de code écrite pour ça. Le navigateur fait le travail.
Ici, il n'y a rien à récupérer. Un champ de saisie doublé d'une liste de propositions navigable aux flèches n'existe pas en HTML. Il faut l'écrire, et il porte un nom dans la norme d'accessibilité, combobox, avec une demi-douzaine d'attributs à tenir à jour : l'état ouvert ou fermé, le lien vers la liste, la proposition courante, les rôles de la liste et de chaque option.
Le piège est ailleurs, dans le modèle de focus. Le curseur ne quitte jamais le champ, et c'est un attribut qui déplace la sélection. Un développeur qui applique son réflexe et déplace le focus sur les propositions casse la saisie : le champ perd le curseur à chaque flèche. Second piège, l'annonce du nombre de résultats doit être temporisée d'environ trois cents millisecondes, sinon la synthèse vocale bégaie sur chaque caractère et ne finit aucune phrase.
Fait à moitié, ce composant est pire que rien. Un lecteur d'écran annonce alors un champ de saisie vide pendant que huit propositions défilent en silence, et l'utilisateur ne sait même pas qu'il y a quelque chose à choisir.
Ce que ça change sur un catalogue client
Les mesures finales, sur la page réelle. Construire l'index au chargement demande 70 millisecondes, sur deux relevés indépendants qui donnent 70 et 72. Une recherche demande entre trois et cinq centièmes de milliseconde, moyennées sur six mille recherches, parce que Firefox arrondit son chronomètre à la milliseconde et qu'une opération isolée n'y est pas mesurable. Le fichier fait 182 kilooctets transférés une fois, puis mis en cache un an.
Méthode : découpage Etalab 6.0.0, compression gzip au niveau 6, celui que sert Apache. Relevés sous Firefox sur un poste de bureau, le 1er août 2026, poids lus dans l'interface de mesure du navigateur et non estimés.
Ces 70 millisecondes ont une conséquence directe sur la façon de câbler la page. L'index se construit juste après l'affichage, jamais au premier caractère tapé, sinon le champ paraît cassé au moment précis où il doit convaincre.
La comparaison avec l'autre voie se pose en nature plutôt qu'en euros, faute de l'avoir chiffrée. Une recherche en aller-retour serveur, c'est une requête par caractère, donc une dizaine par nom saisi, multipliées par chaque visiteur et par chaque champ de la page. L'approche décrite ici en fait une seule, pour tout le monde, pendant un an.
Une limite, parce qu'il n'y a pas de solution universelle. Le procédé tient tant que le catalogue reste de l'ordre de quelques dizaines de milliers d'entrées et que ses données changent rarement. Un stock qui bouge à la minute, des prix qui varient dans la journée, un catalogue de plusieurs centaines de milliers de références : rien de tout cela ne se met dans un fichier mis en cache un an. La bonne architecture dépend de la fréquence de changement autant que du volume.
Reste à savoir où vous en êtes. Ouvrez votre propre recherche produit et faites trois essais, ils prennent deux minutes.
Tapez trois lettres et regardez si les propositions arrivent avant que vous ayez tapé la quatrième. Si elles arrivent après, chaque frappe part au serveur et revient.
Tapez une référence en oubliant un accent, un tiret ou une majuscule. Si elle ne sort pas, la normalisation n'a pas été faite, et vos visiteurs qui écrivent vite ne trouvent pas ce que vous vendez.
Tapez le nom exact d'un produit peu vendu. S'il n'apparaît pas en premier, votre classement trie sur autre chose que la pertinence, et c'est le défaut qui nous a caché 137 communes.
Le démonstrateur demande de nommer une commune dans chacun des cinq départements du jour. La recherche y est celle décrite ici, anciens noms compris, et le poids réellement transféré se vérifie dans l'onglet réseau du navigateur, comme nous l'avions fait pour les bibliothèques d'une page ordinaire. Mesurer avant de décider, et publier les mesures qui nous donnent tort, c'est notre approche du développement sur mesure.
Questions fréquentes
Peut-on faire de l'autocomplétion sans appeler le serveur ?
Oui, à condition que le catalogue tienne dans un fichier que le navigateur peut charger une fois et garder en cache. Pour les 34 746 communes de France métropolitaine, ce fichier fait 182 kilooctets compressés et l'index se construit en 70 millisecondes. Au-delà de quelques dizaines de milliers d'entrées, ou si les données changent plusieurs fois par jour, une recherche côté serveur reste le bon choix.
Combien pèse un index de recherche côté client ?
Cela dépend surtout de l'encodage. Les mêmes 34 746 noms pèsent 227 kilooctets en JSON classique et 163 en texte trié avec front-coding, où chaque nom ne porte que ce qui le distingue du précédent. Un dictionnaire de mots, qui paraissait plus efficace, remonte à 208 kilooctets parce que le vocabulaire compte 27 611 mots distincts dont la plupart n'apparaissent qu'une fois.
Faut-il une bibliothèque pour construire un champ de recherche avec suggestions ?
Non, et l'élément datalist du HTML ne suffit pas non plus, parce qu'il ne laisse aucun contrôle sur l'ordre des propositions. Le composant décrit ici est écrit en JavaScript sans dépendance. Le vrai travail n'est pas la recherche mais la normalisation des noms, qui décide qu'une saisie approximative trouve ou ne trouve pas.
Un champ de suggestions est-il utilisable au clavier et au lecteur d'écran ?
Seulement s'il est écrit pour, car aucun élément HTML ne fournit ce comportement. La norme d'accessibilité décrit le motif combobox, dans lequel le focus ne quitte jamais le champ de saisie et où un attribut désigne la proposition courante. Un composant à moitié conforme est pire qu'une simple liste : le lecteur d'écran annonce un champ vide pendant que les propositions défilent en silence.
Un champ qui met une seconde à répondre, une recherche qui rate un accent, un catalogue qui grossit plus vite que son moteur : ce sont trois symptômes du même problème d'architecture. Nous concevons des plateformes sur mesure où la recherche reste immédiate quand le catalogue grossit.
En parler avec nousRéponse par une personne, pas par un formulaire automatique.