geojsonkit.org
GeoJSON utilities, in the browser
Say hi →

GeoJSON to TopoJSON

The same map, without the duplication. Every border shared by two countries is written twice in GeoJSON; TopoJSON writes it once and has both features point at it. Add integer quantisation and delta-encoded arcs and a boundary file usually loses most of its weight.

GeoJSON to TopoJSON

updated 30 August 2026

Drop a .geojson file, or

What this tool does

It rewrites a GeoJSON FeatureCollection as a TopoJSON Topology: one arcs array holding every run of coordinates in the file, and geometries that refer to those runs by index instead of carrying their own copy. Two features that share a border end up pointing at the same arc — the second one as a negative index, which means "that arc, backwards".

The intent it closes: "this boundary file is 12 MB and the map takes four seconds to appear." Shared borders and full float precision are where the bytes are. TopoJSON removes the first and quantisation removes the second, and unlike simplification neither one changes the shape you see at normal zoom.

How this tool works

1. Quantise

The bounding box of the whole collection is mapped onto an integer grid — 10,000 steps across by default — and every position is rounded onto it. The grid spacing goes into transform.scale and the corner into transform.translate, so any TopoJSON reader can undo it exactly. On a country-sized file 1e4 steps is about 11 m per step, which is finer than the line width at any zoom that shows the whole country.

2. Extract the arcs

Every ring and line is cut at its junctions — the points where the neighbourhood stops matching. Along a border shared by two polygons, each interior point has the same two neighbours in both features (in opposite order), so nothing is cut there; the two ends do differ, so that is where the cuts land. The run between them is stored once and both polygons reference it.

3. Delta-encode

Inside an arc only the first position is absolute; the rest are stored as the step from the previous one. Neighbouring vertices are close together, so those steps are small integers — which is where quantisation pays off a second time, in how many digits each number takes.

Options

Quantisation

1e4 is the default and the setting that makes the format worth using. 1e5 and 1e6 trade size for precision — 1e6 on a country is roughly 0.1 m, well past what any source data justifies. none writes exact floats and no transform, which is valid TopoJSON and still removes the duplicated borders, but gives up most of the saving.

Share arcs between features

On, the junction pass runs and identical runs are stored once. Off, every ring becomes its own arc — the output is still valid TopoJSON, and it is a useful comparison: the difference between the two arc counts in the status line is exactly how much duplication your file contains.

Keep properties

On, each geometry keeps its properties object and its id. Off drops the properties (ids are always kept) — worth trying when the geometry is for display only and the attributes are half the file.

Example

Two squares sharing the edge at x = 1:

{"type":"FeatureCollection","features":[
 {"type":"Feature","properties":{"n":"a"},"geometry":{"type":"Polygon",
  "coordinates":[[[0,0],[1,0],[1,1],[0,1],[0,0]]]}},
 {"type":"Feature","properties":{"n":"b"},"geometry":{"type":"Polygon",
  "coordinates":[[[1,0],[2,0],[2,1],[1,1],[1,0]]]}}]}

Output (quantisation off, for readability):

{"type":"Topology","bbox":[0,0,2,1],
 "objects":{"data":{"type":"GeometryCollection","geometries":[
   {"type":"Polygon","arcs":[[0,1]],"properties":{"n":"a"}},
   {"type":"Polygon","arcs":[[2,-1]],"properties":{"n":"b"}}]}},
 "arcs":[[[1,0],[1,1]],[[1,1],[0,1],[0,0],[1,0]],[[1,0],[2,0],[2,1],[1,1]]]}

Arc 0 is the shared edge. The second polygon references it as -1, which is ~0 — arc 0 traversed backwards. Move one of those two coordinates and both polygons move together; that is the property the format exists for.

Tips & common pitfalls

  • Borders only share if they are byte-identical. Two files digitised separately, or one that has been through a rounding step, will have borders that nearly match — and near-match is no match. Run coordinate precision over everything first if the arc count looks too high.
  • Quantise before you simplify, not after. Simplify with keep shared borders on, then convert; the topology survives and the two savings multiply.
  • The third coordinate is dropped. TopoJSON is two-dimensional. Elevation in a GPS track does not survive the round trip — keep the GeoJSON if you need it.
  • You need a reader on the other end. Nothing renders TopoJSON directly; d3 uses topojson.feature(), and most map libraries want GeoJSON back. The win is transfer size, not the drawing step.
  • Winding order is left as it was. Some TopoJSON producers reverse the rings relative to GeoJSON. This tool does not touch them, so a round trip returns what you put in; if a spherical renderer fills the wrong side of the world, run fix winding order on the GeoJSON first.

FAQ

How much smaller does it actually get?

The status line tells you for your file, minified against minified. For an administrative boundary file with lots of shared borders, 70–90% is normal. For scattered points with no shared geometry there is nothing to share, and the saving is only what quantisation gives.

Is quantisation lossy?

Yes — that is the point. Positions are rounded onto a grid, and at 1e4 across a whole country that is roughly 11 m. If you need the original coordinates back exactly, choose none, which keeps floats and simply removes the duplication.

Can it convert back?

Not yet — this direction is the one that saves bytes. Reading a topology back is topojson.feature(topology, topology.objects.data) in the topojson-client library, and the output here is written to be exactly what that expects.

Why is my arc count nearly the same as my ring count?

Because nothing is being shared. Either the features genuinely do not touch, or their touching edges are not identical to the last decimal. Toggle share arcs off and compare the two counts — if they barely move, it is the second case.