# tilemaker: Building Vector Tiles Directly from OpenStreetMap

> tilemaker converts an `.osm.pbf` extract into Mapbox Vector Tiles, `.mbtiles`, or `.pmtiles` without requiring a separately operated database. It suits engineers and map producers that need local control over layer selection, zoom levels, and OSM tag processing.

**systemed/tilemaker** — Make OpenStreetMap vector tiles without the stack

- Repository: https://github.com/systemed/tilemaker
- Website: https://tilemaker.org/
- Stars: 1,912 · Forks: 285
- Language: C++
- License: NOASSERTION
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/systemed-tilemaker

## Why tilmaker avoids a conventional tile database

tilemaker addresses a specific operational problem: converting OpenStreetMap data into vector tiles without installing and maintaining a separate database service. Its target users include engineers who produce their own map data, organizations that do not want a third-party tile contract, and map builders creating tiles for offline use. The README says the project is “stack-free” because it provides one executable and requires no database.

The input is an `.osm.pbf` planet extract, such as a regional snapshot downloaded from Geofabrik. The output follows the Mapbox Vector Tile format and can be written as individual tile files, packed into `.mbtiles`, or stored in `.pmtiles`. This format is intended for browser and application renderers and can also support server-side raster rendering. Its practical advantage for these use cases is that styling changes and interactive map behavior can be handled by the renderer rather than encoded as a fixed set of pre-rendered raster images.

tilemaker is aimed at batch production rather than a continuously updated hosted service. The documentation explicitly advises against choosing it if you want someone else to create and host the tiles or if you need continuous updates from the latest OSM data. That boundary matters because regenerating tiles, distributing new extracts, and operating an update pipeline remain outside the basic conversion command.

## The JSON and Lua path from OSM tags to tile layers

Tile generation is controlled by two files. A JSON configuration lists thematic layers and the zoom levels at which those layers apply. A Lua program examines tags on each processed OSM node and way and determines where those features belong. This separates tile structure from feature interpretation: JSON declares the intended layers and zoom coverage, while Lua implements tag-based decisions.

The runtime uses `--config` to select the JSON file and `--process` to select the Lua program. If neither option is specified, it looks for `config.json` and `process.lua` in the current directory. If those files are absent, the command ends with an error. That default behavior makes the program predictable for repeatable builds, but it also means a container invocation must mount the configuration in the working directory or pass explicit paths.

The repository includes configuration compatible with the OpenMapTiles schema, plus `config.json` and `process.lua` at the top level. The `resources/` directory also contains configuration examples. According to the README, advanced users should inspect `docs/CONFIGURATION.md` for layer definitions and `docs/RUNNING.md` for runtime options. The repository layout suggests that tile logic is kept outside the C++ core, allowing schema and tag decisions to change without rewriting the converter.

This design is more flexible than accepting only a fixed geographic schema, but it also makes configuration quality part of the output. The converter can read OSM tags correctly while still producing the wrong map if the Lua rules, layer assignments, or zoom ranges do not match the intended cartography.

## Running the first Monaco tile build with Docker

The README offers a Docker route for a first real use. It starts by obtaining `monaco-latest.osm.pbf` from Geofabrik, then mounts the current directory at `/data`. This avoids compiling the C++ project and its native dependencies first. The following command uses the default configuration and writes a PMTiles archive:

```bash
docker run -it --rm --pull always -v $(pwd):/data \
  ghcr.io/systemed/tilemaker:master \
  /data/monaco-latest.osm.pbf \
  --output /data/monaco-latest.pmtiles
```

The input path must match the location of the downloaded file inside the mounted directory. On completion, the expected output named by the command is `monaco-latest.pmtiles` in that same host directory. The README links to the PMTiles debug viewer for checking the generated tiles.

The `:master` image tag follows the repository's current default branch and should not be treated as a pinned release. The README also shows a multi-line variant of this command. Its explicit `--pull always` requests the latest available matching image before each run, which favors current branch content over build reproducibility. Teams planning repeated production builds should separately decide which released tag or build they intend to control; the README does not provide a command for pinning that selection here.

This first run is a real conversion exercise because it takes an OSM extract through tile generation and leaves an inspectable archive. It does not require coastline or landcover inputs, which are presented as optional examples.

## Compiling tilemaker and serving local MBTiles output

For a source build, tilemaker is written in C++14. Its chief dependencies are Boost, with version 1.66 or later advised to be the latest available, Lua 5.1 or later or LuaJIT, sqlite3, shapelib, and rapidjson. The `Makefile` detects an installed Lua executable, including LuaJIT and several versioned Lua names, before building. Platform-specific guidance is available in `docs/INSTALL.md`.

Once the dependencies are present, the documented build and installation sequence is:

```bash
make
sudo make install
```

The README notes a build-system limitation: the Makefile does not currently detect changes to header files. After modifying a `.h` file, a rebuild may require:

```bash
make clean
```

That detail matters for contributors, but it is also useful to maintainers of private C++ builds because a normal `make` invocation can give stale results after header changes.

A basic MBTiles conversion uses the installed executable with an OSM input and output path:

```bash
tilemaker /path/to/your/input.osm.pbf /path/to/your/output.mbtiles
```

tilemaker keeps working data in RAM by default. For a large region, the documented option directs temporary storage to an SSD path:

```bash
tilemaker /path/to/your/input.osm.pbf /path/to/your/output.mbtiles --store /path/to/your/ssd
```

The README does not state memory estimates or processing times, so the correct capacity must be established against the intended extract. The bundled demonstration server can then be started from the repository's `server` directory:

