Map Data

TopoJSON, GeoJSON and Sourcing Map Data

GeoJSON (RFC 7946) stores each feature's coordinates in full, so shared borders appear twice. TopoJSON 4,906 stores them once as arcs of quantized, delta-encoded integers, and is far smaller. topojson-client (3.1.0) converts back: topojson.feature(topo, object) gives features to fill, and topojson.mesh(topo, object, (a, b) => a !== b) the interior borders as one line.

Measured on jsDelivr 15,886 : world-atlas@2.0.2/countries-110m.json (177 countries, 595 arcs) is 108 KB, land-110m.json 55 KB, countries-50m.json 756 KB; us-atlas@3.0.1/states-10m.json is 115 KB and counties-10m.json 842 KB.

Both derive from Natural Earth (public domain) and are ISC licensed. Countries carry ISO 3166-1 numeric ids as strings ("036" is Australia), which BookNest's sample regions reuse; jsDelivr allows cross-origin fetches.

A small inline TopoJSON of Europe turned into GeoJSON features and a mesh of shared bordersHTMLLive
<!doctype html>
<style>
  body { margin: 0; padding: 8px; background: #fafaf7; font: 12px system-ui, sans-serif; color: #263238; }
  svg { width: 100%; max-width: 600px; display: block; background: #eef4f7; }
</style>
<script src="https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/topojson-client@3.1.0"></script>
<p><label><input type="checkbox" id="mesh" checked> topojson.mesh(): interior borders as one path</label></p>
<svg viewBox="0 0 600 330" font-size="10"></svg>
<p id="out"></p>
<script>
  // 25 European countries, simplified from world-atlas countries-110m.json (Natural Earth, public domain).
  // Borders are stored once as quantized, delta-encoded arcs shared by both neighbours.
  const topo = {"type":"Topology","transform":{"scale":[0.03600036000360004,0.016925586033320103],"translate":[-180,-85.60903777459771]},"objects":{"countries":{"type":"GeometryCollection","geometries":[{"type":"Polygon","id":"578","properties":{"name":"Norway"},"arcs":[[-1,1,2,3]]},{"type":"MultiPolygon","id":"250","properties":{"name":"France"},"arcs":[[[4,5,6,7,8,9,10,11]],[[12]]]},{"type":"Polygon","id":"752","properties":{"name":"Sweden"},"arcs":[[-3,13,14]]},{"type":"Polygon","id":"616","properties":{"name":"Poland"},"arcs":[[-16,-17,17,18,19,20,-22,22]]},{"type":"Polygon","id":"040","properties":{"name":"Austria"},"arcs":[[23,24,25,26,27,28,29]]},{"type":"Polygon","id":"348","properties":{"name":"Hungary"},"arcs":[[-31,31,32,33,34,-24,35]]},{"type":"Polygon","id":"642","properties":{"name":"Romania"},"arcs":[[-37,37,38,39,-32,-41,-42]]},{"type":"Polygon","id":"276","properties":{"name":"Germany"},"arcs":[[-20,42,-28,43,-5,44,45,46,47,48,49]]},{"type":"Polygon","id":"100","properties":{"name":"Bulgaria"},"arcs":[[-39,50,51,52,53,54]]},{"type":"MultiPolygon","id":"300","properties":{"name":"Greece"},"arcs":[[[55]],[[-53,56,57,58,59]]]},{"type":"Polygon","id":"191","properties":{"name":"Croatia"},"arcs":[[-34,60,61,62,63,64]]},{"type":"Polygon","id":"756","properties":{"name":"Switzerland"},"arcs":[[-27,65,-6,-44]]},{"type":"Polygon","id":"442","properties":{"name":"Luxembourg"},"arcs":[[-45,-12,66]]},{"type":"Polygon","id":"056","properties":{"name":"Belgium"},"arcs":[[-46,-67,-11,67,68]]},{"type":"Polygon","id":"528","properties":{"name":"Netherlands"},"arcs":[[-47,-69,69]]},{"type":"Polygon","id":"620","properties":{"name":"Portugal"},"arcs":[[70,71]]},{"type":"Polygon","id":"724","properties":{"name":"Spain"},"arcs":[[-71,72,-9,73]]},{"type":"Polygon","id":"372","properties":{"name":"Ireland"},"arcs":[[74,75]]},{"type":"MultiPolygon","id":"380","properties":{"name":"Italy"},"arcs":[[[-26,76,77,-7,-66]],[[78]],[[79]]]},{"type":"MultiPolygon","id":"208","properties":{"name":"Denmark"},"arcs":[[[-49,80]],[[81]]]},{"type":"MultiPolygon","id":"826","properties":{"name":"United Kingdom"},"arcs":[[[-76,82]],[[83]]]},{"type":"Polygon","id":"705","properties":{"name":"Slovenia"},"arcs":[[-25,-35,-65,84,-77]]},{"type":"Polygon","id":"246","properties":{"name":"Finland"},"arcs":[[-86,86,-14,-2]]},{"type":"Polygon","id":"703","properties":{"name":"Slovakia"},"arcs":[[-88,-36,-30,88,-18]]},{"type":"Polygon","id":"203","properties":{"name":"Czechia"},"arcs":[[-19,-89,-29,-43]]}]}},"arcs":[[[5794,9139],[70,29]],[[5794,9139],[12,41],[-36,23],[-83,-89],[-114,27]],[[5573,9141],[-21,-41],[-52,9],[-34,-33],[-89,-234],[-28,1],[-7,-233],[-36,-75]],[[5306,8535],[-18,37],[-55,-69],[-37,-14],[-39,31],[-18,199],[153,149],[118,196],[123,119],[107,23],[42,49],[100,9],[87,-43],[-36,-16],[31,-37]],[[5172,7980],[53,-26],[-18,-82]],[[5207,7872],[-39,-53],[22,-44]],[[5190,7775],[17,-135]],[[5207,7640],[-26,-34],[-95,-3],[-3,-36]],[[5083,7567],[-74,7],[-62,50]],[[4947,7624],[20,153],[-95,157],[83,-2],[-9,67],[27,-25],[97,106]],[[5070,8080],[88,-96]],[[5158,7984],[14,-4]],[[5243,7577],[18,22],[-5,-96],[-13,74]],[[5573,9141],[81,-69],[10,-114]],[[5664,8958],[-48,-17],[-22,-77],[-98,-99],[-20,-83],[46,-74],[-55,-81],[-26,-154],[-34,5],[-15,-46],[-32,-3],[-54,206]],[[5654,8105],[-2,138]],[[5627,7958],[38,79],[-11,68]],[[5627,7958],[-103,24]],[[5524,7982],[-107,96]],[[5417,8078],[-25,156]],[[5392,8234],[98,65],[56,-25]],[[5631,8268],[-85,6]],[[5631,8268],[21,-25]],[[5472,7901],[-22,-75]],[[5450,7826],[-66,-20]],[[5384,7806],[-46,36],[-48,-13]],[[5290,7829],[-23,37]],[[5267,7866],[92,-3],[19,83]],[[5378,7946],[93,-17]],[[5471,7929],[1,-28]],[[5631,7887],[-18,32]],[[5631,7887],[-69,-104]],[[5562,7783],[-39,-13]],[[5523,7770],[-63,36]],[[5460,7806],[-10,20]],[[5472,7901],[24,-21],[82,51],[35,-12]],[[5822,7734],[-38,12]],[[5822,7734],[-29,-94]],[[5793,7640],[-36,28],[-47,-29],[-73,8],[-8,25]],[[5629,7672],[-67,111]],[[5739,7907],[-108,-20]],[[5784,7746],[-45,161]],[[5417,8078],[-77,-50],[38,-82]],[[5267,7866],[-60,6]],[[5172,7980],[-4,40]],[[5168,8020],[3,40]],[[5171,8060],[21,158]],[[5192,8218],[52,32],[-7,55]],[[5237,8305],[39,2]],[[5276,8307],[28,-58],[44,27],[44,-42]],[[5793,7640],[-15,-100]],[[5778,7540],[-53,-11]],[[5725,7529],[0,-29],[-87,0]],[[5638,7500],[-16,58]],[[5622,7558],[7,114]],[[5730,7144],[-43,-23],[-34,21],[5,26],[72,-24]],[[5725,7529],[-1,-59]],[[5724,7470],[-65,-8],[5,-43],[-35,17],[38,-120],[-34,-54],[10,-52],[-41,25],[-42,164]],[[5560,7399],[24,72]],[[5584,7471],[54,29]],[[5523,7770],[5,-62]],[[5528,7708],[-85,23],[-6,-25],[79,-128]],[[5516,7578],[-4,-10]],[[5512,7568],[-131,178]],[[5381,7746],[45,-3],[34,63]],[[5290,7829],[-41,-51],[-59,-3]],[[5158,7984],[10,36]],[[5070,8080],[22,12]],[[5092,8092],[46,7],[33,-39]],[[5092,8092],[39,103],[61,23]],[[4749,7532],[21,24],[53,-53],[-30,-253]],[[4793,7250],[-40,-14],[-18,111],[14,185]],[[4749,7532],[-10,68],[39,43],[169,-19]],[[5083,7567],[-25,-73],[-35,-13],[-20,-134],[-63,-122],[-61,0],[-28,-43],[-58,68]],[[4828,8241],[-17,-95],[-88,-26],[8,121],[59,74]],[[4790,8315],[0,-63],[38,-11]],[[5384,7806],[3,-54]],[[5387,7752],[-45,-13],[8,-76],[163,-232],[-5,-21],[-39,37],[-22,-145],[-19,122],[-117,136],[-28,93],[-36,26],[-40,-39]],[[5410,7312],[21,5],[-12,-95],[-74,58],[4,31],[61,1]],[[5242,7474],[14,19],[16,-42],[-27,-94],[-3,117]],[[5237,8305],[-8,109],[65,55],[-18,-162]],[[5344,8373],[-8,-77],[-33,58],[41,19]],[[4790,8315],[53,-34],[-15,-40]],[[4914,8213],[-85,200],[32,109],[56,0],[-30,-64],[59,8],[-33,-101],[29,-4],[71,-176],[34,-11],[-32,-117],[-97,-4],[-64,-43],[51,86],[-51,34],[29,18],[-10,71],[41,-6]],[[5381,7746],[6,6]],[[5780,8633],[95,139],[-41,41],[5,133],[-32,67],[26,45],[-43,39],[4,42]],[[5780,8633],[-145,-39],[-43,51],[6,146],[107,114],[-41,53]],[[5613,7919],[14,39]],[[5471,7929],[53,53]]]};

  const countries = topojson.feature(topo, topo.objects.countries);             // GeoJSON features to fill
  const borders = topojson.mesh(topo, topo.objects.countries, (a, b) => a !== b); // shared borders only
  const projection = d3.geoConicEqualArea().parallels([43, 62]).rotate([-10, 0])
    .fitExtent([[10, 10], [590, 320]], countries);
  const path = d3.geoPath(projection), svg = d3.select('svg');
  svg.append('path').datum(d3.geoGraticule10()).attr('d', path).attr('fill', 'none').attr('stroke', '#d5e1e8');
  svg.append('g').selectAll('path').data(countries.features).join('path').attr('d', path)
    .attr('fill', (d, i) => d3.schemeTableau10[i % 10]).attr('fill-opacity', 0.35).attr('stroke', 'none')
    .append('title').text(d => `${d.properties.name} (id "${d.id}")`);
  const mesh = svg.append('path').datum(borders).attr('d', path)
    .attr('fill', 'none').attr('stroke', '#b5452f').attr('stroke-width', 1.2);
  svg.append('g').selectAll('text').data(countries.features.filter(f => path.area(f) > 1500)).join('text')
    .attr('transform', d => `translate(${path.centroid(d)})`).attr('text-anchor', 'middle').text(d => d.id);
  d3.select('#mesh').on('change', e => mesh.attr('display', e.target.checked ? null : 'none'));

  const kb = s => (s.length / 1024).toFixed(1) + ' KB';
  d3.select('#out').text(`TopoJSON ${kb(JSON.stringify(topo))} (${topo.arcs.length} arcs) → ` +
    `GeoJSON ${kb(JSON.stringify(countries))} (${countries.features.length} features); ` +
    `numbers are ISO 3166-1 ids, such as "826" for the United Kingdom.`);
</script>