Skip to content

VersaTiles Container Format Specification v2.1 ​

NOTE

This page is generated from the canonical specification in versatiles-spec. Report problems and propose changes there; edits made here are overwritten.

Source: v02/readme.md.

1. Introduction ​

This document defines the VersaTiles Container Format v2.1, which describes the structure and encoding mechanisms for efficiently storing large numbers of map tiles.

2. General Guidelines ​

  • Byte order: All numeric values are encoded in big-endian byte order.
  • Tile organisation: Tiles are organised according to the XYZ scheme, with the origin (x=0, y=0) at the top left (northwest) corner.
  • Zoom levels: Valid zoom levels range from 0 to 30, in line with TileJSON 3.0. This applies to the zoom levels in the File Header and in the Block Index.
  • Unknown values: Values not listed in this specification are reserved for future versions. A reader encountering a reserved value must reject the container. It must not substitute a default, and it must not pass the affected data through unchanged.

3. File Structure ​

The VersaTiles container format consists of four main components:

  1. File Header: Introduces the container file, details its global properties, and indicates the locations of the Metadata and Block Index.
  2. Metadata: Provides detailed information about the tileset, including attribution and layer definitions.
  3. Blocks: Aggregates tiles into larger units (Blocks) for efficient storage and access, each containing Tile Blobs and Tile Index.
  4. Block Index: Acts as a parent directory for all blocks within the file.
File Format
File Format

3.1. File Header ​

  • Length: 66 bytes.
  • Position: At the beginning of the file.
  • Purpose: Outlines essential file properties and indicates subsequent section locations.
  • All offsets are relative to the beginning of the file.
  • The minimum zoom level must be less than or equal to the maximum zoom level.
  • The bounding box values must lie within -180 to 180 degrees longitude and -90 to 90 degrees latitude. The minimum must be less than or equal to the maximum for both axes, so bounding boxes crossing the antimeridian are not supported. A tileset that crosses the antimeridian should use the full longitude range (-180 to 180).
OffsetLengthTypeDescription
014stringFile identifier ("versatiles_v02")
141u8tile_format value
151u8precompression value
161u8minimum zoom level
171u8maximum zoom level
184i32bbox min x (10⁷ × lon)
224i32bbox min y (10⁷ × lat)
264i32bbox max x (10⁷ × lon)
304i32bbox max y (10⁷ × lat)
348u64offset of Metadata
428u64length of Metadata
508u64offset of Block Index
588u64length of Block Index

3.1.1. Value tile_format ​

Value hexValue decTypeMIME type
0x000binapplication/octet-stream
0x1016pngimage/png
0x1117jpgimage/jpeg
0x1218webpimage/webp
0x1319avifimage/avif
0x1420svgimage/svg+xml
0x2032mvtapplication/vnd.mapbox-vector-tile
0x2133geojsonapplication/geo+json
0x2234topojsonapplication/topo+json
0x2335jsonapplication/json
0x2436mltapplication/vnd.maplibre-tile
  • Values not listed above are reserved, see General Guidelines.
  • 0x20 (MVT) was named pbf with the MIME type application/x-protobuf in earlier versions of this specification. The value itself is unchanged. Implementations should accept pbf as an alias for mvt.
  • 0x24 (MLT): MapLibre has not registered a media type for MLT yet. application/vnd.maplibre-tile is the type used by MapLibre tools and may change if an official type is registered. Some tools use the older application/vnd.maplibre-vector-tile.
  • An MLT tile may contain layers of different MLT format versions. The tile_format value does not distinguish between them; readers must handle MLT versioning as defined by the MLT specification.

3.1.2. Value precompression ​

Metadata and all Tile Blobs are pre-compressed with:

ValueMethod
0Uncompressed
1gzip
2Brotli
3Zstandard
  • Values not listed above are reserved, see General Guidelines.
  • The precompression value is independent of the tile_format. This includes formats with internal compression such as MLT, where uncompressed storage (0) is valid but an additional precompression usually still reduces the size.
  • This flag applies only to the Metadata and the Tile Blobs. The Tile Index and the Block Index are always Brotli compressed, regardless of this value.

3.2. Metadata Chunk ​

  • Content: Encapsulates tiles.json, detailing tileset metadata, as defined by TileJSON 3.0 and the VersaTiles Extended TileJSON specification.
  • Encoding: UTF-8.
  • Compression: Defined by the precompression flag in the File Header.
  • Vector tiles: For the vector tile formats mvt and mlt, tiles.json should contain vector_layers describing the layers of the tiles.
  • Note: The absence of Metadata is indicated by zero offsets and lengths in the File Header.