```bash
cd server
tilemaker-server /path/to/your/output.mbtiles
```

According to the README, the map is then available at `http://localhost:8080/`.

## Coastline, landcover, and container path constraints

Coastline and landcover support is optional and requires separate downloads. The README gives two scripts for obtaining the data:

```bash
./get-coastline.sh
./get-landcover.sh
```

It estimates that around 2GB of disk space is needed. The repository's `resources/` directory contains a coastline and landcover example. These inputs support features such as sea tiles and small-scale landcover rather than the core conversion of OSM nodes and ways.

The Docker documentation exposes a path constraint that is easy to miss. A custom configuration can use absolute paths such as `/data/coastline/water_polygons.shp`, or the container can set its workdir to `/data` so relative paths resolve against the mounted directory. The documented custom run combines these choices:

```bash
docker run -it --rm --pull always -v $(pwd):/data -w /data \
  ghcr.io/systemed/tilemaker:master \
  /data/monaco-latest.osm.pbf \
  --output /data/monaco-latest.pmtiles \
  --config /data/config-coastline.json \
  --process /data/process-coastline.lua
```

The mount exposes files to the container, but path names still need to match the container's filesystem. Relative references that work in a local checkout can therefore fail when configuration is mounted but the working directory is wrong. This is a configuration and packaging concern rather than a tile algorithm limitation.

## Trade-offs against managed and database-backed tile production

The clearest documented alternative is a managed tile provider. tilemaker's README positions its own approach around self-generation, avoiding a third-party contract, and avoiding the need to host or maintain a database. A managed provider reverses that operating model: another party creates and hosts the tiles. That can remove responsibility for conversion and delivery, but it also means tile production is not controlled locally. The README does not document pricing, update frequency, schema behavior, or export terms for such a provider, so this comparison is limited to the operational boundary stated by the project.

A second choice is to retain a database-backed tile pipeline. Based on tilemaker's documented architecture, its distinction is not merely the output format. It processes the `.osm.pbf` input with C++ and Lua logic without requiring a separately maintained database service. A conventional pipeline that keeps OSM data in a database introduces database provisioning and administration into the toolchain. tilemaker instead emphasizes a single executable, in-memory processing by default, and optional SSD temporary storage.

That simplification is attractive for controlled batch builds, but it does not turn tilemaker into a continuously synchronized map platform. The project expressly excludes the need for continuous updates from its target use cases. Operators must still schedule extract downloads, regenerate tiles when data changes, store outputs, and arrange delivery to clients.

## Release, maintenance, and licensing costs for tilemaker users

The repository is not archived, and its last push was on 2026-09-04. Recent releases listed for the project include `v3.2.0` on 2026-08-29, `v3.1.0` on 2026-03-18, and `v3.0.0` on 2024-01-15. Those dates show that versioned releases exist, although the README's use of `ghcr.io/systemed/tilemaker:master` introduces a separate choice between following the branch and controlling the deployed version.

The source build carries native library requirements and includes third-party code under `include/`. The README identifies C++14, Boost, Lua or LuaJIT, sqlite3, shapelib, and rapidjson as chief dependencies. Docker avoids direct installation but shifts attention to image tags and mounted configuration files. Header changes may also require `make clean`, which adds a small but explicit contributor and private-build maintenance step.

The project's code is licensed as FTWPL. The README states that contributors permit use of the code and provide no warranty. It also lists separate licenses for bundled libraries, including Boost Software Licence for kaguya, MIT for libdeflate and minunit, BSD 2-clause for libpopcnt and protozero, BSD 3-clause for pmtiles, and ISC for polylabel. Repository naming differs between the `LICENCE.txt` entry and the README reference to a LICENSE file, so license review should start with `LICENCE.txt` and account for every third-party component used in a distribution. This is a licensing inventory task, not legal advice.

## Conclusion

tilemaker is appropriate for engineers, map maintainers, and offline-data producers who want to control layer rules and generate tiles without hosting a database. It is a poor fit for users who need a third party to operate the tiles or require a continuously updated OSM service. Before adopting it, verify that your target renderers accept the selected vector tile output, confirm that the JSON and Lua configuration represents the required layers, and estimate memory or SSD requirements for the region. For a minimal first production check, run the documented Docker command on `monaco-latest.osm.pbf` and inspect the resulting `.pmtiles` file in the PMTiles viewer.

## FAQ

### How do I install tilemaker and create my first vector tiles?

The quickest documented path is the `ghcr.io/systemed/tilemaker:master` Docker image with a Geofabrik `.osm.pbf` extract and an `--output` path. A source installation uses `make` followed by `sudo make install`, after installing the listed C++ dependencies.

### What output formats can tilemaker produce?

tilemaker can write Mapbox Vector Tiles as individual files, `.mbtiles`, or `.pmtiles`. The output format is selected through the generation setup, with the README examples producing `.pmtiles` and `.mbtiles` files.

### Does tilemaker require a database?

No. Its stated design goal is database-free operation with one executable, and the README keeps working data in RAM by default. For large areas, `--store` can direct temporary data to an SSD path.

## Sources

- [Issues](https://github.com/systemed/tilemaker/issues)
- [Project website](https://tilemaker.org/)
- [README](https://github.com/systemed/tilemaker/blob/master/README.md)
- [Releases](https://github.com/systemed/tilemaker/releases)
- [systemed/tilemaker on GitHub](https://github.com/systemed/tilemaker)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/systemed-tilemaker
