A dynamic vector tile generation service that converts OGR-compatible geospatial data formats into Mapbox Vector Tiles (MVT) on-the-fly.
CartoKit is a lightweight, cartographer focused vector tile server that enables cartographers and geospatial developers to quickly prototype maps
- Dynamic Tile Generation: Converts GeoPackage, Shapefile, GeoJSON, and other OGR formats to MVT on-the-fly
- Flexible Caching: Optional tile pre-generation and caching using MBTile format
- Three Operating Modes: Serve dynamic tiles, build cache, or serve cached tiles only
- Auto-Generated Styles: Automatic Mapbox GL style generation for quick visualization
- CRS Agnostic: Handles input data in any coordinate system, outputs Web Mercator tiles
- YAML Configuration: Per-tileset customization via manifest files
- REST API: Standard TileJSON and MVT endpoints compatible with MapLibre GL and Mapbox GL
- CORS Enabled: Ready for cross-origin requests from web applications
Ideal for cartographers and geospatial developers who need:
- Quick prototyping of vector tile visualizations
- Local development without external dependencies
- Custom tile generation from proprietary data sources
- Lightweight alternative to commercial tile services
Note: This tool is optimized for development workflows, not production-scale serving.
- FastAPI: Async REST API framework
- Fiona: OGR wrapper for reading geospatial data
- Shapely: Geometric operations and spatial analysis
- Mapbox Vector Tile: Protocol Buffer encoding for MVT
- PyProj: Coordinate reference system transformations
- More Cantile: Web Mercator tile math utilities
- SQLite3: MBTile cache storage
- Rich: Terminal UI with progress bars
pip install ogr_tiller -Ugit clone https://github.com/geoyogesh/ogr_tiller.git
cd ogr_tiller
pip install -e .conda create -n ogr_tiller -y
conda activate ogr_tiller
conda config --env --add channels conda-forge
conda config --env --set channel_priority strict
conda install python=3 fiona mapbox-vector-tile rtree pyproj -y
pip install -e .Place your GeoPackage (.gpkg) files in a data folder:
mkdir -p data
# Add your .gpkg files to the data folderDynamic tile serving with caching:
ogr_tiller --data_folder ./data/ --cache_folder ./cache/ --port 8080Dynamic serving without caching:
ogr_tiller --data_folder ./data/ --cache_folder ./cache/ --port 8080 --disable_caching trueOpen your browser to http://localhost:8080 to see available tilesets and styles.
Use the test viewer at test/test.html or integrate with MapLibre GL:
const map = new maplibregl.Map({
container: 'map',
style: 'http://localhost:8080/styles/system/starter.json',
center: [0, 0],
zoom: 2
});Dynamic tile generation with optional caching for development:
ogr_tiller --data_folder ./data/ --cache_folder ./cache/ --port 8080Options:
--tile_timeout: Timeout for tile generation in seconds (default: 3)--disable_caching: Set totrueto bypass cache and always generate fresh tiles
Pre-generate all tiles for all zoom levels (0-24 or configured range):
ogr_tiller --mode build_cache --data_folder ./data/ --cache_folder ./cache/This recursively generates tiles using a quadtree descent and stores them in MBTile databases.
Serve only pre-generated cached tiles (read-only, production-safe):
ogr_tiller --mode serve_cache --data_folder ./data/ --cache_folder ./cache/ --port 8080Returns 404 for any tiles not in the cache.
Create a manifest.yml in your data folder to customize tile generation:
config:
defaults:
minzoom: 0
maxzoom: 18
extent: 4096
tile_buffer: 64
simplify_tolerance: 1.0
attribution: "© Your Organization"
tilesets:
my_tileset:
minzoom: 5
maxzoom: 16
name: "My Custom Tileset"
attribution: "© Custom Attribution"Parameters:
minzoom/maxzoom: Zoom level range (0-24)extent: Vector tile extent in pixels (default: 4096)tile_buffer: Buffer around tiles for clipping in pixels (default: 64)simplify_tolerance: Geometry simplification factor (default: 1.0)attribution: Data source attribution textname: Human-readable tileset name
Place custom Mapbox GL style JSON files in a stylesheet folder:
ogr_tiller --data_folder ./data/ --cache_folder ./cache/ --stylesheet_folder ./styles/ --port 8080Access custom styles at: http://localhost:8080/styles/user/{stylesheet}.json
GET /- List available styles and tilesets
GET /styles/user/- List user-defined stylesheetsGET /styles/user/{stylesheet}.json- Serve custom Mapbox GL styleGET /styles/system/starter.json- Auto-generated default style
GET /tilesets/{tileset}/info/tile.json- TileJSON metadataGET /tilesets/{tileset}/tiles/{z}/{x}/{y}.mvt- Vector tile (MVT format)
ogr_tiller [OPTIONS]
Options:
--mode Operating mode: serve | build_cache | serve_cache (default: serve)
--data_folder Path to folder containing GPKG files (required)
--cache_folder Path to folder for MBTile cache files (required)
--stylesheet_folder Path to folder containing custom Mapbox GL styles (optional)
--port HTTP server port (default: 8080)
--tile_timeout Timeout for tile generation in seconds (default: 3)
--disable_caching Bypass cache and always generate fresh tiles (default: false)
make buildmake publishmake clean- Data Source Discovery: Scans data folder for
.gpkgfiles - Tile Request: Client requests tile at
/tilesets/{tileset}/tiles/{z}/{x}/{y}.mvt - Cache Check: Looks up tile in SQLite MBTile cache (if caching enabled)
- Tile Generation: If not cached, extracts features from GPKG, clips to tile bounds, simplifies geometry
- MVT Encoding: Encodes features as Mapbox Vector Tile (Protocol Buffers)
- Cache Storage: Stores generated tile in MBTile database
- Response: Returns compressed MVT to client
Raw Features → Spatial Filter → Clip to Bounds → Simplify → Encode MVT → GZIP → Client
- Development Tool: Not optimized for production-scale serving
- Single-Threaded: Tile generation is not parallelized
- Memory Usage: Cache building loads entire datasets into memory
- Windows Timeout: Timeout protection disabled on Windows (SIGALRM limitation)
- Web Mercator Only: Outputs tiles in EPSG:3857 only
Contributions are welcome! Please feel free to submit issues or pull requests.
See LICENSE file for details.
Built with open-source geospatial tools:
