Skip to content

Migration Guide

Use this guide to update an existing Martin setup after a major release. See the changelog for other changes.

From 1.x to 2.0

Martin 2.0 removes deprecated options and changes several defaults. Existing routes and legacy URL redirects remain available when their Cargo features are enabled. The configuration file format is unchanged apart from the keys and substitution syntax below.

Review the database versions, martin cp, the terminal dashboard, the web UI, archive tile caching, cache keys and the MBTiles schema even if 1.x showed no deprecation warnings.

martin-cp is now martin cp

Replace martin-cp with martin cp in scripts and commands. The copy options and configuration file still apply, subject to the changes below. Release tarballs, Docker and Homebrew no longer include a separate martin-cp binary. The mbtiles binary keeps its name and loses its hidden --verbose flag, which did nothing. Use RUST_LOG to control logging.

# 1.x
martin-cp --output-file tileset.mbtiles --source my_source postgres://postgres@localhost/db
# 2.0
martin cp --output-file tileset.mbtiles --source my_source postgres://postgres@localhost/db

See Generating Tiles in Bulk.

The terminal dashboard is on by default

Remove --tui. Martin now shows the dashboard when stdout is a terminal. Use --no-tui for the log stream instead. When stdout is not a terminal, as in a service or pipe, Martin keeps the plain log automatically.

The dashboard's log pane follows RUST_LOG_FORMAT and defaults to pretty.

See Terminal dashboard.

The web UI is served to localhost by default

--webui now defaults to enable instead of disable. Loopback clients get the web UI at /. Other clients get the same text response as with disable. Set --webui disable or web_ui: disable to restore the 1.x behavior. --webui enable-for-all is unchanged.

Reverse proxies and containers

Martin checks the TCP peer address, ignoring forwarded headers. A proxy connecting over loopback exposes the web UI to its clients unless you set --webui disable. With Docker bridge networking, connections from the host are not loopback. Use --webui enable-for-all to expose the UI as described in Running with Docker.

PMTiles and MBTiles tiles attach the Cache-Control header by default

When no cache_control is configured, PMTiles and MBTiles tiles have max-age=0, stale-while-revalidate=86400 by default. 1.x sent no Cache-Control header for them. This means that a returning visitor's browser can now use tiles which are assumed to be static and only checks them with the server in the background. A server side rewritten archive may only show up on the visitor's next load due to invalidation if the tiles are cached on the client and the stale-while-revalidate-check in the background suggests that the tiles martin offers are stale.

Set cache_control: no-cache for browsers to check before drawing it

A top-level or per-source cache_control replaces this default.

cache_control: no-cache

See Tile Sources.

PostgreSQL sources need PostgreSQL 15 and PostGIS 3.5

Martin 2.0 refuses to start against older databases, where 1.x accepted PostgreSQL 11 and PostGIS 3.0. Upgrade the database before upgrading Martin.

Requirement 1.x 2.0
PostgreSQL 11 15
PostGIS 3.0 3.5

PostgreSQL 12, 13 and 14 are end-of-life, and PostGIS 3.5 fixes geometry that older versions hid on some zoom levels.

PostgreSQL settings come from the command line or the configuration file

Replace these environment variables with command-line options or configuration keys.

1.x environment variable 2.0 command line 2.0 configuration file
DATABASE_URL the connection string as a positional argument postgres.connection_string
DEFAULT_SRID --default-srid postgres.default_srid
PGSSLCERT --ssl-cert postgres.ssl_cert
PGSSLKEY --ssl-key postgres.ssl_key
PGSSLROOTCERT --ca-root-file postgres.ssl_root_cert

Martin ignores the old variables. Starting with only DATABASE_URL exported fails with No tile sources found. On grids with a coordinate reference system, auto-discovered tables with SRID 0 are skipped with a warning unless you set default_srid. Simple grids use SRID 0 and need no fallback. Client certificates previously supplied through PGSSLCERT are not sent unless you configure them explicitly.

# 1.x
export DATABASE_URL=postgres://postgres@localhost/db
martin
# 2.0
martin postgres://postgres@localhost/db

To keep using an environment variable, reference it in the configuration file. See Configuration for the substitution syntax.

postgres:
  connection_string: ${DATABASE_URL}

With Docker, pass the connection string after the image name or pass the variable to a mounted configuration file.

# 1.x
docker run -p 3000:3000 -e DATABASE_URL=postgres://postgres@postgres.example.org/db ghcr.io/maplibre/martin
# 2.0
docker run -p 3000:3000 ghcr.io/maplibre/martin postgres://postgres@postgres.example.org/db
# 2.0, keeping the variable
docker run -p 3000:3000 -e DATABASE_URL -v "$PWD/config.yaml:/config.yaml" ghcr.io/maplibre/martin --config /config.yaml

See Environment Variables and SSL Connections.

Default values in the configuration file use ${VAR:-default}

Replace ${VAR:default} with ${VAR:-default}. The old syntax fails at startup with a substitution error.

