Les SDK d'Overture parlent TypeScript et Python. Pas votre application mobile.
81 455 423 enregistrements de lieux trônent dans la version 2026-09-23.1 d'Overture, interrogeables en place depuis un ordinateur portable, et chaque client que le projet publie suppose que les données elles-mêmes sont votre produit de travail. L'outillage est taillé pour le serveur : une CLI Python capable de copier une version entière dans MongoDB, une fondation de SDK baptisée overture-core, un provider Airflow pour les pipelines, rien qui se charge dans un runtime applicatif. Une équipe web vit très bien dans ce monde. Une équipe mobile compile une application qui doit lire des enregistrements cartographiques sur un appareil, hors ligne, en Kotlin ou en Swift, et Overture ne publie aucun client qui l'atteigne.
Voilà l'affirmation que ce billet défend, et qu'un architecte mobile sceptique est invité à contester : le client Overture dont les équipes mobiles ont besoin est un noyau Rust qui lit le GeoParquet directement, typé contre une version du schéma épinglée, exposé aux deux plateformes par des bindings UniFFI. Pas une surcouche HTTP, puisqu'il n'existe aucun point de terminaison HTTP à envelopper. Overture publie des données ouvertes qui se lisent, et c'est la lecture le produit. Ce qui suit est une architecture à laquelle nous croyons et que nous n'avons pas construite. La section des limites vient avant la section de conception, dans l'esprit : les parties difficiles sont visibles d'ici.
Un téléphone rend Overture à merveille. Il ne sait pas le lire.
Le rendu sur mobile est un problème réglé. MapLibre Native consomme les mêmes tuiles PMTiles qu'un build web, c'est le chemin que parcourt notre billet sur les tuiles Overture. Livrez l'archive de tuiles et la carte de fond fonctionne sans fournisseur de raster. Cela couvre ce que l'utilisateur voit.
Cela ne couvre pas ce que l'application sait. Prenons l'application qui revient tout au long de ce billet : un outil d'inspection de terrain qui doit rester utile dans un hangar sans réseau. Avant la phase hors ligne, elle doit mettre en cache les lieux autour du lac Tahoe, 28 166 d'entre eux dans la version 2026-09-23.1, réduits de l'ensemble mondial par un seul prédicat de boîte englobante en 2,77 secondes avec DuckDB 1.5.6 le 2026-10-11. L'élagage est bon marché parce qu'Overture transporte une colonne struct bbox, si bien que le prédicat écarte des fichiers parquet et des lignes sans jamais toucher une géométrie. N'importe quel script de bureau produit cet extrait.
L'extrait, lui, n'est qu'une collection de structures opaques à la JSON, et le téléphone vivra avec pendant des mois. Quel champ porte les horaires d'ouverture ? Quelle règle de nommage imbriquée s'applique en France ? Et l'identifiant GERS, la clé de jointure entre ce lieu et tout ce que vos données savent, doit venir de quelque part que l'extrait n'étiquette pas lui-même. Un SDK répond à tout cela en le typant : une structure par thème et par type, générée depuis une version du schéma. Sans cela, chaque base de code mobile redérive le schéma à la main et le réapprend à chaque publication d'Overture.
L'organisation écrit déjà du Rust. Ce Rust ne regarde pas encore le téléphone.
L'indice que Rust est le bon langage système pour les données d'Overture n'a rien de théorique, parce que l'organisation Overture Maps construit elle-même en Rust. omf-bifrost, dans le dépôt transportation-routing, construit des tuiles de graphe Valhalla directement depuis le GeoParquet d'Overture. osm-pbf-parquet transcode l'OSM PBF en parquet partitionné à la hive. stac catalogue les publications. Ce sont des composants éprouvés, sous licence MIT, et aucun ne sait ce qu'est un téléphone.
Le travail SDK côté officiel regarde ailleurs. La CLI overturemaps-py écrit dans MongoDB avec un seul drapeau. overture-core pose les fondations d'un SDK. Le provider Airflow ordonnance des pipelines. Les trois supposent un environnement serveur où Python ou TypeScript est déjà installé et où la version est la chose à traiter. Rien de cette liste ne se charge dans un build Android ou un bundle iOS.
C'est l'écart, dit franchement : un lac de données à six thèmes (addresses, base, buildings, divisions, places, transportation) et un schéma qui bouge chaque mois. Il n'existe aucune bibliothèque cliente pour les plateformes où ces données doivent devenir une fonctionnalité applicative. La lecture honnête des dépôts de l'organisation elle-même tient en une phrase : la direction est prouvée, et le lecteur manque.
Les trois chemins évidents s'arrêtent, chacun pour sa raison
Le premier chemin est d'embarquer Python et de piloter overturemaps-py sur l'appareil. Ça marche dans une démo et échoue en revue, parce qu'un runtime Python complet pèse des dizaines de mégaoctets par plateforme et que chaque lecteur d'une équipe applicative connaît déjà la conversation qui suit dans la réunion sur le budget de taille. Le deuxième est de binder DuckDB lui-même, qui tourne aujourd'hui sur les deux plateformes mobiles. C'est réellement viable, et nous nous arrêterions quand même avant d'appeler ça un SDK, parce que DuckDB répond à des requêtes et renvoie des lignes non typées ; les couches Kotlin et Swift placées au-dessus décoderaient chacune le schéma à la main. Vous construiriez la partie dont parle ce billet en appelant ça une intégration.
Le troisième chemin est celui que la plupart des équipes empruntent en silence : extraire côté serveur, envoyer du JSON figé aux clients. Techniquement rien ne cloche. Là où ça coince, c'est la propriété d'auto-service qui rend Overture séduisant au départ, parce qu'un backend, avec son calendrier d'épinglage de version et son pipeline d'extraits, s'interpose désormais entre l'application et les données, et chaque changement de schéma transite par lui. L'argument d'Overture, c'est qu'il n'existe pas de point de terminaison propriétaire. Ce chemin en réinstalle un, avec vous à son service.
Le schéma est le produit : ce qu'un noyau Rust devra faire
Quatre chantiers, et le premier est le produit. Le noyau génère ses types d'enregistrements depuis le dépôt du schéma d'Overture à une version épinglée, et la version fait partie du type. Un binaire construit contre 2026-09-23.1 possède un champ taxonomy.primary sur les enregistrements de lieux et pas de champ categories, parce que le v2.0.0 a remplacé ce dernier par taxonomy plus basic_category. Quand une version déplace le schéma, la montée arrive sous forme de revue d'erreurs de compilation, et non comme une charge utile non typée qui change de forme en production. C'est tout l'argument de la génération de code contre l'analyse manuelle, et c'est aussi pourquoi la section des limites parle de la douleur d'entretenir ce générateur.
Le deuxième chantier, ce sont les extraits bornés. La surface de requête expose une boîte englobante, et sous le capot le prédicat vise d'abord la struct bbox, exactement le mécanisme qui a taillé 81 455 423 lieux à 28 166 en 2,77 secondes. Les extraits de segments de Transportation dans la même boîte ont pris 18,0 secondes, et les 228 935 bâtiments ont pris 37,1 secondes, si bien que le gestionnaire d'extraits va chercher chaque thème par boîte une fois par version et met le résultat en cache.
Le troisième chantier est un cache indexé par GERS. L'identifiant du Global Entity Reference System est la clé de jointure entre les thèmes, et entre vos données et celles d'Overture, donc le cache enregistre les enregistrements par (version, id GERS) et jamais par identifiant seul. Le quatrième chantier est la gestion des versions : une chaîne, une version épinglée, un chemin d'invalidation unique quand vous passez à la suivante. Une esquisse de surface d'appel, aucun code compilé :
let overture = Overture::new(cache_dir)?.pin_release("2026-09-23.1")?;
let places = overture
.theme(Theme::Places)
.bbox(-121.0, 38.7, -119.6, 39.5)
.fetch()?;
// 28,166 rows, only true of release 2026-09-23.1
Un noyau, deux téléphones, et la discipline que nous appliquons déjà
UniFFI génère des bindings Kotlin et Swift depuis une seule interface Rust, et ce fait unique est ce qui rend l'architecture moins chère que trois SDK natifs. Le noyau s'écrit et se teste une fois. Les types d'erreur et les sémantiques de version épinglée traversent la frontière comme de vrais types de plateforme, si bien qu'un champ manquant surgit comme une valeur d'erreur aux sites d'appel Kotlin et Swift plutôt que comme un nil que quelqu'un déballera en courant.
Nous avons déjà livré des travaux de cette forme, et la règle de conception se transporte de ces projets. everymap-rs, notre client Rust sous licence MIT pour cinq fournisseurs géospatiaux, détient 35 implémentations de fournisseurs derrière une seule interface et fait échouer bruyamment, en ces mots, les capacités non prises en charge. Nos bindings HERE pour .NET MAUI ont appris la leçon la plus difficile : écrivez d'abord la surface qu'un développeur taperait réellement, puis taillez le pont pour l'épouser, parce que le pont est la spécification, et nous l'avons appris une version trop tard. Dans le monde UniFFI, cette règle se lit pareil : les sites d'appel Kotlin et Swift doivent être indiscernables, et si une distinction de plateforme fuit dans le code applicatif, c'est que le binding a mal fait son travail. Ici, cette règle ne coûte rien, parce qu'UniFFI couvre Android et iOS depuis une seule définition.
Les limites, et ce que chacune reçoit à la place
- La génération de code du schéma d'une version à l'autre est réellement difficile, et c'est la partie difficile qui porte tout. Le schéma change chaque mois ; le v2.0.0 a déjà cassé des consommateurs de places. Le substitut à une solution est une politique : des types générés par version et des montées revues comme des diffs. Chaque version de schéma que vous décidez de maintenir vivante porte une note de migration et un coût d'entretien.
- Une partie du typage est optionnelle que le SDK le veuille ou non. Dans notre échantillon de Tahoe issu de la version 2026-09-23.1, 896 des 28 166 lieux, soit 3,2 %, avaient un
taxonomy.primaryNULL. Les types doivent porter l'optionalité partout où le schéma la porte, et un champ non optionnel là où les données avouent honnêtement leur absence est un bug en forme de crash. - Le thème addresses est en alpha : 474 000 000 de caractéristiques sans identifiants GERS pour l'instant, selon la documentation d'Overture. Le SDK lirait des adresses comme géométrie plus champs de source et refuserait d'en promettre davantage, sinon la promesse serait la première chose que la publication d'octobre invaliderait.
- Les identifiants GERS changent. La version 2026-09-23 a régénéré les UUID des catégories base et building_part, selon ses notes de version. Un cache indexé par
(version, id GERS)contient cela ; un cache indexé par identifiant seul garderait des jointures orphelines d'une version à l'autre et échouerait en silence, ce qui est précisément la défaillance que toute la conception existe pour éviter. - L'histoire web est hors sujet. UniFFI couvre Android et iOS ; le navigateur exigerait du wasm, et la réponse honnête pour le web est qu'il dispose déjà d'un chemin qui fonctionne, DuckDB dans le navigateur et le pipeline de tuiles. Cette architecture sert les plateformes qui n'ont rien.
- Rien de tout cela n'est livré. Les dépôts Rust cités plus haut appartiennent à l'organisation d'Overture. Le client décrit appartient à un chantier que nous n'avons pas commencé, et l'esquisse du bloc de code est le seul code de ce billet.
Épinglez la version, ou c'est elle qui vous épingle
Si votre application affiche des tuiles Overture aujourd'hui et porte encore derrière elles un dictionnaire de données cartographiques non typées, le schéma bouge déjà sous ce dictionnaire, une version à la fois. La version décisionnelle de ce billet : épinglez la version dans le système de types, lisez le GeoParquet par extraits bornés, mettez en cache sur (version, id GERS), et laissez UniFFI porter un seul noyau vers les deux téléphones. Une rupture de schéma est survivable quand le compilateur la signale. La même rupture qui arrive comme un changement de forme des données en production, c'est ainsi que meurt le code cartographique mobile. Overture a réglé la moitié données ouvertes, au rythme mensuel, avec des identifiants GERS pour joindre. Il reste le lecteur, et un langage tourne déjà là où tournent les deux téléphones.
Merci d'avoir lu jusqu'ici. Si cela ressemble au problème sur lequel vous butez, parlez-nous-en. Un fondateur lit chaque message.
Engager la conversation