MBTiles and PMTiles File Sources
Martin can serve any type of tiles from PMTile
and MBTile files. To serve a file from CLI, simply put the path to the file or
the directory with *.mbtiles or *.pmtiles files. A path to PMTiles file may be a URL. For example:
You may also want to generate a config file using the --save-config my-config.yaml, and later edit
it and use it with --config my-config.yaml option.
Tip
See our tile sources explanation for a more detailed explanation on the difference between our available data sources.
Autodiscovery
For mbtiles or local pmtiles files, we support auto discovering at startup. This means that the following will discover all mbtiles and pmtiles files in the directory:
Warning
For remote PMTiles, we don't currently support auto-discovery. If you want to implement this feature, please see https://github.com/maplibre/martin/issues/2180
MBTiles Hot Reload
Martin watches directories configured under mbtiles for changes at runtime. When .mbtiles files are added, modified, or removed from a watched directory, Martin automatically updates the tile catalog — no restart required.
# Martin will watch this directory and reflect any *.mbtiles changes live
martin /path/to/mbtiles/directory
Or via config file:
The following events are handled automatically:
- File added - the new source appears in the catalog.
- File modified - the source is reloaded and its tile cache is invalidated.
Not avaliable on windows due to OS-limtations (SQLite not allowing
FILE_SHARE_DELETE). - File removed - the source is removed from the catalog.
Note
Hot reload applies to directories configured under mbtiles.paths (or passed on the CLI). Named sources listed under mbtiles.sources are snapshotted at startup and are not watched for changes.
Note
PMTiles hot reload is not yet supported. If you want to help implement it, see https://github.com/maplibre/martin/issues/2180.
MBTiles vs PMTiles
MBTiles and PMTiles are both formats for storing tiled geospatial data, but they differ in architecture, deployment, and operational characteristics.
Key Differences
- Deployment model MBTiles archives must be stored locally on the same machine as the tile server. PMTiles archives can be accessed either locally or remotely via HTTP range requests, e.g. from an object storage like S3. PMTiles allows simpler production deployment with Kubernetes, as it allows the large data file to reside in S3 and shared by multiple pods, but restricted from direct user access.
- Performance MBTiles typically provide slightly lower latency due to local access and SQLite indexing. PMTiles may introduce additional latency when accessed remotely, but this is usually mitigated by HTTP caching and CDN usage.
- Storage efficiency PMTiles archives are generally more space-efficient, typically ~10–15% smaller than equivalent MBTiles archives.
- Memory usage MBTiles relies on SQLite, which maintains an internal page cache and may increase memory usage under load. PMTiles can, in some cases, operate with lower memory overhead, depending on access patterns and caching configuration.
Serving PMTiles without a Tile Server
PMTiles archives can be served directly from HTTP range–capable storage without a dedicated tile server. This approach has several limitations:
- Unrestricted access risk Without proper access controls, clients may download large portions (or all) of an archive, leading to significant egress costs. A tile server restricts access to tile requests, but bulk extraction remains possible via many requests, which are generally easier to detect and block.
- Over-fetching PMTiles may fetch more data than strictly required per tile request to minimize the number of HTTP requests.
- Lack of source composition Direct serving does not support combining PMTiles with dynamic data sources (e.g., PostGIS) into a unified tile service. A tile server (e.g, Martin) is required for this.
- Caching behavior Cache efficiency may be reduced compared to setups with a dedicated tile server that can optimize request patterns.
The choice between MBTiles and PMTiles depends on system requirements:
- Use MBTiles for local, self-contained deployments with minimal external dependencies.
- Use PMTiles for cloud-native or distributed setups where remote access, CDN integration, or object storage is preferred.
Serving PMTiles from local file systems, http or Object Storage
The settings available for a PMTiles source depend on the backend:
For local sources, you need to provide the path or URL. For example:
The available schemes are:
file:///path/to/my/file.pmtilespath/to/my/file.pmtiles
You can also configure this via the configuration file:
For HTTP(s), you need to provide the url. For example:
The available url schemes are:
http://example.com/path.pmtileshttps://example.com/path.pmtiles
If you want more control over your requests, you can configure additional options here as such:
Available http client settings
Security options
| configuration | description | example |
|---|---|---|
allow_http |
Allow non-TLS, i.e. non-HTTPS connections Security warning: If you enable this option, attackers may be able to read the data you request |
true |
allow_invalid_certificates |
Skip certificate validation on https connections Security warning: You should think very carefully before using this method. If invalid certificates are trusted, any certificate for any site will be trusted for use. This includes expired certificates. This introduces significant vulnerabilities, and should only be used as a last resort or for testing |
true |
Connection options
| configuration | description | example |
|---|---|---|
user_agent |
User-Agent header to be used by this client | martin 1.0.0 |
randomize_addresses |
Randomize order addresses that the DNS resolution yields. This will spread the connections across more servers. |
true |
connect_timeout |
Timeout for only the connect phase of a Client | 5s |
timeout |
The timeout is applied from when the request starts connecting until the response body has finished | 10s |
pool_idle_timeout |
The pool max idle timeout | 5m |
pool_max_idle_per_host |
maximum number of idle connections per host | 10 |
http1_only |
Only use http1 connections | false |
http2_only |
Only use http2 connections | false |
http2_keep_alive_interval |
Interval for HTTP2 Ping frames should be sent to keep a connection alive. | 15s |
http2_keep_alive_timeout |
Timeout for receiving an acknowledgement of the keep-alive ping. | 15s |
http2_keep_alive_while_idle |
Enable HTTP2 keep alive pings for idle connections | true |
http2_max_frame_size |
Sets the maximum frame size to use for HTTP2. |
Proxy settings
| configuration | description | example |
|---|---|---|
proxy_url |
HTTP proxy to use for requests | http://proxy.example.com:8080 |
proxy_ca_certificate |
PEM-formatted CA certificate for proxy connections | -----BEGIN CERTIFICATE-----... -----END CERTIFICATE----- |
proxy_excludes |
List of hosts that bypass proxy | example.com, maplibre.org |
Important
Even though we name this section Amazon S3, it also works with other providers that support the S3 API, such as MinIO, Ceph, Cloudflare R2, hetzner object storage and many more.
For AWS, you need to provide the bucket name and the prefix of the object key. For example:
The available url schemes are:
s3://<bucket>/<path>s3a://<bucket>/<path>https://s3.<region>.amazonaws.com/<bucket>https://<bucket>.s3.<region>.amazonaws.comhttps://ACCOUNT_ID.r2.cloudflarestorage.com/bucket
If you want more control over your requests, you can configure additional options here as such:
Tip
All settings are also available under the aws_ prefix.
This can be useful if you want to have different cloud providers.
Available AWS S3 settings
AWS specific Authentication & Credentials
| configuration | description | example |
|---|---|---|
access_key_id |
AWS Access Key | AKIAIOSFODNN7EXAMPLE |
secret_access_key |
Secret Access Key | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
session_tokentoken |
AWS session token used for temporary credentials | IQoJb3JpZ2luX2VjEOr... |
web_identity_token_file |
Web identity token file path for AssumeRoleWithWebIdentity | /var/run/secrets/eks.amazonaws.com/serviceaccount/token |
role_arn |
Role ARN to assume with web identity token | arn:aws:iam::123456789012:role/MyWebIdentityRole |
role_session_name |
Session name for web identity assumption | my-session |
endpoint_url_sts |
Custom STS endpoint for web identity token exchange | https://sts.amazonaws.com |
AWS specific Connection & Endpoint Configuration
| configuration | description | example |
|---|---|---|
region |
AWS region Defaults to us-east-1 |
us-west-2 |
bucketbucket_name |
Bucket name | my-app-bucket |
endpointendpoint_url |
Custom S3 endpoint Defaults to regional endpoint Ensure consistency with virtual_hosted_style_requestBy default, only HTTPS schemes are enabled; enabling HTTP can expose sensitive data Local testing example: "http://localhost:4566" |
https://s3.us-west-2.amazonaws.com |
metadata_endpoint |
Instance metadata endpoint (IPv4 default http://169.254.169.254)IPv6 alternative: http://fd00:ec2::254 |
http://169.254.169.254 |
container_credentials_relative_uri |
ECS container credentials relative URI | /v2/credentials/12345678-1234-1234-1234-123456789012 |
container_credentials_full_uri |
EKS container credentials full URI | http://169.254.170.2/v2/credentials/abc123 |
container_authorization_token_file |
Authorization token file for EKS container creds | /var/run/secrets/eks.amazonaws.com/serviceaccount/token |
AWS specific Request Behavior & Fallbacks
| configuration | description | example |
|---|---|---|
imdsv1_fallback |
Fall back to IMDSv1 if IMDSv2 is not supported (useful for older kube2iam deployments) Security note: AWS recommends IMDSv2 only; IMDSv1 is vulnerable to SSRF attacks Has no effect if not using instance credentials |
true |
virtual_hosted_style_request |
Use virtual-hosted-style requests instead of path-style Endpoint must match the style Ensures correct bucket addressing for security and routing |
true |
skip_signature |
Skip signing request Security warning: Unsigned requests may expose credentials or allow tampering if endpoint is public |
true |
unsigned_payload |
Use unsigned payload option (UNSIGNED-PAYLOAD) instead of signedImpact: Checksums for request body are not computed in canonical requests, which can reduce integrity guarantees Default is signed payload with checksum |
true |
disable_tagging |
Disable tagging objects (useful if unsupported by backend) | true |
s3_express |
Enable S3 Express One Zone | true |
request_payer |
Enable S3 Requester Pays | true |
AWS Specific Object Integrity & Encryption
| configuration | description | example |
|---|---|---|
checksum |
Checksum algorithm for uploads | SHA256 |
server_side_encryption |
Type of server-side encryption:AES256 (SSE-S3)aws:kms (SSE-KMS)aws:kms:dsse (DSSE-KMS)sse-c |
AES256 |
kms_key_id |
KMS Key ID for SSE-KMS or DSSE-KMS | arn:aws:kms:us-east-1:123456789012:key/abcd-1234-efgh-5678 |
bucket_key_enabled |
Use bucket’s default KMS key (true/false) |
true |
customer_encryption_key |
Base64-encoded 256-bit key for SSE-C | MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY= |
Security options
| configuration | description | example |
|---|---|---|
allow_http |
Allow non-TLS, i.e. non-HTTPS connections Security warning: If you enable this option, attackers may be able to read the data you request |
true |
allow_invalid_certificates |
Skip certificate validation on https connections Security warning: You should think very carefully before using this method. If invalid certificates are trusted, any certificate for any site will be trusted for use. This includes expired certificates. This introduces significant vulnerabilities, and should only be used as a last resort or for testing |
true |
Connection options
| configuration | description | example |
|---|---|---|
user_agent |
User-Agent header to be used by this client | martin 1.0.0 |
randomize_addresses |
Randomize order addresses that the DNS resolution yields. This will spread the connections across more servers. |
true |
connect_timeout |
Timeout for only the connect phase of a Client | 5s |
timeout |
The timeout is applied from when the request starts connecting until the response body has finished | 10s |
pool_idle_timeout |
The pool max idle timeout | 5m |
pool_max_idle_per_host |
maximum number of idle connections per host | 10 |
http1_only |
Only use http1 connections | false |
http2_only |
Only use http2 connections | false |
http2_keep_alive_interval |
Interval for HTTP2 Ping frames should be sent to keep a connection alive. | 15s |
http2_keep_alive_timeout |
Timeout for receiving an acknowledgement of the keep-alive ping. | 15s |
http2_keep_alive_while_idle |
Enable HTTP2 keep alive pings for idle connections | true |
http2_max_frame_size |
Sets the maximum frame size to use for HTTP2. |
Proxy settings
| configuration | description | example |
|---|---|---|
proxy_url |
HTTP proxy to use for requests | http://proxy.example.com:8080 |
proxy_ca_certificate |
PEM-formatted CA certificate for proxy connections | -----BEGIN CERTIFICATE-----... -----END CERTIFICATE----- |
proxy_excludes |
List of hosts that bypass proxy | example.com, maplibre.org |
For Google Cloud, you need to provide the bucket name and the prefix of the object key. For example:
The available url scheme is:
gs://bucket/path
If you want more control over your requests, you can configure additional options here as such:
Tip
All settings are also available under the google_ prefix.
This can be useful if you want to have different cloud providers.
Available google settings
Google specific configuration
| configuration | description | example |
|---|---|---|
base_url |
Sets the base URL for communicating with GCS. If not explicitly set, it will be: 1. Derived from the service account credentials, if provided 2. Otherwise, uses the default GCS endpoint |
https://storage.googleapis.com |
service_accountservice_account_path |
Path to the service account file | some/path/to/file |
service_account_key |
The serialized service account key | {"private_key": "private_key", "private_key_id": "private_key_id", "client_email":"client_email", "disable_oauth":true} |
bucketbucket_name |
Bucket name | foobar-abc |
application_credentials |
Set the path to the application credentials file | some/path/to/file |
skip_signature |
Skip signing request | true |
Security options
| configuration | description | example |
|---|---|---|
allow_http |
Allow non-TLS, i.e. non-HTTPS connections Security warning: If you enable this option, attackers may be able to read the data you request |
true |
allow_invalid_certificates |
Skip certificate validation on https connections Security warning: You should think very carefully before using this method. If invalid certificates are trusted, any certificate for any site will be trusted for use. This includes expired certificates. This introduces significant vulnerabilities, and should only be used as a last resort or for testing |
true |
Connection options
| configuration | description | example |
|---|---|---|
user_agent |
User-Agent header to be used by this client | martin 1.0.0 |
randomize_addresses |
Randomize order addresses that the DNS resolution yields. This will spread the connections across more servers. |
true |
connect_timeout |
Timeout for only the connect phase of a Client | 5s |
timeout |
The timeout is applied from when the request starts connecting until the response body has finished | 10s |
pool_idle_timeout |
The pool max idle timeout | 5m |
pool_max_idle_per_host |
maximum number of idle connections per host | 10 |
http1_only |
Only use http1 connections | false |
http2_only |
Only use http2 connections | false |
http2_keep_alive_interval |
Interval for HTTP2 Ping frames should be sent to keep a connection alive. | 15s |
http2_keep_alive_timeout |
Timeout for receiving an acknowledgement of the keep-alive ping. | 15s |
http2_keep_alive_while_idle |
Enable HTTP2 keep alive pings for idle connections | true |
http2_max_frame_size |
Sets the maximum frame size to use for HTTP2. |
Proxy settings
| configuration | description | example |
|---|---|---|
proxy_url |
HTTP proxy to use for requests | http://proxy.example.com:8080 |
proxy_ca_certificate |
PEM-formatted CA certificate for proxy connections | -----BEGIN CERTIFICATE-----... -----END CERTIFICATE----- |
proxy_excludes |
List of hosts that bypass proxy | example.com, maplibre.org |
For Azure, you need to provide the account name, container and path. For example:
The available url schemes are:
abfs[s]://<container>/<path>(according to fsspec)abfs[s]://<file_system>@<account_name>.dfs.core.windows.net/<path>abfs[s]://<file_system>@<account_name>.dfs.fabric.microsoft.com/<path>az://<container>/<path>(according to fsspec)adl://<container>/<path>(according to fsspec)azure://<container>/<path>(custom)https://<account>.dfs.core.windows.nethttps://<account>.blob.core.windows.nethttps://<account>.blob.core.windows.net/<container>https://<account>.dfs.fabric.microsoft.comhttps://<account>.dfs.fabric.microsoft.com/<container>https://<account>.blob.fabric.microsoft.comhttps://<account>.blob.fabric.microsoft.com/<container>
If you want more control over your requests, you can configure additional options here as such:
Tip
All settings are also available under the azure_ prefix.
This can be useful if you want to have different cloud providers.
Available azure settings
Azure specific Authentication & Credentials
| configuration | description | example |
|---|---|---|
account_name |
Name of the Azure Storage account | myaccount |
access_keyaccount_keymaster_key |
Master key for accessing the storage account Security note: Keep this key secret; anyone with access can read/write all data in the account |
abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef9012 |
client_id |
Service principal client ID for OAuth authorization | 12345678-90ab-cdef-1234-567890abcdef |
client_secret |
Service principal client secret for OAuth authorization Security note: Must be kept confidential |
s3cr3tV@lu3! |
tenant_idauthority_id |
Tenant ID used in OAuth flows | abcdef12-3456-7890-abcd-ef1234567890 |
authority_host |
Authority host used in OAuth flows | https://login.microsoftonline.com/ |
sas_keysas_token |
Shared Access Signature (percent-encoded) Security note: Grants scoped access; treat as sensitive credentials |
sv=2021-06-08&ss=b&srt=sco&sp=rwdl&se=2025-12-31T23:59:00Z&sig=ABCDEF1234567890 |
bearer_tokentoken |
Bearer token for requests Security note: Token must be protected; use HTTPS |
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
identity_endpointmsi_endpoint |
Endpoint to request a managed identity token | http://169.254.169.254/metadata/identity/oauth2/token |
object_id |
Object ID for use with managed identity authentication | 12345678-90ab-cdef-1234-567890abcdef |
msi_resource_id |
Resource ID for managed identity authentication | /subscriptions/12345678-90ab-cdef-1234-567890abcdef/resourcegroups/myrg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myidentity |
federated_token_file |
File containing token for Azure AD workload identity federation | /var/run/secrets/azure/federated-token |
use_azure_cli |
Use Azure CLI for acquiring access token | true |
Azure specific Connection & Endpoint Configuration
| configuration | description | example |
|---|---|---|
endpoint |
Override endpoint used to communicate with blob storage | https://myaccount.blob.core.windows.net |
object_store_use_emulatoruse_emulator |
Use Azurite storage emulator | true |
use_fabric_endpoint |
Use Azure Fabric endpoint (account.dfs.fabric.microsoft.com) | true |
container_name |
Container name in the storage account | mycontainer |
Azure specific Request Behavior & Security Options
| configuration | description | example |
|---|---|---|
skip_signature |
Skip signing requests Security warning: Unsigned requests may expose sensitive data or allow tampering; use only in secure or local environments |
true |
disable_tagging |
Disable object tagging (useful if backend does not support it) | true |
fabric_token_service_url |
URL of Fabric token service | https://fabric-token.mycompany.com |
fabric_workload_host |
Host for Fabric workload | https://workload.fabric.mycompany.com |
fabric_session_token |
Session token for Fabric Security note: Must be protected; use HTTPS |
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
fabric_cluster_identifier |
Identifier for Fabric cluster | fabric-cluster-01 |
Security options
| configuration | description | example |
|---|---|---|
allow_http |
Allow non-TLS, i.e. non-HTTPS connections Security warning: If you enable this option, attackers may be able to read the data you request |
true |
allow_invalid_certificates |
Skip certificate validation on https connections Security warning: You should think very carefully before using this method. If invalid certificates are trusted, any certificate for any site will be trusted for use. This includes expired certificates. This introduces significant vulnerabilities, and should only be used as a last resort or for testing |
true |
Connection options
| configuration | description | example |
|---|---|---|
user_agent |
User-Agent header to be used by this client | martin 1.0.0 |
randomize_addresses |
Randomize order addresses that the DNS resolution yields. This will spread the connections across more servers. |
true |
connect_timeout |
Timeout for only the connect phase of a Client | 5s |
timeout |
The timeout is applied from when the request starts connecting until the response body has finished | 10s |
pool_idle_timeout |
The pool max idle timeout | 5m |
pool_max_idle_per_host |
maximum number of idle connections per host | 10 |
http1_only |
Only use http1 connections | false |
http2_only |
Only use http2 connections | false |
http2_keep_alive_interval |
Interval for HTTP2 Ping frames should be sent to keep a connection alive. | 15s |
http2_keep_alive_timeout |
Timeout for receiving an acknowledgement of the keep-alive ping. | 15s |
http2_keep_alive_while_idle |
Enable HTTP2 keep alive pings for idle connections | true |
http2_max_frame_size |
Sets the maximum frame size to use for HTTP2. |
Proxy settings
| configuration | description | example |
|---|---|---|
proxy_url |
HTTP proxy to use for requests | http://proxy.example.com:8080 |
proxy_ca_certificate |
PEM-formatted CA certificate for proxy connections | -----BEGIN CERTIFICATE-----... -----END CERTIFICATE----- |
proxy_excludes |
List of hosts that bypass proxy | example.com, maplibre.org |