Back to the blog

Generating data for a map server (vector tiles)

Setting up a map server takes several technical steps: getting the geographic data, turning it into vector tiles, then serving them through a dedicated server.

This article explains how to build an infrastructure that generates and serves maps from OpenStreetMap (OSM) data.

We will cover:

  1. the data sources

  2. extracting an area

  3. generating vector tiles

  4. optimizing the data

  5. deploying a tile server

 

Pipeline overview

Generating a vector map usually follows this pipeline:

OpenStreetMap (PBF) => osmium (extraction / cleanup) => tilemaker / planetiler => MBTiles / PMTiles => TileServer / Martin => Client (MapLibre / Mapbox GL)

Each step transforms the data to make it more compact, faster to load and suited to web display.

 

Plan your own route

MapPlanner helps you calculate distances, elevation, duration and plan your hikes, runs and bike rides on an interactive map.

  • Automatic distance & elevation calculation
  • Topographic, satellite maps
  • GPX/KML export for your GPS
  • Real-time GPS tracking

1. Mapping tools and resources

Before starting, it helps to know the main data resources and tools of the mapping ecosystem.

General tools

A few useful resources:

Handy tools to work with the data:

These tools let you, for example:

  • select a precise geographic area

  • fetch only some OSM objects

  • prepare the data before transforming it.

 

2. Geographic data sources

A map is built from several kinds of data:

  • vector data (roads, buildings, POIs)

  • topographic data (relief, glaciers)

  • simplified global data (continents, oceans)

 

Topographic data

This data enriches the map with natural features:

  • relief

  • oceans

  • glaciers

  • urban areas

Sources:

 

OpenStreetMap data

OSM data is distributed in the PBF (Protocolbuffer Binary Format) format.

This format is compact and optimized for processing.

World

Europe / regions

 

3. Downloading and extracting the data

Full OSM files can be extremely large.

For example:

  • whole planet: more than 80 GB in PBF format

  • Europe: several tens of GB

It is therefore often better to work on a sub-area.

 

Installing osmium

Osmium is a fast tool for handling PBF files.

Installation:

sudo apt-get install osmium-tool

 

Extracting a geographic area

The following command extracts a specific region from a larger file.

osmium extract --bbox=2.68,50.72,7.55,54.12 --set-bounds --strategy=smart europe-latest.osm.pbf --output netherlands.osm.pbf

Explanation:

  • --bbox sets the geographic area

  • --set-bounds writes the bounds into the file

  • --strategy=smart optimizes the extraction

 

4. Converting to vector tiles

OSM data is vector data, but it cannot be used directly for web map rendering.

It has to be converted to the Mapbox Vector Tiles (MVT) format.

This conversion:

  • cuts the data into tiles

  • simplifies the geometries

  • improves client-side performance.

The tool used here is Tilemaker.

 

5. Installing Tilemaker

Install the required dependencies:

sudo apt install libboost-dev libboost-filesystem-dev libboost-iostreams-dev libboost-program-options-dev libboost-system-dev shapelib lua5.4 liblua5.4-dev libprotobuf-dev libshp-dev libsqlite3-dev protobuf-compiler rapidjson-dev

Clone the project:

git clone https://github.com/systemed/tilemaker.git
cd tilemaker

Build:

make
sudo make install

 

6. Configuring Tilemaker

Tilemaker works with two main files:

JSON file

It describes:

  • the layers

  • the zoom levels

  • the data sources

resources/config-openmaptiles.json

Lua file

The Lua file defines how OSM objects are turned into map layers.

resources/process-openmaptiles.lua

For example, this file decides:

  • which roads are displayed

  • which buildings are included

  • which POIs appear.

Documentation:

https://github.com/systemed/tilemaker/blob/master/docs/CONFIGURATION.md

 

7. Extra data for Tilemaker

Some data has to be added to improve the visual quality of the maps.

 

Coastlines and land cover

Run the scripts:

./get-coastline.sh
./get-landcover.sh

These scripts download:

  • coastlines

  • oceans

  • some simplified natural areas.

 

Handling cliffs

Tilemaker handles cliffs as polygons.

In OSM, however, they are usually mapped as lines.

They therefore have to be extracted separately.

Installing Osmosis:

https://wiki.openstreetmap.org/wiki/Osmosis/Installation

Extraction:

./bin/osmosis --rbf europe-latest.osm.pbf --way-key-value keyValueList=natural.cliff --wb europe_cliffs.osm.pbf

Conversion to a shapefile:

