GIS · GeoJSON

GeoJSON Merger

Combine two or more GeoJSON files into a single FeatureCollection. Tag features by source, deduplicate by geometry, and download in one click.

Sources
Options
All processing happens in your browser · no data sent to any server

What This Tool Does

Combine any number of GeoJSON files into a single FeatureCollection with full control over deduplication and source tracking.

🔀
Unlimited sources
Start with two slots and add more with the "Add source" button. Each slot accepts paste, file upload (.geojson, .json), or drag-and-drop independently.
🏷️
Source tagging
Optionally inject a _source property on every feature with the name of the slot it came from. Name slots anything — "Roads", "POIs", "Layer A" — and filter by that in your map.
🔍
Geometry deduplication
Skip features that have the exact same geometry as a feature already seen in an earlier source. Useful when files have overlapping coverage and you don't want duplicate shapes.
📊
Per-source summary
After merging, a table shows each source's input feature count, how many were added, and how many were skipped by deduplication. Catch missing data before you use the file.
📝
Pretty or minified
Toggle between pretty-printed (human-readable, 2-space indent) and minified (compact, smaller file size) JSON output. Both are valid GeoJSON.
🔒
100% client-side
All parsing and merging runs in your browser with JSON.parse. No data is uploaded. Works offline once loaded. Your GeoJSON never leaves your device.

How to Use

1
Add your sources
Paste GeoJSON text into Source 1 and Source 2. Upload .geojson files with the Upload button, or drag-and-drop files directly onto each slot. Click "Load sample" for a two-file Paris/Berlin cities example.
2
Name your sources
Click the source name (e.g. "Source 1") and type a meaningful label like "Roads", "POIs", or "Dataset A". These labels appear in the _source property and the per-source summary table.
3
Add more sources if needed
Click "Add source" for a third, fourth, or any number of additional slots. Each slot is independent — add files in any order. Remove extra slots with the × button (minimum 2 are always kept).
4
Set options
Enable "Tag features with source name" to add a _source property. Enable "Deduplicate by geometry" if sources have overlapping coverage. Toggle pretty-print for readability vs file size.
5
Merge
Click "Merge GeoJSON". The output FeatureCollection appears with a stats bar (total features, sources, duplicates removed) and a per-source breakdown table.
6
Download or copy
Click "Download merged.geojson" or Copy. Load the result directly in Leaflet, Mapbox, QGIS, geojson.io, or any tool that accepts GeoJSON.

Logic Behind the Tool

How sources are parsed, combined, and optionally deduplicated.

Input normalisation
Each source is parsed with JSON.parse(). The tool accepts a FeatureCollection (uses .features array), a single Feature (wrapped in an array), or a bare geometry object (wrapped in a Feature with empty properties). All three produce a flat array of Feature objects before merging.
Merge strategy
Features from each source are deep-cloned with JSON.parse(JSON.stringify(f)) to avoid mutating the originals. They are concatenated in slot order into a single array. The output wraps the array in a FeatureCollection. No spatial operation is performed — this is a simple feature concatenation, not a topological union.
Geometry deduplication
When enabled, each feature's geometry object is serialised to a string with JSON.stringify(geometry) and added to a Set. If the same string was seen from an earlier source, the feature is skipped. This is exact string equality — coordinate order, precision, and nesting must match exactly. Properties are not compared.
Source tagging
When enabled, feature.properties._source = slot.label is set on every feature after deep-cloning. Existing _source properties from the input are overwritten. This is intentional — the tag reflects where the feature came from in this merge operation, not any prior source history.

Frequently Asked Questions

It concatenates features — this is not a spatial union or intersection. Each feature from each source is added as-is into the output FeatureCollection. If you have two polygon layers representing different areas, the output will contain both polygons. If you want to compute the geometric union of two polygons (combine them into one shape), that is a spatial operation requiring a library like Turf.js or GDAL.

Use the style or pointToLayer option of L.geoJSON: L.geoJSON(data, { style: f => f.properties._source === 'Roads' ? {color:'blue'} : {color:'red'} }). In Mapbox GL JS, use a filter expression: ["==", ["get", "_source"], "Roads"] on a separate layer for each source. In QGIS, add a categorised symbol renderer on the _source field.

Only if the features have identical geometry objects (same coordinates, same type, same precision). Enable "Deduplicate by geometry" to remove exact duplicates. If your files come from different sources with slightly different coordinate precision, deduplication will not catch them — the geometries must match string-for-string. For fuzzy spatial deduplication (within N metres), use Turf.js or QGIS.

Pretty-printed output uses 2-space indentation and newlines, making it readable in a text editor but larger in file size. Minified output strips all whitespace, reducing file size significantly — a 1MB pretty GeoJSON is typically 600–700KB minified. Use minified when serving the file from a web API or loading it in a browser map; use pretty when you want to inspect or version-control the file.