Geometry Registry
geo.map accepts a registry id, a URL, or geometry you pass directly. A registry id is the fastest path: nothing is fetched until you use a pack, and one pack is one request no matter how many aliases or maps on the page ask for it.
geo: { map: 'world/countries@110m' } // canonical id
geo: { map: 'world/countries' } // detail-free alias: the lightest pack
geo: { map: 'us' } // alias for us/states@10m
geo: { map: 'jp/prefectures' } // alias, the country's own word for its tier
geo: { map: 'eu/nuts2@20m' } // Eurostat regions
What travels with each pack
Finding, converting, and hosting boundary files is the tax on every map project. Each of the 26 packs carries four things so you do not have to work them out yourself.
A recommended join key. Data is keyed the way it is actually keyed: us/states joins on "CA", admin-1 packs join on ISO 3166-2 codes like "DE-BY". Generic key detection cannot get this right on its own, an admin-1 feature also carries a country-level code, and choosing that would give every Japanese prefecture the same key.
Repaired identifiers. Natural Earth publishes ISO_A3 as -99 for France and Norway, among others, because it splits their overseas parts into separate features. A join on iso_a3 against the raw file silently loses both countries. The pipeline repairs this once, at build time.
A recommended projection and view, for packs where the generic default is not just suboptimal but wrong. us gets albersUsa, because Alaska's Aleutians cross the antimeridian and the map would otherwise span the whole width of the world. The NUTS packs get an azimuthal equal-area projection centered on Europe with a mainland-only view, because the geometry reaches from French Guiana to Réunion and fitting all of it leaves Europe a few pixels across. An explicit geo.projection or geo.view always overrides the recommendation.
Provenance. Source, license, vintage, boundary policy, and detail level, available through ApexMaps.mapMeta(id) and ApexMaps.catalogue(). Required attribution renders automatically, so a NUTS map credits EuroGeographics whether or not anyone remembered to add it.
The 26 packs
World
| Pack id | Aliases | Covers | Join key |
|---|---|---|---|
world/countries@110m | world, world/countries | Countries, low detail | iso_a3 |
world/countries@50m | Countries, medium detail | iso_a3 | |
world/land@110m | world/land | Coastline only, no data | none |
world/land@50m | Coastline only, no data | none |
United States
| Pack id | Aliases | Covers | Join key |
|---|---|---|---|
us/states@10m | us/states, us | 50 states | abbr (USPS) |
us/counties@10m | us/counties | All 3,231 counties | fips |
us/nation@10m | Outline only, no data | none |
Both US packs recommend albersUsa, which insets Alaska and Hawaii. County FIPS codes are five digits with a leading zero ("06037"); a numeric data key that lost it is repaired automatically, see Joins.
European Union (Eurostat NUTS)
| Pack id | Aliases | Covers | Join key |
|---|---|---|---|
eu/nuts0@20m | eu | Countries | nuts_id |
eu/nuts1@20m | eu/regions | Major regions | nuts_id |
eu/nuts2@20m | Basic regions | nuts_id | |
eu/nuts3@20m | Small regions | nuts_id |
All four recommend EPSG:3035-equivalent (azimuthal equal-area, rotated on Europe) with a mainland-only view, and credit EuroGeographics on screen.
Admin-1, 15 countries
Natural Earth's "admin-1" tier is not the same administrative level everywhere, so each alias uses the country's own term for what the pack actually contains.
| Pack id | Aliases | Level | Notes |
|---|---|---|---|
cn/admin1@10m | cn/provinces, cn | Provinces | |
in/admin1@10m | in/states, in | States | |
jp/admin1@10m | jp/prefectures, jp | Prefectures | |
de/admin1@10m | de/states, de | States | |
gb/admin1@10m | gb/districts, gb | Districts and unitary authorities | Not the 4 countries or 12 regions; use eu/nuts1@20m for those |
fr/admin1@10m | fr/departments, fr | Departments | Not the 13 metropolitan regions; use eu/nuts1@20m. Default view is metropolitan France |
it/admin1@10m | it/provinces, it | Provinces | Not the 20 regions; use eu/nuts2@20m |
ca/admin1@10m | ca/provinces, ca | Provinces and territories | |
br/admin1@10m | br/states, br | States | |
ru/admin1@10m | ru/regions, ru | Federal subjects | Custom rotation, Chukotka crosses the antimeridian |
mx/admin1@10m | mx/states, mx | States | |
au/admin1@10m | au/states, au | States and territories | Default view excludes Heard and McDonald Islands |
kr/admin1@10m | kr/provinces, kr | Provinces | |
es/admin1@10m | es/provinces, es | Provinces | Not the 17 autonomous communities; use eu/nuts2@20m |
id/admin1@10m | id/provinces, id | Provinces |
All 15 join on iso_3166_2 (e.g. "DE-BY", "JP-13").
Checking provenance
ApexMaps.mapMeta('us/counties@10m')
// { source: 'US Census Bureau TIGER/Line via us-atlas 3.0', license: 'public domain',
// vintage: '2023', detail: 'high', keyField: 'fips', levelName: 'Counties', ... }
ApexMaps.catalogue() // every built-in pack, unfiltered, with provenance
ApexMaps.listMaps() lists every registered id and alias. A typo in geo.map throws with a suggestion computed the same way a failed join suggestion is, by edit distance against the registered ids.
Pointing at your own copy: setGeoSource
Packs are fetched from jsDelivr by default, so nothing needs installing to try one. Install the dataset separately, apexmaps-geo, when you want the files locally: offline work, air-gapped deployments, or build-time resolution.
npm install apexmaps-geo
// No network: resolve packs from the installed dataset
ApexMaps.setGeoSource((file) => import(`apexmaps-geo/${file}`).then((m) => m.default))
// Self-hosted: any base URL that serves the same files
ApexMaps.setGeoSource('https://cdn.example.com/apexmaps-geo/')
apexmaps-geo ships as its own package, versioned independently of apexmaps, because boundaries change on their own schedule: NUTS is revised every three years, US counties re-district on the census, and countries rename themselves. A boundary correction should not force a library upgrade.
Status: apexmaps-geo is prepared but has not had its first publish yet, so the default jsDelivr source 404s until it does. Until then, pass geometry directly to geo.map or call setGeoSource() with your own loader.
Registering your own geometry
ApexMaps.registerMap(id, geometry, meta) adds a pack under an id of your choosing, a floor plan, a custom region, anything with a GeoJSON or TopoJSON shape. This is a free, unlicensed feature:
ApexMaps.registerMap('office/floor-3', floorPlanGeoJson, {
source: 'Internal facilities team',
license: 'proprietary',
keyField: 'roomId',
})
Registered geometry is looked up the same way as a built-in pack, so geo.map: 'office/floor-3' works exactly like geo.map: 'us/states'.