sudo apt-get install gdal-bin
ogr2ogr -lco ENCODING=UTF-8 -f "ESRI Shapefile" europe_cliffs.shp europe_cliffs.osm.pbf lines

Then copy the generated files (.shp, .shx, .dbf, .prj) into tilemaker’s landcover/ directory, the one referenced by the configuration below.

Then add the layer to the configuration:

"cliff": { "minzoom": 8, "maxzoom": 14, "source": "landcover/europe_cliffs.shp" },

 

8. Optimizing the PBF file

Before generating the tiles, optimizing the data is recommended.

osmium cat -f pbf your-file.osm.pbf -o optimized.osm.pbf

This operation:

  • reorganizes the data

  • speeds up processing.

Typical usage:

  • 2 GB of RAM

  • about 14 minutes

 

9. Generating the vector tiles

The tiles are generated with Tilemaker.

./tilemaker FILE.osm.pbf --output FILE.mbtiles --config resources/config-map-planner.json --process resources/process-map-planner.lua

Result:

  • an MBTiles file

  • holding all the vector tiles.

 

10. Generation performance

Performance depends on the area processed.

Examples:

Area Time RAM
Europe 30 min 40 GB
North America 24 min 40 GB
World 1 h 20 60 GB

Recommended disk space: ≈600 GB

 

Options to reduce RAM usage

Tilemaker offers several options:

  • --store

  • --shard-stores

  • --compact

To use --compact, the data has to be renumbered:

osmium renumber -o optimized-renumbered.osm.pbf optimized.osm.pbf

 

11. Alternative: Planetiler

Planetiler is a modern alternative to Tilemaker.

Installation:

sudo apt install default-jre default-jdk

Generation:

java -Xmx136g -jar planetiler.jar --config=config.properties

Example:

https://onthegomap.github.io/planetiler-demo/#9.09/46.122/6.155

 

12. Alternative: OpenMapTiles

OpenMapTiles provides a complete Docker environment.

Clone the project:

git clone https://github.com/openmaptiles/openmaptiles.git
cd openmaptiles/
nano .env

Edit:

PGPORT=5432
...
MAX_ZOOM=14

Generation:

./quickstart.sh france

 

13. Optimizing client-side rendering

Rendering happens in the browser.

Rendering time depends mainly on:

render time = constant time
            + [ number of sources * per source time ]
            + [ number of layers * per layer time ]
            + [ number of vertices * per vertex time ]

Possible optimizations:

  • fewer layers

  • fewer sources

  • fewer POIs

  • drop unneeded IDs

  • limit filter computations.

 

14. Installing the tile server

The server used is TileServer GL.

Create the structure:

mkdir tileserver
cd tileserver
mkdir data fonts glyphs sprites styles

Layout:

  • data → mbtiles files

  • fonts → fonts

  • styles → Mapbox styles

 

15. Configuring the server

Create config.json:

{
  "options": {
    "paths": {
      "root": "",
      "fonts": "fonts",
      "sprites": "sprites",
      "styles": "styles",
      "mbtiles": "data"
    },
    "domains": [
      "maps.map-planner.com",
      "maps-a.map-planner.com",
      "maps-b.map-planner.com"
    ],
    "frontPage": true,
    "formatQuality": {
      "jpeg": 80,
      "webp": 90
    },
    "maxScaleFactor": 3,
    "maxSize": 2048,
    "pbfAlias": "pbf",
    "serveAllFonts": false,
    "serveAllStyles": false,
    "serveStaticMaps": true,
    "tileMargin": 0
  },
  "styles": {
    "map-planner": {
      "style": "map-planner/style.json"
    }
  },
  "data": {
    "world": {
      "mbtiles": "world.mbtiles"
    },
    "natural_earth_relief": {
      "mbtiles": "natural_earth_relief.mbtiles"
    }
  }
}

The styles are then declared in the full configuration.

 

16. Starting the server

With Docker:

sudo docker pull maptiler/tileserver-gl
sudo docker run -it -v $(pwd):/data -p 5010:8080 maptiler/tileserver-gl -c config.json

NPM alternative:

npm install tileserver-gl-light

 

17. Running it as a systemd service

Create a service:

sudo nano /etc/systemd/system/tileserver.service

Start it:

sudo systemctl daemon-reload
sudo systemctl enable tileserver.service
sudo systemctl start tileserver.service
sudo systemctl status tileserver.service

 

18. MBTiles vs PMTiles

Comparison:

Format Characteristics
MBTiles local SQLite database
PMTiles single file optimized for HTTP, lighter (15–25%)

