The question comes up constantly: you’re in QGIS, you’ve added a vector tile layer from a basemap service or loaded a .mbtiles file, and you want to export those features to a Shapefile or GeoJSON for editing. You right-click the layer and look for “Save Features As” — but the option is either missing or produces empty output.
This is not a QGIS bug. It’s a fundamental property of the vector tile format, and understanding it is the difference between a working extraction workflow and hours of confusion.
What Vector Tiles Actually Are
A Mapbox Vector Tile (MVT) is a binary-encoded tile of geographic data clipped to a fixed grid cell, compressed with Protocol Buffers (protobuf), and served from a tile server or stored in an .mbtiles SQLite database. The specification defines a coordinate system that is tile-local: coordinates are integers between 0 and 4096 representing position within the tile grid, not geographic coordinates.
Each tile contains one or more layers (road network, buildings, water, etc.) with their features clipped to the tile boundary. A polygon that spans multiple tiles appears as a separate clipped fragment in each of those tiles. There is no global feature ID that links the fragments together across tile boundaries.
This design is intentional and excellent for rendering: tiles are small, independently cacheable, decoded in parallel on the GPU. For editing, it is a significant problem. The “feature” you see in QGIS is not the actual feature — it is a tile fragment of the feature at a given zoom level, with potentially simplified geometry.
What QGIS Can and Cannot Do With Vector Tiles
QGIS 3.14+ has native vector tile support for both XYZ tile services and local .mbtiles or .vtpk files. What you get:
- Rendering: Full support. Styles apply via MapboxGL-compatible style JSON or QGIS layer styling.
- Attribute inspection: The identify tool works on individual features within a tile.
- Export via “Save Features As”: This works for file-based sources only (
.mbtiles,.vtpk), and only exports features currently visible in the map canvas at the current zoom level, each tile fragment as a separate feature.
The result is a layer with tile-clipped polygons, duplicate fragments at tile boundaries, and simplified geometry from whatever zoom level was active at export time. For most analytical purposes, this is not usable data — it’s a rendering artifact.
For XYZ tile services (remote tile servers), “Save Features As” is not available at all. The server returns tiles on demand; QGIS does not buffer the complete dataset.
What GDAL Can Do: Reading MVT With ogr2ogr
GDAL includes an MVT driver that treats a vector tile source as a set of OGR layers. This is the right tool for bulk extraction.
Prerequisites: GDAL 2.3+ with libsqlite3 support. Check with ogrinfo --version. Most recent QGIS installations bundle a recent GDAL.
Reading an MBTiles file
# List all layers in the MBTiles
ogrinfo input.mbtiles
# Typical output — one OGR layer per MVT layer
# Layer: road (Line), road (Polygon), building, water, landuse ...
Each MVT layer becomes an OGR layer. Extract a specific layer to GeoJSON:
ogr2ogr \
-f GeoJSON buildings.geojson \
input.mbtiles \
building \
-t_srs EPSG:4326
The -t_srs EPSG:4326 is mandatory. The MVT driver reads tile coordinates and reprojects to the output CRS. Omitting it leaves you with tile-local integer coordinates that have no geographic meaning.
Specifying zoom level: By default, ogr2ogr reads from the maximum zoom level available in the MBTiles. This gives the highest geometry detail but the largest output. To read from a specific zoom:
ogr2ogr \
-f GeoJSON buildings.geojson \
"MVT:input.mbtiles" \
building \
-t_srs EPSG:4326 \
-dsco ZOOM_LEVEL=14
Lower zoom levels have more aggressively simplified geometry. For area calculations or editing, use the maximum available zoom.
Reading a tile directory
If you have tiles in a directory structure (/{z}/{x}/{y}.pbf), GDAL can read those too:
ogr2ogr \
-f GeoJSON output.geojson \
"MVT:/path/to/tiles" \
-t_srs EPSG:4326
The tile fragment problem persists
Here is the important caveat that the GDAL documentation mentions but does not emphasize enough: the tile clipping artifacts remain in the output. A building polygon that spans two tiles appears as two polygons in the GeoJSON, with a hard edge where the tile boundary was. ogr2ogr does not merge fragments across tile boundaries.
For display and rough analysis this may be acceptable. For editing, topology operations, or area calculations, it is not.
Fixing tile boundary artifacts with GDAL/PostGIS:
The approach is to dissolve on a feature attribute after extraction. If the MVT layer has a unique feature ID (id attribute), you can dissolve fragments in PostGIS:
-- Load the fragmented GeoJSON into PostGIS
-- Then merge by id
SELECT id, ST_UnaryUnion(ST_Collect(geom)) as geom, name
FROM buildings_raw
GROUP BY id, name;
In GDAL alone, use ogr2ogr with -dialect SQLITE -sql for a dissolve:
ogr2ogr \
-f GeoJSON buildings_merged.geojson \
buildings_fragmented.geojson \
-dialect SQLITE \
-sql "SELECT id, name, ST_Union(geometry) as geometry FROM buildings_fragmented GROUP BY id, name"
This requires GDAL to be built with GEOS and SQLite support. Most distribution builds have both.
Tile Coordinate System Gotchas
Vector tiles use Spherical Mercator (EPSG:3857) internally, with coordinates quantized to a 4096-unit grid per tile. When GDAL reprojects to EPSG:4326, the reprojection is correct at the scale of the tile — but very small features (buildings at zoom 12 vs zoom 16) have different coordinate precision depending on which zoom level they come from.
If you’re working with data that needs submeter accuracy, always extract from the maximum zoom level available. At zoom 16, the tile pixel represents roughly 0.6m at the equator. At zoom 12, it’s about 9.5m. For urban mapping, the difference is significant.
A second gotcha: some MVT generators clip features to tile boundaries with a buffer (typically 64 or 128 units beyond the tile edge) to handle features that overlap tiles. The GDAL MVT driver respects this buffer during decode, so features near tile edges may have extra vertices beyond the nominal tile boundary. These get cleaned up during reprojection, but you may see unexpected geometry at the output edges of your bounding box.
When to Skip Extraction and Find the Source Data
For most common use cases, the right answer is to find the original dataset rather than extract from tiles. Vector tile services are derived products — the source data is higher quality, not tile-clipped, and often freely available:
- OpenStreetMap tiles (MapTiler, Protomaps, etc.): Use the Geofabrik OSM extracts for the region you need. These are full-fidelity OSM data in PBF format, convertible to any format via osmium or ogr2ogr with the OSM driver. Far better than tile extraction.
- Government basemaps (OS, IGN, BKG, etc.): Most national mapping agencies publish open data downloads at higher resolution than their tile services. Check the agency’s data portal.
- Commercial tiles (Mapbox, HERE, Esri): These are often proprietary datasets. Extraction from tiles for redistribution may violate the terms of service. Always check the license before extracting.
If you must work with the tile data directly — either because the source isn’t available or you need the pre-processed attribute schema from the tile layer — the GDAL approach above gives you the most consistent results.
Extracting from QGIS Headless for Automation
If you’re building an automated pipeline that extracts tiles repeatedly (for different extents or zoom levels), doing it through QGIS headless is more scriptable than clicking through the GUI:
# Using qgis_process for batch extraction
qgis_process run gdal:ogr2ogr \
--INPUT=input.mbtiles \
--CONVERT_ALL_LAYERS=False \
--OPTIONS="-t_srs EPSG:4326 -dsco ZOOM_LEVEL=15" \
--OUTPUT=output.gpkg
For production pipelines that convert regularly between GIS formats — including MVT extraction, coordinate system transforms, and validation — a dedicated conversion layer avoids rebuilding these GDAL commands for every project. The fragmented-polygon problem still needs to be solved upstream, but at least the projection and format handling becomes consistent.
Summary
| Approach | Use Case | Tile Fragments | Geometry Quality |
|---|---|---|---|
| QGIS “Save Features As” | Quick visual check | Yes | Current zoom only |
| ogr2ogr MBTiles | Bulk extraction, all features | Yes | Max zoom supported |
| ogr2ogr + ST_Union | Analytical layers | Mostly resolved | Max zoom |
| Original source data | Production use | No | Full resolution |
The vector tiles format is excellent at what it was designed for: fast, styleable, bandwidth-efficient rendering. Treating it as an editable data source requires working around the tile clipping by design. For the common workflows — converting GeoJSON to Shapefile for downstream analysis, or choosing the right storage format for a project — the source dataset is always the cleaner starting point. When you do need to work with tiles directly, GDAL’s MVT driver plus a dissolve step on a feature ID gets you to usable data with the least friction.