Grabbing and Chopping Vector Tiles

This morning I noticed a tweet indicating OSM2VectorTiles is no longer maintained and that users should switch to OpenMapTiles.

I’ve been looking forward to this ever since the world’s most polite saber rattling from Mapbox over the data schema used by OSM2VectorTiles. I had some design work I wanted to do, but I was holding out for this and Maputnik, the styling tool from Lukas Martinelli I contributed an embarrassingly small amount to on Kickstarter. They are both here now, and if you haven’t tried it, Maputnik is really good.

This also makes for a good opportunity for a couple of blog posts on dealing with vector tiles. In this one we’ll look at how I grab and chop up vector tiles for Mecklenburg’s use.

There are two truisms for downloadable tile sources on the web:

For the area around Mecklenburg County, there are basically two options: the City of Charlotte, which isn’t big enough, and the whole US, which is too big. Here’s how I handle that.

First, I grab the US. That’s easy enough.


6GB and whatever your bandwidth is later, you’ve got the whole US. I could use that for Mecklenburg’s stuff, but that’s a lot of space on my 20GB Digital Ocean droplet. We’re going to chop that up using tilelive and mbtiles. If you haven’t installed those before:

npm install -g tilelive mbtiles

Then it’s a matter of picking your extent.


I’m going quite a ways out with this (further still than shown here - north into Virginia and South past Columbia SC), but you never know when some yahoo is going to fullscreen on their 4k monitor.

To chop the United States tiles down to size, I run my desired extent through tilelive-copy.

tilelive-copy --bounds="-83.285,33.180,-78.255,37.384" united_states_of_america.mbtiles chopped.mbtiles

This gets us from 6GB to 292MB with much more extent clearance than I will ever need, and it takes <10 seconds on my desktop. My tiny Digital Ocean droplet says thank you. Easy enough to script and schedule.

On the MapBox GL JS end of things, you can use the same extent so users don’t run off the edge of the world.

let mapOptions = {
maxBounds: [[-83.285, 33.180],[-78.255, 37.384]]

I know what you’re saying: that’s great for OpenStreetMap data, but my data is much better, and no amount of empirical evidence will convince me otherwise! I hear you. In my next post we’ll look at making our own vector tiles with tippicanoe. I’m also doing a talk on vector tiles at the NC GIS Conference in February if you find yourself stranded in Raleigh with nothing to do.