3.3. Blocks ​

  • Structure: Blocks act as aggregators for up to 256×256 tiles.
  • Zoom Levels: Individual Blocks can span entire zoom levels (0-8). Higher zoom levels (>8) may require multiple Blocks.
  • Maximum number of Blocks per zoom level: pow(4, max(0, level - 8)).
Blocks per level
Level Blocks
  • Each Block contains concatenated Tile Blobs and ends with a Tile Index.
  • Neither the Tile Blobs in a Block nor the Blocks in the file need to follow any particular order.

3.3.1. Tile Blobs ​

  • Tile Blobs are concatenated binary data, each containing one tile. All tiles have the same format and the same precompression.
  • Format: Each Tile Blob has the same file format, determined by the tile_format code in the File Header.
  • Compression: Each Tile Blob is compressed according to the precompression flag in the File Header.

3.3.2. Tile Index ​

  • Compression: Brotli, regardless of the precompression flag.
  • Purpose: Maps the coordinates of tiles within a block to their respective binary position and length.
  • Position: The Tile Index directly follows the Tile Blobs, i.e. it starts at the offset of the Block plus the length of the Tile Blobs (both specified in Block Index).
  • Entries: After decompression, the Tile Index contains exactly (col_max - col_min + 1) * (row_max - row_min + 1) entries of 12 bytes each.
  • Tiles are ordered horizontally, then vertically
  • index = (row - row_min) * (col_max - col_min + 1) + (col - col_min)
  • (col_min, row_min, col_max, row_max are specified in Block Index)
  • Identical Tile Blobs can be stored once and referenced multiple times to save storage space.
  • If a tile does not exist, the length of the Tile Blob is 0. Writers should set its offset to 0 as well; readers must ignore the offset of entries with length 0.
  • The offsets of Tile Blobs are relative to the beginning of the Block. Since the Tile Blobs start at the beginning of the Block, the smallest offset should always be 0, regardless of the order of the entries in the Tile Index.
OffsetLengthTypeDescription
12*i8u64offset of Tile Blob in Block
12*i+84u32length of Tile Blob
index of Tile Blobs
Block Tiles

3.4. Block Index ​

  • Compression: Brotli, regardless of the precompression flag.
  • Function: Provides a directory for locating Blocks within the container file.
  • Empty Blocks are not stored.
  • Each Block, identified by level, column and row, must appear at most once in the Block Index. Readers should reject a Block Index containing duplicate entries.
  • Each 33-byte entry within the Block Index is structured as follows:
OffsetLengthTypeDescription
0 + 33*i1u8level
1 + 33*i4u32column/256
5 + 33*i4u32row/256
9 + 33*i1u8col_min (0..255)
10 + 33*i1u8row_min (0..255)
11 + 33*i1u8col_max (0..255)
12 + 33*i1u8row_max (0..255)
13 + 33*i8u64offset of Block in file
21 + 33*i8u64length of Tile Blobs
29 + 33*i4u32length of Tile Index
  • col_min must be less than or equal to col_max, and row_min must be less than or equal to row_max. Readers must reject a Block Index entry violating this.
  • Since a Block consists only of Tile Blobs appended by a Tile Index, the length of Block must be the sum of the lengths of the Tile Blobs and the Tile Index.
  • Note: To efficiently find the Block containing the tile you are looking for, use a data structure such as a "map", "dictionary" or "associative array" and fill it with the data from the Block Index.

4. Glossary ​

  • Blob: A chunk of binary data. Object storage on Wikipedia
  • Block: A composite unit containing up to 256×256 tiles.
  • Brotli: A compression algorithm known for its efficiency and performance. It provides better compression than gzip. Brotli on Wikipedia
  • gzip: A widely supported compression algorithm based on DEFLATE. gzip on Wikipedia
  • MLT: MapLibre Tile, a column-oriented vector tile format developed by MapLibre. MapLibre Tile Specification
  • MVT: Mapbox Vector Tile, a Protocol Buffers based vector tile format. Formerly referred to as pbf in this specification. Mapbox Vector Tile Specification
  • Tile: A square geographic area at a given zoom level containing map information as an image or as vector data.
  • TileJSON: A JSON format describing a tileset, e.g. its zoom levels, bounding box, attribution and vector layers. TileJSON 3.0
  • XYZ: A tiling scheme that addresses tiles by zoom level z, column x and row y, with the origin at the top left (northwest) corner. Tiled web map on Wikipedia
  • Zstandard: A compression algorithm, commonly abbreviated as zstd, that reaches compression ratios comparable to Brotli at significantly higher compression and decompression speeds. Zstandard on Wikipedia

Released under Unlicense