Conversion

./pmtiles convert natural_earth_relief.mbtiles natural_earth_relief.pmtiles

 

19. Alternative server: Martin

Martin is a modern vector tile server written in Rust.

Documentation:

https://maplibre.org/martin/

 

20. Using it with MapLibre

Install PMTiles:

yarn add pmtiles

Register the protocol:

import { addProtocol } from 'maplibre-gl';
import { Protocol as PMTilesProtocol } from 'pmtiles';

const protocol = new PMTilesProtocol();
addProtocol('pmtiles', protocol.tile);

Related articles

What our Explorer users say

⭐⭐⭐⭐⭐

I planned a 5-mile running loop around my neighborhood in minutes. The distance and pace estimate were spot on for my morning run before work.

Sarah K. New runner
⭐⭐⭐⭐⭐

With the isochrone mode, I plan my hikes in no time! I instantly see how far I can go with my available time. GPS tracking keeps me on trail in the Rockies.

Jessica W. Passionate hiker
⭐⭐⭐⭐⭐

We prepared a 25-mile cycling loop with friends and exported the GPX track. Everyone followed the same route on their Garmin without getting lost. Perfect organization!

Mike R. Weekend cyclist
⭐⭐⭐⭐⭐

Before a hike in Shenandoah, I checked the elevation and duration. The route followed real trails, which saved me from unpleasant surprises. Very reliable!

Emily L. Beginner hiker
⭐⭐⭐⭐⭐

I wanted an easy walk for my kids. I set a short max distance and MapPlanner helped me create the perfect loop. We had a wonderful family afternoon.

David N. Family outing
⭐⭐⭐⭐⭐

I love planning my outings in advance. I saved several routes for the weekends. It saves me so much time compared to figuring it out on the go.

Karen G. Occasional hiker
⭐⭐⭐⭐⭐

By exploring the routes around my area, I discovered great trails I didn’t know about. MapPlanner opened new places for me to explore right in my backyard.

Chris P. Trail discovery
⭐⭐⭐⭐⭐

I keep track of my progress with the history feature. Comparing my running pace and distance over the months keeps me motivated and accountable.

Ashley T. Performance tracking
⭐⭐⭐⭐⭐

For our MTB group ride, we created the route and sent the GPX to everyone. Nobody got separated — the whole group stayed together from start to finish.

Brian B. Club activity
⭐⭐⭐⭐⭐

I love taking photos while hiking. MapPlanner automatically places my pictures on the map. It’s awesome to review the route and share it with friends.

Lauren F. Discovery outing
⭐⭐⭐⭐⭐

Depending on the activity, I switch the map style: topo for the mountains, street for the city, satellite to scout terrain. It makes route planning super intuitive.

Tyler S. Experienced hiker
⭐⭐⭐⭐⭐

MapPlanner now estimates my times based on my own pace. I know exactly how long my next run will take. Perfect for squeezing in a workout on a tight schedule.

Rachel J. Aspiring runner

Popular routes

Discover the most popular routes near you

Miles at the Meadow - 5k / 10K (2 loops)
pete.augrom
Running
Very easy

Miles at the Meadow - 5k / 10K (2 loops)

3.095mi
•
33m
•
5.63mph
Virginia - The Plains
Fusion Invitational High School 5K Course
nm8zkrv8hk
Running
Easy

Fusion Invitational High School 5K Course

3.201mi
•
34m
•
5.65mph
Colorado - Commerce City
ada
rajan
Running
Strenuous

ada

11.669mi
•
4h10m
•
2.8mph
New York - New York
Route 2 - Prayer Walk Connecting Churches (Ferguson)
SR St. Louis
Walk
Very easy

Route 2 - Prayer Walk Connecting Churches (Ferguson)

1.441mi
•
31m
Missouri - Ferguson
2026 HHHH 25mi Route
buschlive
Bike
Moderate

2026 HHHH 25mi Route

24.79mi
•
2h30m
•
9.92mph
Texas - Hutchins
Central park
Fibula
Running
Moderate

Central park

6.393mi
•
1h
•
6.39mph
New York - New York
Miles at the Meadow - 1 mile
pete.augrom
Running
Very easy

Miles at the Meadow - 1 mile

1.012mi
•
11m
•
5.52mph
Virginia - The Plains
Chincoteague National Wildlife Refuge
Gaynor
Bike
Very easy

Chincoteague National Wildlife Refuge

9.532mi
•
2h
•
4.77mph
Virginia - Chincoteague Island