pmtilr is a high-performance, standalone Golang reader for PMTiles. It is designed to treat a tile archive like any other service (e.g., a database or HTTP client), making it easy to integrate into existing handlers.
- High Performance: Includes fast Hilbert ID resolution for quick tile look-ups.
- In-Memory Caching: Uses otter/v2 by default, with support for custom cache implementations.
- Protocol Agnostic: Supports various range readers, including
file://,s3://, andhttp(s)://. - Observability: Built-in support for OpenTelemetry metrics and traces.
go get github.com/iwpnd/pmtilrpackage main
import (
"context"
"log"
"fmt"
"github.com/iwpnd/pmtilr"
)
func main() {
ctx := context.Background()
// Initialize source (e.g., from S3)
src, err := pmtilr.NewSource(ctx, "s3://my_bucket/tiles.pmtiles")
if err != nil {
log.Fatalf("init source: %v", err)
}
// Access metadata and headers
fmt.Println(src.Header())
fmt.Println(src.Meta())
// Fetch a specific tile
tile, err := src.Tile(ctx, 14, 8943, 5372)
if err != nil {
log.Fatalf("fetch tile: %v", err)
}
log.Printf("tile size: %d bytes", len(tile))
}In addition to Tile(), Header(), and Meta(), the Source interface provides:
TileJSON(host string) TileJSON: generates a TileJSON v2 or v3 document from archive metadata (v3 withvector_layersfor MVT/MLT types).Close(): releases underlying resources (cache, connections).
If a tile is not present in the archive, Tile() returns pmtilr.ErrTileNotFound.
The TileType enum identifies the format of tiles in the archive:
| Constant | Value | Extension | Content Type |
|---|---|---|---|
TileTypeMVT |
1 | .mvt |
application/x-protobuf |
TileTypePNG |
2 | .png |
image/png |
TileTypeJPEG |
3 | .jpeg |
image/jpeg |
TileTypeWebp |
4 | .webp |
image/webp |
TileTypeAvif |
5 | .avif |
image/avif |
TileTypeMLT |
6 | .mlt |
application/vnd.maplibre-vector-tile |
Helper methods:
Ext()returns the file extension (e.g..mvt).ToContentType()returns the HTTP Content-Type string.IsVector()returnstruefor MVT and MLT types.
pmtilr ships with four built-in RangeReader implementations:
NewFileRangeReader(path): reads from local files.NewMMapFileRangeReader(path): memory-mapped local file access for lower latency on repeated reads.NewHTTPRangeReader(host, ...opts): HTTP/HTTPS range requests viarip.Client.NewS3RangeReader(bucket, key, client): S3 range requests via the AWS SDK.
Pass a custom reader with WithRangeReader(reader) to override the default, or implement the RangeReader interface for any backend.
pmtilr supports OpenTelemetry for both metrics and traces. By default, it uses the global OpenTelemetry provider. You can customize this behavior using the following options:
- use
WithTracerProvider(provider trace.TroperProvider)to pass a custom tracer provider for tracing. - use
WithMeterProvider(provider metric.MeterProvider)to pass a custom meter provider for metrics. - use
WithDisableInstrumentation()to completely disable all tracing and metrics on thepmtilr.Source.
The following metrics are tracked:
pmtilr.source.tile.request.duration: Histogram of tile request durations (includessuccessattribute).pmtilr.directory.cache.request.duration: Histogram of cache request durations (includesoperationattribute).pmtilr.directory.cache.hits: Counter of cache hits (includescachedattribute).pmtilr.repository.directory.request.duration: Histogram of directory lookup request durations (includessuccessattribute).pmtilr.repository.directory.request.shared: Counter of requests shared via singleflight (includessharedandsuccessattributes).
- Go 1.26+
- Docker (for S3 integration tests via MinIO)
make test # run tests with verbose output
make lint # run golangci-lint
make dev-up # start MinIO dev environment
make dev-down # stop MinIO dev environmentThis repository uses pre-commit and enforces conventional commits with gitlint. Install with:
pre-commit installCommits follow Conventional Commits and are validated by gitlint. Releases are automated via semantic-release.