{"id":50027254,"url":"https://github.com/tobilg/duckdb-tileserver","last_synced_at":"2026-05-20T16:39:52.097Z","repository":{"id":325324058,"uuid":"1098262015","full_name":"tobilg/duckdb-tileserver","owner":"tobilg","description":"A lightweight MVT (Mapbox Vector Tile) tileserver for DuckDB with the duckdb-spatial extension","archived":false,"fork":false,"pushed_at":"2025-11-20T17:36:50.000Z","size":118,"stargazers_count":29,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-20T19:20:13.417Z","etag":null,"topics":["duckdb","geospatial","mvt","spatial","tileserver"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tobilg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-17T13:18:25.000Z","updated_at":"2025-11-20T17:27:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tobilg/duckdb-tileserver","commit_stats":null,"previous_names":["tobilg/duckdb-tileserver"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/tobilg/duckdb-tileserver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobilg%2Fduckdb-tileserver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobilg%2Fduckdb-tileserver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobilg%2Fduckdb-tileserver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobilg%2Fduckdb-tileserver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tobilg","download_url":"https://codeload.github.com/tobilg/duckdb-tileserver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobilg%2Fduckdb-tileserver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33267109,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-20T15:12:43.734Z","status":"ssl_error","status_checked_at":"2026-05-20T15:12:42.300Z","response_time":356,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["duckdb","geospatial","mvt","spatial","tileserver"],"created_at":"2026-05-20T16:39:47.763Z","updated_at":"2026-05-20T16:39:52.087Z","avatar_url":"https://github.com/tobilg.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# duckdb-tileserver\n\nA lightweight MVT (Mapbox Vector Tile) tileserver for [DuckDB](https://duckdb.org/) with [duckdb-spatial](https://github.com/duckdb/duckdb-spatial) support, written in [Go](https://golang.org/).\n\nServes vector tiles directly from DuckDB databases using the new `ST_AsMVT` function from DuckDB Spatial v1.4+.\n\nFor a complete list of implemented features, see [FEATURES.md](FEATURES.md).\n\n## Contents\n\n- [Features](#features)\n- [Download](#download)\n- [Preparing Your Database](#preparing-your-database)\n  - [Prerequisites](#prerequisites)\n  - [Basic Setup](#basic-setup)\n  - [Importing Data](#importing-data)\n  - [Setting the Spatial Reference System (SRID)](#setting-the-spatial-reference-system-srid)\n  - [Creating Spatial Indexes](#creating-spatial-indexes)\n  - [Validating Your Data](#validating-your-data)\n  - [Optimizing for Zoom Levels](#optimizing-for-zoom-levels)\n  - [Example: Complete Database Setup](#example-complete-database-setup)\n  - [Supported Geometry Types](#supported-geometry-types)\n  - [Tips](#tips)\n- [Quick Start](#quick-start)\n- [Build from Source](#build-from-source)\n  - [With Go installed](#with-go-installed)\n  - [Without Go (Docker build)](#without-go-docker-build)\n  - [Docker Image](#docker-image)\n- [Configuration](#configuration)\n  - [Configuration Using Environment Variables](#configuration-using-environment-variables)\n  - [SSL Configuration](#ssl-configuration)\n- [API Endpoints](#api-endpoints)\n  - [Tile Endpoints](#tile-endpoints)\n  - [Cache Management Endpoints](#cache-management-endpoints)\n  - [Example Requests](#example-requests)\n  - [Using with MapLibre GL JS](#using-with-maplibre-gl-js)\n- [Data Requirements](#data-requirements)\n- [Command-line Options](#command-line-options)\n- [Sample Data](#sample-data)\n- [Performance Tips](#performance-tips)\n- [Troubleshooting](#troubleshooting)\n  - [Enable Debug Logging](#enable-debug-logging)\n  - [Common Issues](#common-issues)\n- [Architecture](#architecture)\n- [License](#license)\n- [Credits](#credits)\n\n## Features\n\n* **MVT Tile Server**: Serves Mapbox Vector Tiles (MVT/PBF) for all spatial tables\n* **Auto-discovery**: Automatically discovers all tables with geometry columns\n* **Multi-SRID support**: Automatically transforms geometries to Web Mercator (EPSG:3857)\n* **TileJSON metadata**: Provides TileJSON spec endpoints for each layer\n* **Interactive map viewer**: Built-in HTML viewer with MapLibre GL JS\n* **Fast \u0026 Efficient**: Leverages DuckDB's columnar storage and spatial indexing\n* **Spatial extension**: Uses DuckDB Spatial's `ST_AsMVT` for efficient tile generation\n* **RESTful API**:\n  * `/` - Interactive map viewer\n  * `/layers` - List all available layers\n  * `/tiles/{layer}/{z}/{x}/{y}.mvt` - MVT tiles\n  * `/tiles/{layer}.json` - TileJSON metadata\n  * `/health` - Health check endpoint\n* **Full HTTP support**:\n  * CORS support with configurable origins\n  * GZIP response encoding\n  * HTTP and HTTPS support\n\n## Download\n\nBuilds of the latest code:\n\n* [GitHub Releases (Linux/MacOS/Windows binaries)](https://github.com/tobilg/duckdb-tileserver/releases)\n* [Docker image](https://hub.docker.com/repository/docker/tobilg/duckdb-tileserver/general)\n\n## Preparing Your Database\n\nTo use duckdb-tileserver, you need a DuckDB database with spatial data. This section covers how to prepare your database properly.\n\n### Prerequisites\n\n1. **Install DuckDB CLI**: Download from [duckdb.org](https://duckdb.org/docs/installation/)\n2. **Load the Spatial Extension**: The spatial extension provides geometry types and functions\n\n### Basic Setup\n\n```sql\n-- Load the spatial extension\nINSTALL spatial;\nLOAD spatial;\n\n-- Create a table with a geometry column\nCREATE TABLE buildings (\n    id INTEGER PRIMARY KEY,\n    name VARCHAR,\n    geom GEOMETRY\n);\n\n-- Insert some data (example using WKT)\nINSERT INTO buildings VALUES\n    (1, 'Building A', ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'));\n```\n\n### Importing Data\n\n#### From Shapefiles\n\n```sql\nLOAD spatial;\n\n-- Import shapefile directly\nCOPY buildings FROM 'buildings.shp' WITH (FORMAT GDAL, DRIVER 'ESRI Shapefile');\n```\n\n#### From GeoJSON\n\n```sql\nLOAD spatial;\n\n-- Import GeoJSON file\nCOPY buildings FROM 'buildings.geojson' WITH (FORMAT GDAL, DRIVER 'GeoJSON');\n```\n\n#### From GeoParquet\n\n```sql\nLOAD spatial;\n\n-- Read GeoParquet file\nCREATE TABLE buildings AS\n    SELECT * FROM ST_Read('buildings.parquet');\n```\n\n#### From PostGIS\n\n```sql\nLOAD spatial;\nINSTALL postgres;\nLOAD postgres;\n\n-- Attach PostgreSQL database\nATTACH 'dbname=mydb user=postgres host=localhost' AS pg (TYPE postgres);\n\n-- Copy data from PostGIS\nCREATE TABLE buildings AS\n    SELECT id, name, geom::GEOMETRY as geom\n    FROM pg.public.buildings;\n```\n\n### Setting the Spatial Reference System (SRID)\n\nFor best performance, set your geometries to EPSG:3857 (Web Mercator). If your data uses a different SRID, you can transform it:\n\n```sql\n-- Check current SRID\nSELECT DISTINCT ST_SRID(geom) FROM buildings;\n\n-- Transform to Web Mercator (EPSG:3857)\nUPDATE buildings\nSET geom = ST_Transform(geom, 'EPSG:4326', 'EPSG:3857');\n\n-- Or create a new column with transformed geometries\nALTER TABLE buildings ADD COLUMN geom_3857 GEOMETRY;\nUPDATE buildings\nSET geom_3857 = ST_Transform(geom, 'EPSG:4326', 'EPSG:3857');\n```\n\n### Creating Spatial Indexes\n\nR-Tree indexes significantly improve tile generation performance:\n\n```sql\n-- Create R-Tree spatial index on geometry column\nCREATE INDEX buildings_geom_idx ON buildings USING RTREE (geom);\n\n-- Verify index was created\nSELECT * FROM duckdb_indexes() WHERE table_name = 'buildings';\n```\n\n### Validating Your Data\n\nEnsure your geometries are valid before serving tiles:\n\n```sql\n-- Check for invalid geometries\nSELECT id, ST_IsValid(geom) as is_valid, ST_IsValidReason(geom) as reason\nFROM buildings\nWHERE NOT ST_IsValid(geom);\n\n-- Fix invalid geometries\nUPDATE buildings\nSET geom = ST_MakeValid(geom)\nWHERE NOT ST_IsValid(geom);\n```\n\n### Optimizing for Zoom Levels\n\nFor large datasets, consider creating simplified versions for lower zoom levels:\n\n```sql\n-- Create simplified geometries for overview zoom levels\nCREATE TABLE buildings_simplified AS\nSELECT\n    id,\n    name,\n    ST_Simplify(geom, 100) as geom  -- Simplify with 100m tolerance\nFROM buildings\nWHERE ST_Area(geom) \u003e 10000;  -- Only keep larger features\n\n-- Create spatial index on simplified table\nCREATE INDEX buildings_simplified_geom_idx\n    ON buildings_simplified USING RTREE (geom);\n```\n\n### Example: Complete Database Setup\n\n```sql\n-- Create database and load extensions\nINSTALL spatial;\nLOAD spatial;\n\n-- Import data from GeoJSON\nCOPY buildings FROM 'buildings.geojson' WITH (FORMAT GDAL, DRIVER 'GeoJSON');\n\n-- Transform to Web Mercator if needed\nUPDATE buildings\nSET geom = ST_Transform(geom, 'EPSG:4326', 'EPSG:3857')\nWHERE ST_SRID(geom) = 4326;\n\n-- Validate and fix geometries\nUPDATE buildings\nSET geom = ST_MakeValid(geom)\nWHERE NOT ST_IsValid(geom);\n\n-- Create spatial index\nCREATE INDEX buildings_geom_idx ON buildings USING RTREE (geom);\n\n-- Verify setup\nSELECT\n    COUNT(*) as feature_count,\n    ST_SRID(geom) as srid,\n    ST_GeometryType(geom) as geometry_type\nFROM buildings\nGROUP BY ST_SRID(geom), ST_GeometryType(geom);\n```\n\n### Supported Geometry Types\n\nDuckDB Spatial supports all standard OGC geometry types:\n\n* **POINT** / **MULTIPOINT** - For point features (POIs, markers)\n* **LINESTRING** / **MULTILINESTRING** - For linear features (roads, rivers)\n* **POLYGON** / **MULTIPOLYGON** - For area features (buildings, parcels)\n* **GEOMETRYCOLLECTION** - Mixed geometry types\n\n### Tips\n\n* **Column naming**: The tileserver auto-detects geometry columns - use standard names like `geom`, `geometry`, or `wkb_geometry`\n* **Multiple geometry columns**: If a table has multiple geometry columns, the tileserver uses the first one and logs a warning\n* **Data types**: All standard DuckDB data types are preserved in tile properties\n* **File size**: DuckDB uses columnar compression - expect significant space savings compared to shapefiles\n* **Read-only mode**: The tileserver opens databases in read-only mode, so your data is safe\n\n## Quick Start\n\n### 1. Prepare Your Data\n\nCreate a DuckDB database with spatial data:\n\n```bash\n# Create sample data\nduckdb tiles.db \u003c testing/sample_data.sql\n```\n\nThis creates sample tables: `buildings`, `roads`, `poi`, and `parcels` with geometry columns.\n\n### 2. Run the Server\n\n```bash\n./duckdb-tileserver --database-path tiles.db\n```\n\n### 3. View the Map\n\nOpen http://localhost:9000/ in your browser to see an interactive map with all your spatial layers.\n\n## Build from Source\n\n`duckdb-tileserver` requires Go 1.24+ to support the latest DuckDB driver.\n\n### With Go installed\n\n```bash\ncd duckdb-tileserver/\ngo build\n```\n\nThis creates a `duckdb-tileserver` executable in the application directory.\n\n### Without Go (Docker build)\n\n```bash\nmake APPVERSION=\u003cVERSION\u003e clean build-in-docker\n```\n\n### Docker Image\n\n#### Build the image\n\n```bash\nmake APPVERSION=\u003cVERSION\u003e clean docker\n```\n\n#### Run the image\n\n```bash\ndocker run --rm -dt \\\n  -v \"$PWD/tiles.db:/data/tiles.db\" \\\n  -e DUCKDBTS_DATABASE_PATH=/data/tiles.db \\\n  -p 9000:9000 \\\n  tobilg/duckdb-tileserver:\u003cVERSION\u003e\n```\n\n#### Complete example with sample data\n\n```bash\n# Build the Docker image\nmake APPVERSION=0.1.2 clean docker\n\n# Create sample database with spatial data\nduckdb tiles.db \u003c testing/sample_data.sql\n\n# Run the container\ndocker run --rm -dt \\\n  -v \"$PWD/tiles.db:/data/tiles.db\" \\\n  -e DUCKDBTS_DATABASE_PATH=/data/tiles.db \\\n  -p 9000:9000 \\\n  --name duckdb-tileserver \\\n  tobilg/duckdb-tileserver:0.1.2\n\n# View logs\ndocker logs -f duckdb-tileserver\n\n# Access the interactive map viewer at http://localhost:9000\n# Stop the container when done\ndocker stop duckdb-tileserver\n```\n\n## Configuration\n\nThe configuration file (see [example](config/duckdb-tileserver.toml.example)) is automatically read from:\n\n* `/etc/duckdb-tileserver.toml`\n* `./config/duckdb-tileserver.toml`\n* `/config/duckdb-tileserver.toml`\n\nTo specify a configuration file directly use the `--config` parameter.\n\n### Configuration Using Environment Variables\n\nAll configuration options can be set via environment variables using the prefix `DUCKDBTS_` followed by the section and key name separated by underscores. For nested configuration like `Server.HttpPort`, use `DUCKDBTS_SERVER_HTTPPORT`.\n\n#### Database Configuration\n\n```bash\n# Database path (required)\nexport DUCKDBTS_DATABASE_PATH=\"/path/to/database.db\"\n\n# Filter which tables to serve as tile layers (comma-separated)\nexport DUCKDBTS_DATABASE_TABLEINCLUDES=\"buildings,roads,parcels\"\nexport DUCKDBTS_DATABASE_TABLEEXCLUDES=\"temp_table,staging\"\n\n# Function includes (comma-separated, default: \"postgisftw\")\nexport DUCKDBTS_DATABASE_FUNCTIONINCLUDES=\"func1,func2\"\n\n# Connection pool settings (for performance tuning)\nexport DUCKDBTS_DATABASE_MAXOPENCONNS=25        # Max open connections (default: 25)\nexport DUCKDBTS_DATABASE_MAXIDLECONNS=5         # Max idle connections (default: 5)\nexport DUCKDBTS_DATABASE_CONNMAXLIFETIME=3600   # Connection max lifetime in seconds (default: 3600)\nexport DUCKDBTS_DATABASE_CONNMAXIDLETIME=600    # Idle connection timeout in seconds (default: 600)\n```\n\n#### Server Configuration\n\n```bash\n# HTTP server settings\nexport DUCKDBTS_SERVER_HTTPHOST=\"0.0.0.0\"\nexport DUCKDBTS_SERVER_HTTPPORT=9000\nexport DUCKDBTS_SERVER_HTTPSPORT=9001\n\n# TLS/HTTPS configuration\nexport DUCKDBTS_SERVER_TLSSERVERCERTIFICATEFILE=\"/path/to/server.crt\"\nexport DUCKDBTS_SERVER_TLSSERVERPRIVATEKEYFILE=\"/path/to/server.key\"\n\n# URL configuration\nexport DUCKDBTS_SERVER_URLBASE=\"https://example.com\"\nexport DUCKDBTS_SERVER_BASEPATH=\"/tiles\"\n\n# CORS origins (default: \"*\")\nexport DUCKDBTS_SERVER_CORSORIGINS=\"https://example.com,https://app.example.com\"\n\n# Debug mode\nexport DUCKDBTS_SERVER_DEBUG=true\n\n# Assets path for HTML templates\nexport DUCKDBTS_SERVER_ASSETSPATH=\"./assets\"\n\n# Timeouts in seconds\nexport DUCKDBTS_SERVER_READTIMEOUTSEC=5\nexport DUCKDBTS_SERVER_WRITETIMEOUTSEC=30\n\n# Disable HTML UI\nexport DUCKDBTS_SERVER_DISABLEUI=false\n```\n\n#### Metadata Configuration\n\n```bash\n# Service metadata\nexport DUCKDBTS_METADATA_TITLE=\"My Tile Server\"\nexport DUCKDBTS_METADATA_DESCRIPTION=\"Custom tile server description\"\n```\n\n#### Website Configuration\n\n```bash\n# Custom basemap URL for the map viewer\nexport DUCKDBTS_WEBSITE_BASEMAPURL=\"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"\n```\n\n#### Cache Configuration\n\n```bash\n# Cache settings\nexport DUCKDBTS_CACHE_ENABLED=true\nexport DUCKDBTS_CACHE_MAXITEMS=10000\nexport DUCKDBTS_CACHE_MAXMEMORYMB=1024\nexport DUCKDBTS_CACHE_BROWSERCACHEMAXAGE=3600  # Browser cache max-age in seconds\n\n# Cache management API endpoints\nexport DUCKDBTS_CACHE_DISABLEAPI=false  # Disable /cache/* endpoints\nexport DUCKDBTS_CACHE_APIKEY=\"your-secret-key\"  # Require API key for cache endpoints\n```\n\n#### Paging Configuration\n\n```bash\n# Pagination settings for feature queries\nexport DUCKDBTS_PAGING_LIMITDEFAULT=10\nexport DUCKDBTS_PAGING_LIMITMAX=1000\n```\n\n### SSL Configuration\n\nFor SSL support, generate or provide a server certificate and private key:\n\n```bash\n# Generate self-signed certificate for testing\nopenssl req -nodes -new -x509 -keyout server.key -out server.crt\n```\n\nConfigure in config file:\n```toml\n[Server]\nTlsServerCertificateFile = \"/path/server.crt\"\nTlsServerPrivateKeyFile = \"/path/server.key\"\nHttpsPort = 9001\n```\n\n## API Endpoints\n\n### Tile Endpoints\n\n* **GET /** - Interactive map viewer (HTML)\n* **GET /layers** - List all available spatial layers (JSON)\n* **GET /tiles/{layer}.json** - TileJSON metadata for a layer\n* **GET /tiles/{layer}/{z}/{x}/{y}.mvt** - MVT tile for a layer\n* **GET /tiles/{layer}/{z}/{x}/{y}.pbf** - MVT tile (alternative extension)\n* **GET /health** - Health check endpoint\n\n### Cache Management Endpoints\n\nThese endpoints allow you to manage the tile cache. They can be disabled via configuration and optionally protected with an API key.\n\n* **GET /cache/stats** - Get cache statistics (hits, misses, hit rate, size, memory usage)\n* **DELETE /cache/clear** - Clear the entire tile cache\n* **DELETE /cache/layer/{layer}** - Clear cache for a specific layer\n\n**Authentication:** If `ApiKey` is configured in the `[Cache]` section, include the `X-API-Key` header:\n```bash\ncurl -H \"X-API-Key: your-secret-key\" http://localhost:9000/cache/stats\n```\n\n**Configuration:**\n- Set `DUCKDBTS_CACHE_DISABLEAPI=true` to disable these endpoints\n- Set `DUCKDBTS_CACHE_APIKEY=your-secret-key` to require authentication\n\n### Example Requests\n\n```bash\n# List available layers\ncurl http://localhost:9000/layers\n\n# Get TileJSON metadata for buildings layer\ncurl http://localhost:9000/tiles/buildings.json\n\n# Get a specific tile (zoom 12, x=1205, y=1539)\ncurl http://localhost:9000/tiles/buildings/12/1205/1539.mvt -o tile.mvt\n\n# Check service health\ncurl http://localhost:9000/health\n\n# Cache management (without authentication)\ncurl http://localhost:9000/cache/stats\ncurl -X DELETE http://localhost:9000/cache/clear\ncurl -X DELETE http://localhost:9000/cache/layer/buildings\n\n# Cache management (with API key authentication)\ncurl -H \"X-API-Key: your-secret-key\" http://localhost:9000/cache/stats\ncurl -H \"X-API-Key: your-secret-key\" -X DELETE http://localhost:9000/cache/clear\n```\n\n### Using with MapLibre GL JS\n\n```javascript\nmap.addSource('buildings', {\n  type: 'vector',\n  tiles: ['http://localhost:9000/tiles/buildings/{z}/{x}/{y}.mvt'],\n  minzoom: 0,\n  maxzoom: 22\n});\n\nmap.addLayer({\n  id: 'buildings-fill',\n  type: 'fill',\n  source: 'buildings',\n  'source-layer': 'buildings',\n  paint: {\n    'fill-color': '#3388ff',\n    'fill-opacity': 0.6\n  }\n});\n```\n\n## Data Requirements\n\nTables must have a geometry column to be served as tile layers. DuckDB Spatial supports various geometry types:\n\n* POINT / MULTIPOINT\n* LINESTRING / MULTILINESTRING\n* POLYGON / MULTIPOLYGON\n* GEOMETRYCOLLECTION\n\nThe tileserver will:\n1. Auto-detect all tables with geometry columns\n2. Use the first geometry column if multiple exist (with a warning)\n3. Automatically transform geometries to EPSG:3857 (Web Mercator) for tiles\n4. Apply include/exclude filters from configuration\n\n## Command-line Options\n\n* `-?` - Show command usage\n* `--config file.toml` - Specify configuration file\n* `--debug` - Set logging level to TRACE\n* `--devel` - Run in development mode (reload templates on each request)\n* `--disable-ui` - Disable HTML UI routes\n* `--test` - Run with mock data for testing\n* `--version` - Display version number\n* `--database-path path` - Path to DuckDB database file\n\n## Sample Data\n\nGenerate sample spatial data for testing:\n\n```bash\nduckdb tiles.db \u003c testing/sample_data.sql\n./duckdb-tileserver --database-path tiles.db\n```\n\nThis creates four sample layers:\n* **buildings** - 1000 polygon features (Web Mercator)\n* **roads** - 500 linestring features (WGS84)\n* **poi** - 200 point features (Web Mercator)\n* **parcels** - 300 polygon features (Web Mercator)\n\n## Performance Tips\n\n1. **Spatial Indexes**: Create R-Tree indexes on geometry columns for better performance:\n   ```sql\n   CREATE INDEX buildings_geom_idx ON buildings USING RTREE (geom);\n   ```\n2. **Coordinate Reference System**: Store data in EPSG:3857 (Web Mercator) to avoid transformation overhead\n3. **Connection Pooling**: Configure connection pool settings based on your workload:\n   - `MaxOpenConns`: Set to 2-4x your CPU cores (default: 25)\n   - `MaxIdleConns`: Keep warm connections available (default: 5)\n   - The server uses a shared connection pool to efficiently handle concurrent tile requests\n4. **Caching**: The built-in LRU cache significantly reduces database load:\n   - Layer metadata is automatically cached to eliminate repeated queries\n   - Tile cache can store up to 10,000 tiles (configurable)\n   - Browser caching reduces server requests (default: 1 hour)\n5. **Table Filtering**: Use `TableIncludes` to serve only necessary tables\n6. **Zoom Levels**: Consider creating pre-aggregated tables for lower zoom levels\n\n## Troubleshooting\n\n### Enable Debug Logging\n\n```bash\n./duckdb-tileserver --debug --database-path tiles.db\n```\n\nOr in config file:\n```toml\n[Server]\nDebug = true\n```\n\n### Common Issues\n\n**No layers appear:**\n- Check that tables have geometry columns: `SELECT * FROM duckdb_columns WHERE data_type = 'GEOMETRY'`\n- Verify spatial extension is loaded: `LOAD spatial;`\n- Check table filters in configuration\n\n**Empty tiles:**\n- Verify data has geometries in the tile extent\n- Check SRID of geometries: `SELECT DISTINCT ST_SRID(geometry) FROM your_table`\n- Ensure geometries are valid: `SELECT ST_IsValid(geometry) FROM your_table`\n\n**Slow tile generation:**\n- Create R-Tree spatial indexes on geometry columns if not already present\n- Consider filtering data by zoom level\n- Pre-aggregate data for lower zoom levels\n\n## Architecture\n\n```\n┌─────────────────┐\n│   HTTP Client   │\n│ (Browser/QGIS)  │\n└────────┬────────┘\n         │\n         ↓\n┌─────────────────┐\n│  HTTP Handlers  │\n│  (Gorilla Mux)  │\n└────────┬────────┘\n         │\n         ↓\n┌─────────────────┐\n│  Tile Generator │\n│  (ST_AsMVT)     │\n└────────┬────────┘\n         │\n         ↓\n┌─────────────────┐\n│   DuckDB + SQL  │\n│  Spatial Ext.   │\n└─────────────────┘\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobilg%2Fduckdb-tileserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftobilg%2Fduckdb-tileserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobilg%2Fduckdb-tileserver/lists"}