PMTiles DataStore¶
The PMTiles DataStore provides read and query access to Protomaps PMTiles format files, both local and remote, within the GeoTools framework.
PMTiles is a cloud-optimized single-file archive format for pyramids of tiled data. PMTiles is designed for efficient random access to tiles, eliminating the need for a tile server and enabling direct hosting of tile data on object storage like S3 or Azure Blob Storage. The format is particularly well-suited for hosting vector tiles and other tiled geospatial data.
Maven:
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-pmtiles</artifactId>
<version>${geotools.version}</version>
</dependency>
Features¶
Local File Access: Read PMTiles files from your local filesystem
Remote File Access: Access PMTiles files via HTTP/HTTPS URLs
- Cloud Storage Support: Direct access to PMTiles files on:
AWS S3 and S3-compatible storage (MinIO, LocalStack)
Azure Blob Storage
Google Cloud Storage
HTTP Authentication: Support for multiple authentication methods (Basic Auth, Bearer Token, API Key)
Cloud Storage Authentication: Built-in authentication support for AWS S3, Azure Blob Storage, and Google Cloud Storage
Spatial Queries: Full support for spatial filters (intersects, contains, within, etc.)
Attribute Filters: Filter data based on attribute values
Vector Tiles: Accesses Mapbox Vector Tile (MVT) data stored in PMTiles format
Efficient Random Access: Leverages PMTiles’ optimized structure for fast tile retrieval
Memory Caching: Configurable in-memory caching of byte ranges for performance optimization
How It Works¶
Under the hood, this DataStore uses the Tileverse PMTiles and Range Reader libraries to provide flexible, high-performance access to PMTiles files. The implementation:
Uses the Range Reader library to access PMTiles files from various sources (local, HTTP, S3, Azure, GCS)
Reads the PMTiles header and directory structure for efficient tile lookups
Decodes Mapbox Vector Tiles (MVT) from the PMTiles archive
Translates GeoTools queries to tile requests based on spatial bounds and zoom levels
Provides a standard GeoTools DataStore interface for vector tile data
The Range Reader library provides a unified interface for reading byte ranges from different storage backends, with support for:
Decorators: Composable caching and optimization layers
Authentication: Flexible credential management for cloud storage and HTTP
Performance: In-memory caching of byte ranges
Usage¶
Basic Example (Local File)¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "file:/path/to/data.pmtiles");
DataStore store = DataStoreFinder.getDataStore(params);
String[] typeNames = store.getTypeNames();
SimpleFeatureSource source = store.getFeatureSource(typeNames[0]);
// Read all features
SimpleFeatureCollection features = source.getFeatures();
// Or apply a spatial filter
FilterFactory ff = CommonFactoryFinder.getFilterFactory();
Filter filter = ff.intersects(
ff.property("geometry"),
ff.literal(geometryFactory.toGeometry(new Envelope(-122.5, -122.3, 37.7, 37.9)))
);
SimpleFeatureCollection filtered = source.getFeatures(filter);
Remote PMTiles File (HTTP)¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "https://example.com/tiles/data.pmtiles");
DataStore store = DataStoreFinder.getDataStore(params);
Remote PMTiles with HTTP Basic Authentication¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "https://example.com/secure/data.pmtiles");
params.put("storage.http.username", "myuser");
params.put("storage.http.password", "mypassword");
DataStore store = DataStoreFinder.getDataStore(params);
Remote PMTiles with Bearer Token¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "https://example.com/secure/data.pmtiles");
params.put("storage.http.bearer-token", "your-bearer-token");
DataStore store = DataStoreFinder.getDataStore(params);
AWS S3¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "s3://my-bucket/tiles/data.pmtiles");
params.put("storage.s3.region", "us-west-2");
params.put("storage.s3.aws-access-key-id", "AKIAIOSFODNN7EXAMPLE");
params.put("storage.s3.aws-secret-access-key", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
DataStore store = DataStoreFinder.getDataStore(params);
Azure Blob Storage¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "https://myaccount.blob.core.windows.net/container/tiles/data.pmtiles");
params.put("storage.azure.account-key", "BASE64_ENCODED_KEY");
DataStore store = DataStoreFinder.getDataStore(params);
Google Cloud Storage¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "https://storage.googleapis.com/my-bucket/tiles/data.pmtiles");
params.put("storage.gcs.project-id", "my-project");
// Enable default credentials chain (looks for application default credentials)
params.put("storage.gcs.default-credentials-chain", true);
DataStore store = DataStoreFinder.getDataStore(params);
With Caching and Optimization¶
Map<String, Object> params = new HashMap<>();
params.put("pmtiles", "s3://my-bucket/tiles/data.pmtiles");
params.put("storage.s3.region", "us-west-2");
// Enable in-memory caching
params.put("storage.caching.enabled", true);
DataStore store = DataStoreFinder.getDataStore(params);
Parameters¶
Core Parameters¶
Parameter |
Type |
Required |
Description |
|---|---|---|---|
pmtiles |
String |
Yes |
URI to a PMTiles file. Supports local files (file://), HTTP/HTTPS, AWS S3 (s3://), Azure Blob Storage, and Google Cloud Storage URLs |
namespace |
String |
No |
Namespace URI to use for features |
storage.provider |
String |
No |
Force a specific storage provider (file, http, s3, azure, gcs) |
HTTP/HTTPS Parameters¶
Parameter |
Type |
Description |
|---|---|---|
storage.http.timeout-millis |
Integer |
HTTP connection timeout in milliseconds |
storage.http.trust-all-certificates |
Boolean |
Trust all SSL/TLS certificates (use with caution, for development only) |
storage.http.username |
String |
HTTP Basic Authentication username |
storage.http.password |
String |
HTTP Basic Authentication password |
storage.http.bearer-token |
String |
Bearer token for token-based authentication |
storage.http.api-key-headername |
String |
Custom header name for API key authentication |
storage.http.api-key |
String |
API key value |
storage.http.api-key-value-prefix |
String |
Optional prefix for API key value (e.g., “Bearer “ or “ApiKey “) |
Memory Caching Parameters¶
Parameter |
Type |
Description |
|---|---|---|
storage.caching.enabled |
Boolean |
Enable in-memory caching of byte ranges (default: false) |
AWS S3 Parameters¶
Parameter |
Type |
Description |
|---|---|---|
storage.s3.region |
String |
AWS region (e.g., us-west-2) |
storage.s3.endpoint |
String |
Custom S3 endpoint URL for S3-compatible services (e.g., http://localhost:9000 for MinIO); lets an s3://bucket/key URI target a non-AWS service |
storage.s3.aws-access-key-id |
String |
AWS access key ID |
storage.s3.aws-secret-access-key |
String |
AWS secret access key |
storage.s3.anonymous |
Boolean |
Anonymous (unsigned) access for public buckets (default: false) |
storage.s3.requester-pays |
Boolean |
Add the requester-pays header to bill the requester rather than the bucket owner (default: false) |
storage.s3.use-default-credentials-provider |
Boolean |
Use AWS default credentials provider chain (default: false) |
storage.s3.default-credentials-profile |
String |
AWS credentials profile name to use |
storage.s3.force-path-style |
Boolean |
Enable S3 path style access for S3-compatible services like MinIO; defaults to true when an endpoint override is in effect |
Azure Blob Storage Parameters¶
Parameter |
Type |
Description |
|---|---|---|
storage.azure.blob-name |
String |
Set the blob name if the endpoint points to the account URL |
storage.azure.account-key |
String |
Azure storage account key |
storage.azure.sas-token |
String |
Shared Access Signature (SAS) token |
storage.azure.connection-string |
String |
Full Azure Storage connection string (common for Azurite / local development) |
storage.azure.endpoint |
String |
Custom Blob service endpoint URL; lets a short-form az://account/container URI target an emulator, sovereign cloud, or custom domain |
storage.azure.anonymous |
Boolean |
Anonymous access for public containers (default: false) |
storage.azure.max-retries |
Integer |
Maximum number of retry attempts for failed requests (default: 3) |
storage.azure.retry-delay |
String |
Initial retry backoff delay, ISO-8601 duration (default: PT4S) |
storage.azure.max-retry-delay |
String |
Maximum retry backoff delay, ISO-8601 duration (default: PT2M) |
storage.azure.try-timeout |
String |
Per-attempt request timeout, ISO-8601 duration (default: PT60S) |
Google Cloud Storage Parameters¶
Parameter |
Type |
Description |
|---|---|---|
storage.gcs.project-id |
String |
Google Cloud project ID |
storage.gcs.quota-project-id |
String |
Quota project ID for billing purposes |
storage.gcs.user-project |
String |
Billing project for Requester Pays buckets |
storage.gcs.default-credentials-chain |
Boolean |
Use default application credentials chain (default: false) |
storage.gcs.endpoint |
String |
Custom GCS endpoint URL for emulators (e.g., http://localhost:4443 for fake-gcs-server); full URL, not a bare hostname |
Performance Optimization¶
Memory Caching Architecture¶
For optimal performance with cloud storage, enable in-memory caching:
Client Request → Memory Cache (fast, configurable size)
→ RangeReader (S3/Azure/HTTP/File)
PMTiles is optimized for byte-range requests natively; enabling the memory cache is sufficient.
Recommended Settings for Cloud Storage¶
// Enable memory cache for optimal cloud storage performance
params.put("storage.caching.enabled", true);
PMTiles Format¶
PMTiles is designed for efficient cloud-native tile serving:
Single File Archive: All tiles in one file, simplifying deployment
Cloud-Optimized: Optimized for HTTP range requests
Efficient Directory: Hierarchical directory structure for fast tile lookups
Compression: Supports gzip and brotli compression
Metadata: JSON metadata describing tile content and attribution
Implementation Notes¶
The DataStore is read-only (no writing capabilities)
All RangeReader implementations are thread-safe for concurrent server use
Proper resource management: Use try-with-resources or call dispose() on the DataStore
The PMTiles directory is cached in memory for fast tile lookups
Tile data is decoded on-demand as features are requested
Current Limitations¶
Currently read-only (no writing capabilities)
Requires PMTiles files to contain Mapbox Vector Tiles (MVT)
This module is unsupported and still under development
Requirements¶
Java 17 or higher
GeoTools 34 or later
Resources¶
Protomaps.com - PMTiles hosting and tools