Tilezen vector datasource: OpenStreetMap turned into styled vector tiles
Tilezen vector tile service - OpenStreetMap data in several formats
At a glance
- What is it?
- The tilezen/vector-datasource repository is the pipeline behind the Nextzen vector tile service, clipping OpenStreetMap geometry to tile bounds, simplifying it by zoom level and serving it as Mapbox Vector Tile, TopoJSON or GeoJSON. It suits a team that wants its own basemap tiles, and the pinned Python 2 era dependencies are the first thing to look at.
- Who is it for?
- Tilezen vector datasource is worth reading if you want to run your own basemap tile service, because it is a complete pipeline rather than a snippet, covering the osm2pgsql import, the clipping and simplification, the layer definitions, the format encoders and the tile server, and because the layer configuration and the tile JSON are data files you can edit rather than code. It is the wrong tool if you want a hosted API and you do not need to run it yourself.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the service is, and what a vector tile actually is
The Nextzen vector tile service provides worldwide basemap coverage sourced from OpenStreetMap and other open data projects, updated roughly quarterly, and the repository is the implementation behind it.
The readme explains vector tiles in a way that is worth reading even if you already know the format. Vector tiles are square-shaped collections of geographic data that contain the map feature geometry, such as lines and points, and the information about how map features are drawn is maintained in a separate stylesheet file.
That separation is the whole argument for the format. A raster tile is an image that already has the visual appearance of the map features pre-drawn, so changing the colour of a building or hiding a class of road means going back to the server for a different set of tiles. With vector tiles there is no need to head back to the server and fetch a different set of tiles if you want to filter the output or change the style of a road or the colour of a building.
The second consequence is real-time rendering. Vector tiles make real-time rendering possible by sending the underlying data geometry and tags directly to the client, whether that is a browser or a native mobile app. Buildings and roads can be rendered in different ways, or not at all, when the vector tile is downloaded, and the changes happen instantly on the client's side.
The rendering itself is left to the client, and the documentation is explicit that how to draw the tile in a browser is up to the vector-friendly visualization tool, such as SVG, Canvas or WebGL, with the Tangram rendering engine, which uses WebGL, given as one way to draw the service in 2D and 3D maps.
The service is hosted at tile.nextzen.org with a developer API key, and the licence field for the repository is one that GitHub cannot classify, with the terms in the LICENSE file.
The URL contract, and the three formats you can ask for
The tile URL is a template with six parts, and it is worth taking apart because it tells you what the service can do.
The pattern is:
https://tile.nextzen.org/tilezen/vector/v1/{tilesize}/{layers}/{z}/{x}/{y}.{format}?api_key=your-nextzen-api-keyThe tilesize is the pixel size of the tile, the layers segment selects what to return, then the zoom level and the tile coordinates, then the format extension, then the key.
The documentation gives two worked examples. A sample tile in MVT format at 512 size is `https://tile.nextzen.org/tilezen/vector/v1/512/all/16/19293/24641.mvt?api_key=your-nextzen-api-key`, and a sample tile in TopoJSON format at 256 size is the same tile with the .topojson extension and a 256 tile size.
The three formats are the choice that matters, and the documentation recommends differently depending on what you are building. Mapbox Vector Tile uses the .mvt extension and is a compact format using protocol buffers, used for raster tile rendering in TileMill2 and for vector rendering in MapboxGL. TopoJSON uses the .topojson extension and is an optimized form of GeoJSON that saves space by encoding topology and reducing replication of shared geometry. GeoJSON uses the .json extension and is easy to get started with, human-readable, and compatible with many tools.
The recommendation is TopoJSON for desktop web development and MVT for native mobile development, and the reason given is a size one. The Nextzen vector tile service gzips tiles automatically, so the TopoJSON file format is comparable in file size to MVT over the wire, and it is much friendlier to debug.
That is a useful piece of advice precisely because it is counterintuitive. TopoJSON on disk is much larger than the binary MVT, because it is text and because it carries the whole geometry of a shared feature once, and the gzipped comparison is what makes the text format viable. For a development workflow, being able to open a tile in a text editor and read it is worth a few kilobytes.
The layers segment is also flexible. Depending on the URL syntax, the tiles can return all of the map data, or just individual layers, or combinations of layers, including water, earth, landuse, roads, buildings and points of interest, although the documentation recommends the default all layer for custom work.
How the tiles are produced, and why the pipeline is interesting
The production pipeline is three steps, and each one is a decision that affects what a consumer sees.
Vector tiles are served by clipping geometries to the tile bounding box, and then simplified to match the zoom level to avoid unnecessary complexity at lower zoom levels. These geometries and features are also further processed to facilitate styling.
The clipping is the obvious necessity, since a tile has to contain only what falls inside its bounds. The simplification is the interesting one, because it is a lossy operation whose parameters are chosen for the zoom level, and a road that is simplified at zoom 10 is a different polyline from the same road at zoom 16. The styling processing is the third step, and it is where the layer definitions come in.
The benefit of the vector approach shows up in the update path. When changes are made to OpenStreetMap or another data source, rather than waiting for an image tile to be redrawn, only the geometry coordinates and feature attributes for that particular building or road need to be updated in the vector tile.
That is the difference in cost between the two models. A raster pipeline re-renders every tile that touches a changed feature and then re-encodes the images, while a vector pipeline updates the attributes and coordinates of the affected feature. For a service covering the world and refreshed quarterly, that difference is the reason a vector service is affordable at all.
The stack in the packaging metadata shows what that pipeline is built from. The dependencies are ASTFormatter, mapbox-vector-tile, ModestMaps at 1.3.0 or newer, pycountry, pyshp, simplejson, StreetNames, tilequeue, kdtree and webcolors. The tilequeue, ModestMaps and kdtree packages are the tile server and the spatial index, mapbox-vector-tile is the MVT encoder, pycountry is the country boundary lookup, pyshp handles shapefiles and StreetNames is the street name gazetteer.
The requirements file shows the Python 2 era clearly. It pins AppDirs, argparse, ASTFormatter, boto, edtf, fiona, future, gunicorn, hanzidentifier, hiredis, lxml, mapbox-vector-tile, ModestMaps, protobuf, psycopg2, pyclipper, pycountry, pyshp, python-dateutil, PyYAML, redis, Shapely, simplejson, six, tqdm, urllib3, Werkzeug, wsgiref and zope.dottedname, and three of them are not on PyPI at all but are git references to the project's own forks: raw_tiles from tilezen and tilequeue and tileserver from tilezen.
Three git dependencies in a requirements file is a design decision worth noticing. The upstream projects do not have the features the service needs, so the project maintains its own forks and installs those directly, which means the build is not reproducible from a package index alone and the state of those forks is part of the state of the service.
The repository layout, and the pieces you would change
The tree shows a service rather than a library, and most of the interesting files are configuration.
There is a vectordatasource/ directory holding the package itself, a data/ directory, a queries/ directory, a tilejson/ directory and a yaml/ directory, which is where the configuration lives. There is an osm2pgsql.lua file and an osm2pgsql.style, which are the import configuration for the OpenStreetMap database import, and the style file in particular is where the mapping from OSM tags to layer attributes is written.
There are scripts/ and a spreadsheet/ directory, which together suggest the pipeline is partly data-driven from spreadsheets, which is an unusual and honest arrangement for a tile pipeline: a spreadsheet is a reasonable place for a layer-to-source mapping that changes often and that several people edit.
Then there is the build and packaging material. There is a setup.py that reads the version from a VERSION file rather than carrying it inline, packages with find_packages, and declares the same dependency set as the requirements file. There is a Dockerfile, a requirements.txt, a MANIFEST.in, a config.dev.yaml and a test_config.example.yaml, and a mkdocs.yml with a readthedocs.yml for the documentation site.
The Docker image is the quickest way to see the age of the project, because it is explicit. It is FROM ubuntu:14.04, it installs osm2pgsql and the PostgreSQL client and the Python build dependencies with an apt-add-repository for a tilezen PPA, it copies the source into /usr/src/app, runs pip install -r requirements.txt and then pip install -e ., and the command is scripts/docker_boostrap.sh. The typo in the bootstrap script name is preserved from the original, which is a small indication of how long that name has been there.
The testing material is unusually thorough for a service. There is a TESTS.md describing a suite of tests which can be run against a tile server to verify query results in well known tiles, an integration-test/ directory, a test/ directory, a test-data-osm-template.xsl and a test-data-update-osm.sh for the test fixtures, and a queries.yaml that appears to be the list of test queries. Testing a tile server by checking known tiles is a good approach, because the output is a large binary with many layers and eyeballing it does not scale.
There is also a PERFORMANCE.md, a MIGRATION_GUIDE.md, a SEMANTIC-VERSIONING.md and a CHANGELOG.md, which is a lot of process documentation for a service, and it says something about how the project has been run. The version tags tell the rest: v1.9.0 from 2023-03-10, v1.8.0 from 2019-06-27 and v1.7.0 from 2019-02-16, with the last push to the repository on 2026-10-19.
Running it yourself, and the terms you have to accept
The documentation points at installation instructions for setting up your own version of the service and at the Dockerfile, and there is a whole section of the readme about using the hosted service instead.
The hosted route is straightforward: get a developer API key, and read the two documents that matter before you ship anything. One is about API keys and rate limits, with the instruction not to abuse the shared service. The other is about attribution requirements, with the note that the terms of service for OpenStreetMap and other projects require attribution.
The attribution point is the one that catches teams out. A basemap tile pipeline is a way of redistributing somebody else's geographic database in a form people do not recognise as data, and the OpenStreetMap terms require that the source is credited. The documentation makes it a first-class document rather than a line in the licence, which is the right way to handle it, and it is also a requirement that survives into your own product's user interface.
For running it yourself, the Dockerfile is the quick route and the wiki has the detailed installation instructions. The container installs osm2pgsql, which is the tool that loads OpenStreetMap data into a PostgreSQL database, and the PostgreSQL client, which is what osm2pgsql talks to. The service then needs that database populated, which is the expensive part of running this yourself, and it needs the tile server and the queue running, which the tilequeue and tileserver forks provide.
The credits are worth noting, because they explain the shape of the code. This is based on the work of Michal Migurski and extends his OSM.US-hosted vector tile service with additional data and format support. That is a project from the mid-2010s, and the repository is a descendant of it, which is consistent with the Python 2 dependencies and the ubuntu:14.04 base image, and it explains why the layers and the formats are the ones that were worth having in 2016.
The primary language is Python, and the topic list names basemap, cartography, geojson, map, mapzen, mvt, natural-earth, openstreetmap, plpgsql, tile, topojson, vector-tiles and whosonfirst, which is a good summary of the inputs and the outputs.
Where the Tilezen pipeline is the wrong tool
The first limit is the age of the stack, and it is not a small one. The requirements file pins packages from the Python 2 era, including a setuptools constraint noted as the last version to support py2 and a webcolors pin for the same reason, and the container base is ubuntu:14.04. Running this today means either finding an old runtime, which is a security problem in itself, or porting the codebase, which is a project.
The second is the three git dependencies. raw_tiles, tilequeue and tileserver are installed from the project's own forks rather than from PyPI, so a build depends on the state of those repositories, and the tileserver and tilequeue forks are where the production-specific behaviour lives, which means the parts that matter most are the parts you cannot read in a package index.
The third is that it is a service, not a library. There is nothing to import and call. To get tiles you run a database import, a queue and a server, and to keep them current you re-import and re-render. A team that wants a basemap for a product is far better served by the hosted API, and a team that wants a basemap for a product with its own data is better served by a generator that reads a schema rather than by this pipeline.
The fourth is the licensing inconsistency, which is the kind of thing that stops a legal review. The licence field for the repository is one that GitHub cannot classify, and the packaging metadata in setup.py declares the licence as MIT. Those cannot both be the whole answer, and for a project that redistributes OpenStreetMap-derived data, the upstream data licences matter as much as the code licence, because the code and the tiles are licensed separately.
And the fifth is the quarterly refresh against a service that now updates continuously. The hosted service is described as updated roughly quarterly, which was reasonable when the data pipeline was expensive and is now a real constraint, because a bus route added last week is not in your tiles. Teams that need current data end up maintaining their own overlay, which is another pipeline, and the boundary between what the tiles carry and what your overlay carries is where the attribution and the licence questions get complicated.
Editorial conclusion
Tilezen vector datasource is worth reading if you want to run your own basemap tile service, because it is a complete pipeline rather than a snippet, covering the osm2pgsql import, the clipping and simplification, the layer definitions, the format encoders and the tile server, and because the layer configuration and the tile JSON are data files you can edit rather than code. It is the wrong tool if you want a hosted API and you do not need to run it yourself. Before you build it, check three things: the Python version, because the requirements file pins packages from the Python 2 era, with a setuptools constraint to the last version supporting py2 and webcolors pinned for the same reason, so this is a codebase that needs porting or an old runtime before it runs on a modern machine; that you understand the attribution obligation, because the terms of service for OpenStreetMap and the other data projects require attribution, and that is not a formality when you are shipping a basemap; and that the licence position is settled, because the licence field for the repository is one GitHub cannot classify while the packaging metadata declares the licence as MIT, so check the LICENSE file before you redistribute it.
Frequently asked questions
How do I request a tile from the Nextzen vector tile service?
The URL pattern is https://tile.nextzen.org/tilezen/vector/v1/{tilesize}/{layers}/{z}/{x}/{y}.{format}?api_key=your-nextzen-api-key, so you choose a tile size in pixels, a layer or layer combination, the zoom level and the tile coordinates, and the output format, and you need a developer API key. A worked example is a 512 pixel MVT tile at zoom 16 with the all layer.
Which output formats does the Tilezen vector tile service support?
Three. Mapbox Vector Tile with the .mvt extension, a compact protocol buffer format used for vector rendering in MapboxGL and for raster rendering in TileMill2; TopoJSON with the .topojson extension, an optimized form of GeoJSON that encodes topology; and GeoJSON with the .json extension, which is human-readable and compatible with many tools. The documentation recommends TopoJSON for desktop web development and MVT for native mobile, because the service gzips tiles automatically and so TopoJSON is comparable in size over the wire.
How are the vector tiles produced from OpenStreetMap data?
Geometries are clipped to the tile bounding box, then simplified to match the zoom level to avoid unnecessary complexity at lower zooms, and then processed further to facilitate styling. The vector approach means that when OpenStreetMap changes, only the geometry coordinates and feature attributes for the affected building or road need updating in the tile, rather than an image tile needing to be redrawn.