# 1.x
connection_string: ${DATABASE_URL:postgres://postgres@localhost/db}
# 2.0
connection_string: ${DATABASE_URL:-postgres://postgres@localhost/db}

Cache sizes have one spelling

Replace the old cache keys below. Martin reports them as unrecognized and ignores their values, so a cache can fall back to its default size. Most migrated silently in 1.x unless both spellings were set. pmtiles.dir_cache_size_mb was already ignored with a deprecation warning.

1.x 2.0
cache_size_mb cache.size_mb
tile_cache_size_mb cache.tile_size_mb
fonts.cache_size_mb fonts.cache.size_mb
sprites.cache_size_mb sprites.cache.size_mb
pmtiles.directory_cache_size_mb pmtiles.directory_cache.size_mb
pmtiles.dir_cache_size_mb pmtiles.directory_cache.size_mb
# 1.x
cache_size_mb: 1024
pmtiles:
  directory_cache_size_mb: 128
# 2.0
cache:
  size_mb: 1024
pmtiles:
  directory_cache:
    size_mb: 128

See the cache section of the full configuration.

Object storage options use their object_store names

Replace these legacy settings with configuration keys directly under pmtiles or cog. Old environment variables are ignored silently. Old configuration keys are reported as unrecognized.

1.x 2.0
AWS_S3_FORCE_PATH_STYLE=1, aws_s3_force_path_style: true, force_path_style: true virtual_hosted_style_request: false (the meaning is inverted)
AWS_SKIP_CREDENTIALS=1, AWS_NO_CREDENTIALS=1, aws_skip_credentials: true, aws_no_credentials: true skip_signature: true
AWS_PROFILE=name profile: name

The standard AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN and AWS_REGION variables still work.

pmtiles:
  skip_signature: true
  sources:
    tiles: s3://public-bucket/tiles.pmtiles

A public bucket previously accessed with AWS_SKIP_CREDENTIALS=1 can now fail during instance credential lookup outside AWS. The error does not name the removed variable. Set skip_signature: true for unsigned requests. This requires a configuration file, including when replacing a command such as martin s3://public-bucket/tiles.pmtiles.

See Remote files and prefixes.

Plain http:// sources must opt in

Set allow_http: true in the configuration file for PMTiles or COG sources using http://. It now defaults to false, so plain HTTP sources are refused at startup with an error naming the option. HTTPS URLs are unaffected.

pmtiles:
  allow_http: true
  sources:
    tiles: http://tiles.internal/tiles.pmtiles

The bare command martin http://tiles.internal/tiles.pmtiles needs a configuration file to enable allow_http.

See HTTP(S).

Normalized MBTiles files use tiles_shallow and tiles_data

New files created with mbtiles copy --dst-type normalized or martin cp --mbtiles-type normalized use tiles_shallow and tiles_data, the layout Planetiler writes. This is also the martin cp default. Both layouts expose the standard tiles view, so readers using that view keep working.

Existing map and images files remain readable. Copying one to a new file without --dst-type preserves its schema. The CLI no longer offers that layout when converting from another schema.

New normalized files have no per-tile hashes or tiles_with_hash view. mbtiles validate checks tile references instead. agg_tiles_hash still covers the content. Choose flat-with-hash if you need per-tile hashes.

See MBTiles Schemas.

Rendering is not part of the default build

For server-side style rendering on Linux, use the -full Docker image (:latest-full or :<version>-full), a -full Linux-gnu tarball, or cargo install martin --features rendering. The default builds no longer include rendering.

Rendering is stable as of 2.0. The configuration is unchanged. Set styles.rendering: true to enable it, or keep your existing rendering options.

See Server-side raster tile rendering and Installation.

x86_64 binaries require an x86-64-v3 CPU

The prebuilt x86_64 binaries, Debian package and Docker images are built for the x86-64-v3 feature level (AVX2, BMI2, FMA; Intel Haswell / AMD Excavator, 2015 or newer). On older CPUs they fail with an illegal instruction error. aarch64 builds are unaffected.

To run Martin on an older CPU, use the martin-x86_64-unknown-linux-musl-legacycpu.tar.gz release asset or the :latest-legacycpu Docker image, or build it from source without -C target-cpu=x86-64-v3.

Cargo features were merged

If you build Martin or martin-core yourself with --features or --no-default-features, rename the features:

1.x features 2.0 feature
fonts, sprites, styles resources
hillshade, contour, geojson processing
mlt none, always enabled
unstable-cog cog

All are enabled by default, so default builds, release binaries and Docker images keep their features and now also serve COG sources. metrics, webui, tui, lambda and the source features postgres, pmtiles, mbtiles and passthrough keep their names.

# 1.x
cargo install martin --locked --no-default-features --features postgres,fonts,sprites,styles
# 2.0
cargo install martin --locked --no-default-features --features postgres,resources

For users of the crates

  • In martin-tile-utils, TileCoord fields are private. Construct coordinates with TileCoord::new_checked or TileCoord::new_unchecked and read them with z(), x() and y().
  • TileData is now bytes::Bytes instead of Vec<u8>, including data returned by mbtiles::Mbtiles::stream_tiles.
  • In martin-core, Source is no longer dyn compatible. Its clone_source and cancel_registry methods were removed. Sources use the closed AnySource enum, and BoxedSource is now Arc<AnySource>. With the postgres feature, call cancel_registry() on AnySource or BoxedSource.
  • CatalogSourceEntry gained tile_grid, PostgresSource::new requires the source's TileGrid, and CogError::TooManyImages was removed.
  • mbtiles::Mbtiles::insert_tiles now requires tile data to implement Sync. The copier writes the normalized layout described above.

See the martin-core and mbtiles changelogs for crate releases.