{"id":35830453,"url":"https://github.com/vinayakkulkarni/tileserver-rs","last_synced_at":"2026-04-03T23:02:42.957Z","repository":{"id":331264160,"uuid":"587174917","full_name":"vinayakkulkarni/tileserver-rs","owner":"vinayakkulkarni","description":"High-performance Rust tile server for PMTiles, MBTiles, PostGIS, and Cloud Optimized GeoTIFFs","archived":false,"fork":false,"pushed_at":"2026-03-30T17:00:44.000Z","size":56951,"stargazers_count":10,"open_issues_count":19,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-30T18:24:00.039Z","etag":null,"topics":["gis","maplibre-gl-js","maplibre-rs","openmaptiles","raster-map","raster-tiles","rust","tileserver","tileserver-rs","vector-tiles"],"latest_commit_sha":null,"homepage":"https://tileserver.app","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vinayakkulkarni.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2023-01-10T06:07:55.000Z","updated_at":"2026-03-30T17:00:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"6929c878-cfbb-44f3-86c5-3bcf1d7234af","html_url":"https://github.com/vinayakkulkarni/tileserver-rs","commit_stats":null,"previous_names":["vinayakkulkarni/tileserver-rs"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/vinayakkulkarni/tileserver-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinayakkulkarni%2Ftileserver-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinayakkulkarni%2Ftileserver-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinayakkulkarni%2Ftileserver-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinayakkulkarni%2Ftileserver-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vinayakkulkarni","download_url":"https://codeload.github.com/vinayakkulkarni/tileserver-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinayakkulkarni%2Ftileserver-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31381009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T21:40:47.592Z","status":"ssl_error","status_checked_at":"2026-04-03T21:40:05.436Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["gis","maplibre-gl-js","maplibre-rs","openmaptiles","raster-map","raster-tiles","rust","tileserver","tileserver-rs","vector-tiles"],"created_at":"2026-01-07T22:16:35.591Z","updated_at":"2026-04-03T23:02:42.950Z","avatar_url":"https://github.com/vinayakkulkarni.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tileserver-rs 🦀\n\n[![CI Pipeline](https://github.com/vinayakkulkarni/tileserver-rs/actions/workflows/pipeline.yml/badge.svg)](https://github.com/vinayakkulkarni/tileserver-rs/actions/workflows/pipeline.yml)\n[![Docker](https://github.com/vinayakkulkarni/tileserver-rs/actions/workflows/release-docker.yml/badge.svg)](https://github.com/vinayakkulkarni/tileserver-rs/actions/workflows/release-docker.yml)\n[![mbgl-sys on crates.io](https://img.shields.io/crates/v/mbgl-sys.svg)](https://crates.io/crates/mbgl-sys)\n[![mbgl-sys on docs.rs](https://docs.rs/mbgl-sys/badge.svg)](https://docs.rs/mbgl-sys)\n\n[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/1u-LMi)\n[![Deploy on Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/vinayakkulkarni/tileserver-rs)\n[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/vinayakkulkarni/tileserver-rs/tree/main)\n\n\u003cimg src=\"./.github/assets/tileserver-rs.png\" width=\"512\" height=\"512\" align=\"center\" alt=\"tileserver-rs logo\" /\u003e\n\nHigh-performance vector tile server built in Rust with a modern Nuxt 4 frontend.\n\n## Features\n\n- **PMTiles Support** - Serve tiles from local and remote PMTiles archives\n- **MBTiles Support** - Serve tiles from SQLite-based MBTiles files\n- **Native Raster Rendering** - Generate PNG/JPEG/WebP tiles using MapLibre Native (C++ FFI)\n- **MLT (MapLibre Tiles)** - Serve and transcode MLT tiles with MLT↔MVT on-the-fly conversion (feature-gated)\n- **PostgreSQL Out-DB Rasters** - Serve VRT/COG tiles via PostGIS functions with dynamic filtering\n- **Static Map Images** - Create embeddable map screenshots (like Mapbox/Maptiler Static API)\n- **Zero-Config Auto-Detect** - Point at a directory or file and start serving instantly\n- **Hot Reload** - Reload configuration via `SIGHUP` signal or admin API without downtime\n- **High Performance** - ~100ms per tile (warm cache), ~800ms cold cache\n- **TileJSON 3.0** - Full TileJSON metadata API\n- **MapLibre GL JS** - Built-in map viewer and data inspector\n- **Docker Ready** - Easy deployment with Docker Compose v2\n- **Fast** - Built in Rust with Axum for maximum performance\n\n## Tech Stack\n\n- **Backend**: Rust 1.75+, Axum 0.8, Tokio\n- **Native Rendering**: MapLibre Native (C++) via FFI bindings\n- **Frontend**: Nuxt 4, Vue 3.5, Tailwind CSS v4, shadcn-vue\n- **Tooling**: Bun workspaces, Docker multi-stage builds\n\n## Table of Contents\n\n- [Features](#features)\n- [Tech Stack](#tech-stack)\n- [Requirements](#requirements)\n- [Quick Start](#quick-start)\n- [Installation](#installation)\n  - [Using Docker](#using-docker)\n  - [Building from Source](#building-from-source)\n- [Configuration](#configuration)\n- [API Endpoints](#api-endpoints)\n- [Deploy](#deploy)\n- [Development](#development)\n- [Contributing](#contributing)\n- [Author](#author)\n\n## Requirements\n\n- [Rust 1.75+](https://www.rust-lang.org/)\n- [Bun 1.0+](https://bun.sh/)\n- (Optional) [Docker](https://www.docker.com/)\n\n### For Native Rendering (Optional)\n\nNative raster tile rendering requires building MapLibre Native. If you don't need raster tiles, the server runs without it (stub implementation returns placeholder images).\n\n**macOS (Apple Silicon/Intel):**\n```bash\n# Install build dependencies\nbrew install ninja ccache libuv glfw bazelisk cmake\n\n# Build MapLibre Native\ncd crates/mbgl-sys/vendor/maplibre-native\ngit submodule update --init --recursive\ncmake --preset macos-metal\ncmake --build build-macos-metal --target mbgl-core mlt-cpp -j8\n```\n\n**Linux:**\n```bash\n# Install build dependencies (Ubuntu/Debian)\napt-get install ninja-build ccache libuv1-dev libglfw3-dev cmake\n\n# Build MapLibre Native\ncd crates/mbgl-sys/vendor/maplibre-native\ngit submodule update --init --recursive\ncmake --preset linux\ncmake --build build-linux --target mbgl-core mlt-cpp -j8\n```\n\n**After building MapLibre Native:**\n```bash\n# Clear Cargo's cached build to detect the new libraries\ncd /path/to/tileserver-rs\nrm -rf target/release/build/mbgl-sys-*\ncargo build --release\n```\n\nYou should see `Building with real MapLibre Native renderer` in the build output.\n\n## Quick Start\n\n```bash\n# Zero-config: point at a directory of tile files\n./tileserver-rs /path/to/data\n\n# Or with an explicit config file\n./tileserver-rs --config config.toml\n\n# Using Docker\ndocker compose up -d\n```\n\nThe server auto-detects `.pmtiles`, `.mbtiles`, `style.json`, fonts, and GeoJSON files from the given path. See the [Auto-Detect Guide](https://docs.tileserver.app/guides/auto-detect) for details.\n\n## Installation\n\n### Using Homebrew (macOS)\n\n```bash\n# Add the tap and install\nbrew tap vinayakkulkarni/tileserver-rs https://github.com/vinayakkulkarni/tileserver-rs\nbrew install vinayakkulkarni/tileserver-rs/tileserver-rs\n\n# Run the server\ntileserver-rs --config config.toml\n```\n\n### Pre-built Binaries\n\nDownload the latest release from [GitHub Releases](https://github.com/vinayakkulkarni/tileserver-rs/releases).\n\n| Platform | Architecture | Download |\n|----------|--------------|----------|\n| macOS | Apple Silicon (ARM64) | `tileserver-rs-aarch64-apple-darwin.tar.gz` |\n| macOS | Intel (x86_64) | `tileserver-rs-x86_64-apple-darwin.tar.gz` |\n| Linux | x86_64 | `tileserver-rs-x86_64-unknown-linux-gnu.tar.gz` |\n| Linux | ARM64 | `tileserver-rs-aarch64-unknown-linux-gnu.tar.gz` |\n\n```bash\n# macOS ARM64 (Apple Silicon)\ncurl -L https://github.com/vinayakkulkarni/tileserver-rs/releases/latest/download/tileserver-rs-aarch64-apple-darwin.tar.gz | tar xz\nchmod +x tileserver-rs\n\n# Remove macOS quarantine (required for unsigned binaries)\nxattr -d com.apple.quarantine tileserver-rs\n\n# Linux x86_64\ncurl -L https://github.com/vinayakkulkarni/tileserver-rs/releases/latest/download/tileserver-rs-x86_64-unknown-linux-gnu.tar.gz | tar xz\nchmod +x tileserver-rs\n\n# Run\n./tileserver-rs --config config.toml\n```\n\n\u003e **macOS Security Note:** If you download via a browser, macOS Gatekeeper will block the unsigned binary. Either use the `curl` command above, or after downloading, run `xattr -d com.apple.quarantine \u003cbinary\u003e` to remove the quarantine flag. Alternatively, right-click the binary in Finder and select \"Open\".\n\n### Using Docker\n\n```bash\n# Development (builds locally, mounts ./data directory)\ndocker compose up -d\n\n# Production (uses pre-built image with resource limits)\ndocker compose -f compose.yml -f compose.prod.yml up -d\n\n# View logs\ndocker compose logs -f tileserver\n\n# Stop\ndocker compose down\n```\n\n**Or run directly with Docker:**\n\n```bash\ndocker run -d \\\n  -p 8080:8080 \\\n  -v /path/to/data:/data:ro \\\n  -v /path/to/config.toml:/app/config.toml:ro \\\n  ghcr.io/vinayakkulkarni/tileserver-rs:latest\n```\n\n### Building from Source\n\n```bash\n# Clone the repository with submodules\ngit clone --recursive git@github.com:vinayakkulkarni/tileserver-rs.git\ncd tileserver-rs\n\n# Or using HTTPS\ngit clone --recursive https://github.com/vinayakkulkarni/tileserver-rs.git\n\n# If you already cloned without --recursive:\ngit submodule update --init --recursive\n\n# Install dependencies\nbun install\n\n# Build the Rust backend\ncargo build --release\n\n# Build with MLT transcoding support (optional)\ncargo build --release --features mlt\n\n# Build the frontend\nbun run build:client\n\n# Run the server\n./target/release/tileserver-rs --config config.toml\n```\n\n\u003e **Note:** The `--recursive` flag fetches the MapLibre Native submodule (~200MB) required for native raster rendering. If the clone times out, use `git submodule update --init --depth 1` for a shallow clone. See [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed setup instructions.\n\n## Configuration\n\nCreate a `config.toml` file. **Important:** Root-level options (`fonts`, `files`) must come before any `[section]` headers:\n\n```toml\n# Root-level options (must come BEFORE [sections])\nfonts = \"/data/fonts\"\nfiles = \"/data/files\"\n\n[server]\nhost = \"0.0.0.0\"\nport = 8080\ncors_origins = [\"*\", \"https://example.com\"]  # Supports multiple origins\n# Admin server bind address for hot-reload endpoint (default: disabled)\n# admin_bind = \"127.0.0.1:9099\"\n\n[telemetry]\nenabled = false\n\n[[sources]]\nid = \"openmaptiles\"\ntype = \"pmtiles\"\npath = \"/data/tiles.pmtiles\"\nname = \"OpenMapTiles\"\nattribution = \"© OpenMapTiles © OpenStreetMap contributors\"\n\n[[sources]]\nid = \"terrain\"\ntype = \"mbtiles\"\npath = \"/data/terrain.mbtiles\"\nname = \"Terrain Data\"\n\n[[styles]]\nid = \"osm-bright\"\npath = \"/data/styles/osm-bright/style.json\"\n\n# PostgreSQL Out-of-Database Rasters (optional)\n[postgres]\nconnection_string = \"postgresql://user:pass@localhost:5432/gis\"\n\n[[postgres.outdb_rasters]]\nid = \"imagery\"                    # Also used as function name if 'function' is omitted\nschema = \"public\"\n# function = \"get_raster_paths\"   # Optional: defaults to 'id' value\nname = \"Satellite Imagery\"\n```\n\n### Admin Server (Hot Reload)\n\nEnable the admin server by setting `admin_bind` in `[server]`:\n\n```toml\n[server]\nadmin_bind = \"127.0.0.1:9099\"\n```\n\nThis exposes `POST /__admin/reload` on a separate port for reloading configuration without restarting the server. You can also send `SIGHUP` to the process for the same effect. See the [Hot Reload Guide](https://docs.tileserver.app/guides/hot-reload) for details.\n\nSee [configs/example.toml](./configs/example.toml) for a complete example, or [configs/offline.toml](./configs/offline.toml) for a local development setup.\n\n## API Endpoints\n\n### Health \u0026 Admin Endpoints\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET /health` | Health check (returns `OK`) |\n| `GET /ping` | Runtime metadata (config hash, loaded sources/styles, version) |\n| `POST /__admin/reload` | Hot-reload configuration (admin server only) |\n| `POST /__admin/reload?flush=true` | Force reload even if config unchanged |\n\n### Data Endpoints (Vector Tiles)\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET /data.json` | List all tile sources |\n| `GET /data/{source}.json` | TileJSON for a source |\n| `GET /data/{source}/{z}/{x}/{y}.{format}` | Get a vector tile (`.pbf`, `.mvt`, `.mlt`) |\n| `GET /data/{source}/{z}/{x}/{y}.geojson` | Get tile as GeoJSON (for debugging) |\n\n### Style Endpoints\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET /styles.json` | List all styles |\n| `GET /styles/{style}/style.json` | Get MapLibre GL style JSON |\n| `GET /styles/{style}/sprite[@2x].{png,json}` | Get sprite image/metadata |\n| `GET /styles/{style}/wmts.xml` | WMTS capabilities (for QGIS/ArcGIS) |\n\n### Font Endpoints\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET /fonts.json` | List available font families |\n| `GET /fonts/{fontstack}/{range}.pbf` | Get font glyphs (PBF format) |\n\n### Other Endpoints\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET /files/{filepath}` | Serve static files (GeoJSON, icons, etc.) |\n| `GET /index.json` | Combined TileJSON for all sources and styles |\n\n### PostgreSQL Out-DB Raster Endpoints\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET /data/{outdb_source}/{z}/{x}/{y}.{format}` | Raster tile from PostgreSQL-referenced VRT/COG |\n| `GET /data/{outdb_source}/{z}/{x}/{y}.{format}?satellite=...` | With dynamic filtering via query params |\n\n### Rendering Endpoints (Native MapLibre)\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET /styles/{style}/{z}/{x}/{y}[@{scale}x].{format}` | Raster tile (PNG/JPEG/WebP) |\n| `GET /styles/{style}/static/{type}/{size}[@{scale}x].{format}` | Static map image |\n\n**Raster Tile Examples:**\n```\n/styles/protomaps-light/14/8192/5461.png          # 512x512 PNG @ 1x\n/styles/protomaps-light/14/8192/5461@2x.webp      # 1024x1024 WebP @ 2x (retina)\n```\n\n**Performance:**\n- Warm cache: ~100ms per tile\n- Cold cache: ~700-800ms per tile (includes tile fetching)\n- Static images: ~3s for 800x600\n\n**Static Image Types:**\n- **Center**: `{lon},{lat},{zoom}[@{bearing}[,{pitch}]]`\n  ```\n  /styles/protomaps-light/static/-122.4,37.8,12/800x600.png\n  /styles/protomaps-light/static/-122.4,37.8,12@45,60/800x600@2x.webp\n  ```\n- **Bounding Box**: `{minx},{miny},{maxx},{maxy}`\n  ```\n  /styles/protomaps-light/static/-123,37,-122,38/1024x768.jpeg\n  ```\n- **Auto-fit**: `auto` (with `?path=` or `?marker=` query params)\n  ```\n  /styles/protomaps-light/static/auto/800x600.png?path=path-5+f00(-122.4,37.8|-122.5,37.9)\n  ```\n\n**Static Image Limits:**\n- Maximum dimensions: 4096x4096 pixels\n- Maximum scale: 4x\n\n## Development\n\n```bash\n# Install dependencies\nbun install\n\n# Start Rust backend (with hot reload via cargo-watch)\ncargo watch -x run\n\n# Start Nuxt frontend (in another terminal)\nbun run dev:client\n\n# Start marketing site (landing page)\nbun run dev:marketing\n\n# Run linters\nbun run lint\ncargo clippy\n\n# Build for production\ncargo build --release\nbun run build:client\n```\n\n### Cargo Feature Flags\n\n| Feature | Description |\n|---------|-------------|\n| `http` | Enable serving PMTiles from remote HTTP URLs |\n| `mlt` | Enable MLT (MapLibre Tiles) transcoding support |\n\n```bash\n# Build with MLT support\ncargo build --release --features mlt\n\n# Build with all optional features\ncargo build --release --features http,mlt\n```\n\n### Project Structure\n\n```\ntileserver-rs/\n├── apps/\n│   └── client/              # Nuxt 4 frontend (embedded in binary)\n├── docs/                    # Documentation site (docs.tileserver.app)\n├── marketing/               # Landing page (tileserver.app)\n├── crates/\n│   └── mbgl-sys/            # FFI bindings to MapLibre Native (C++)\n│       ├── cpp/             # C/C++ wrapper code\n│       │   ├── maplibre_c.h # C API header\n│       │   └── maplibre_c.cpp # C++ implementation\n│       ├── src/lib.rs       # Rust FFI bindings\n│       ├── build.rs         # Build script\n│       └── vendor/maplibre-native/  # MapLibre Native source (submodule)\n├── src/                     # Rust backend\n│   ├── main.rs              # Entry point, routes\n│   ├── admin.rs             # Admin server + /ping endpoint\n│   ├── autodetect.rs        # Zero-config auto-detection\n│   ├── config.rs            # Configuration\n│   ├── error.rs             # Error types\n│   ├── reload.rs            # Hot-reload (ArcSwap + SIGHUP)\n│   ├── startup.rs           # Config resolution priority chain\n│   ├── render/              # Native MapLibre rendering\n│   │   ├── pool.rs          # Renderer pool (per scale factor)\n│   │   ├── renderer.rs      # High-level render API\n│   │   ├── native.rs        # Safe Rust wrappers around FFI\n│   │   └── types.rs         # RenderOptions, ImageFormat, etc.\n│   ├── sources/             # Tile source implementations\n│   └── styles/              # Style management + rewriting\n│   ├── transcode.rs         # MLT↔MVT transcoding (feature-gated)\n├── compose.yml              # Docker Compose (development)\n├── compose.prod.yml         # Docker Compose (production overrides)\n├── Dockerfile               # Multi-stage Docker build\n├── configs/                 # Configuration files\n│   ├── example.toml         # Example configuration\n│   ├── offline.toml         # Offline/local development\n│   ├── dev.toml             # Development config\n│   ├── geoparquet.toml      # GeoParquet source testing\n│   └── benchmark-raster.toml # Raster benchmark config\n└── tests/                   # Integration tests + test configs\n```\n\n## Deploy\n\n### One-Click Cloud Deploy\n\nDeploy a fully working tileserver-rs instance with sample data in minutes. No configuration needed — sample tile data is automatically downloaded on first start.\n\n| Platform | Deploy | Notes |\n|----------|--------|-------|\n| **Render** | [![Deploy on Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/vinayakkulkarni/tileserver-rs) | Uses `render.yaml` blueprint |\n| **DigitalOcean** | [![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/vinayakkulkarni/tileserver-rs/tree/main) | Uses `.do/deploy.template.yaml` |\n| **Railway** | [![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/1u-LMi) | Uses `railway.toml` config |\n| **Fly.io** | `fly launch --copy-config` | Uses `fly.toml` — see below |\n| **Docker** | `docker compose up -d` | Uses `compose.yml` (already included) |\n\n### How Sample Data Works\n\nWhen the Docker container starts with an empty `/data` directory (no tile files mounted), it automatically downloads sample data (~15 MB) from the [latest GitHub release](https://github.com/vinayakkulkarni/tileserver-rs/releases). This includes:\n\n- **Protomaps sample tiles** (PMTiles) — world basemap extract\n- **Zurich MBTiles** — detailed city extract\n- **Noto Sans fonts** — for label rendering\n- **Protomaps Light style** — ready-to-use map style\n- **Sample raster data** — COG test files\n\nTo use your own data, mount a volume at `/data`:\n\n```bash\ndocker run -d -p 8080:8080 -v /path/to/your/data:/data:ro ghcr.io/vinayakkulkarni/tileserver-rs:latest\n```\n\nSet `SAMPLE_DATA_VERSION=v2.12.1` to pin a specific release version instead of `latest`.\n\n### Deploy on Fly.io\n\n```bash\n# Install flyctl: https://fly.io/docs/flyctl/install/\nfly launch --copy-config\nfly deploy\n```\n\nThe included `fly.toml` configures auto-stop/start machines, health checks, and 512MB RAM. Add a persistent volume for your own tile data:\n\n```bash\nfly volumes create tile_data --size 10 --region iad\n```\n\n## Deployments\n\n### Documentation Site (docs.tileserver.app)\n\nThe docs site is deployed automatically via Cloudflare Pages (linked repo). Any changes to `docs/` trigger a rebuild.\n\n### Marketing Site (tileserver.app)\n\nThe marketing/landing page is deployed via GitHub Actions to a separate CF Pages project.\n\n**Setup (one-time):**\n\n1. Create a new CF Pages project named `tileserver-marketing` (Direct Upload, not linked to repo)\n2. Add custom domain `tileserver.app` to the project\n3. Add these secrets to GitHub repo settings:\n   - `CLOUDFLARE_API_TOKEN` - API token with \"Cloudflare Pages: Edit\" permission\n   - `CLOUDFLARE_ACCOUNT_ID` - Your Cloudflare account ID\n\nDeployments are triggered on push to `main` when files in `marketing/` change.\n\n## Releases\n\nThis project uses [Release Please](https://github.com/googleapis/release-please) for automated releases. The release process is fully automated based on [Conventional Commits](https://www.conventionalcommits.org/).\n\n**How it works:**\n1. Commits to `main` with conventional commit messages (`feat:`, `fix:`, etc.) trigger Release Please\n2. Release Please creates/updates a **Release PR** with version bumps and changelog\n3. Merging the Release PR creates a GitHub Release and triggers platform builds\n\n**Version bumping:**\n- `feat:` commits → minor version (0.1.0 → 0.2.0)\n- `fix:` commits → patch version (0.1.0 → 0.1.1)\n- `feat!:` or `BREAKING CHANGE:` → major version (0.1.0 → 1.0.0)\n\n**Release artifacts:**\n- GitHub Release with changelog\n- macOS ARM64 binary (`.tar.gz`)\n- macOS AMD64 (Intel) binary (`.tar.gz`)\n- Linux x86_64 + ARM64 binaries — full (with MapLibre Native) and headless variants\n- Docker image (`ghcr.io/vinayakkulkarni/tileserver-rs`) — multi-arch `linux/amd64` + `linux/arm64`\n- Homebrew formula auto-update\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guidelines.\n\n**Quick Start:**\n\n1. Fork it ([https://github.com/vinayakkulkarni/tileserver-rs/fork](https://github.com/vinayakkulkarni/tileserver-rs/fork))\n2. Clone with submodules: `git clone --recursive \u003cyour-fork-url\u003e`\n3. Create your feature branch (`git checkout -b feat/new-feature`)\n4. Commit your changes (`git commit -Sam 'feat: add feature'`)\n5. Push to the branch (`git push origin feat/new-feature`)\n6. Create a new [Pull Request](https://github.com/vinayakkulkarni/tileserver-rs/compare)\n\n**Working with Git Submodules:**\n\n```bash\n# After cloning (if you forgot --recursive)\ngit submodule update --init --recursive\n\n# After pulling changes from upstream\ngit pull\ngit submodule update --init --recursive\n\n# If clone times out (shallow clone)\ngit submodule update --init --depth 1\n```\n\n**Notes:**\n\n1. Please contribute using [GitHub Flow](https://guides.github.com/introduction/flow/)\n2. Commits \u0026 PRs will be allowed only if the commit messages \u0026 PR titles follow the [conventional commit standard](https://www.conventionalcommits.org/)\n3. Ensure your commits are signed. [Read why](https://withblue.ink/2020/05/17/how-and-why-to-sign-git-commits.html)\n\n## Author\n\n**tileserver-rs** © [Vinayak](https://vinayakkulkarni.dev), Released under the [MIT](./LICENSE) License.\n\nAuthored and maintained by Vinayak Kulkarni with help from contributors ([list](https://github.com/vinayakkulkarni/tileserver-rs/contributors)).\n\n\u003e [vinayakkulkarni.dev](https://vinayakkulkarni.dev) · GitHub [@vinayakkulkarni](https://github.com/vinayakkulkarni) · Twitter [@_vinayak_k](https://twitter.com/_vinayak_k)\n\n### Special Thanks\n\n- [tileserver-gl](https://github.com/maptiler/tileserver-gl) - Inspiration for this project\n- [MapLibre](https://maplibre.org/) - Open-source mapping library\n- [PMTiles](https://github.com/protomaps/PMTiles) - Cloud-optimized tile archive format\n- [PostGIS](https://postgis.net/) - Spatial database extension for PostgreSQL\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvinayakkulkarni%2Ftileserver-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvinayakkulkarni%2Ftileserver-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvinayakkulkarni%2Ftileserver-rs/lists"}