Documentation

Overview

A Corviont stack runs maps, routing, and search fully offline on your device. Once started, your application talks to a single local HTTP entrypoint — no external map APIs required.

The stack includes:

  • Vector tiles: served locally via the go-pmtiles server.
  • Routing API: an offline routing service based on Valhalla.
  • Geocoder API: lightweight forward and reverse geocoding backed by SQLite.
  • Optional UI: a MapLibre frontend wired to the local endpoints.

Requirements

OS & architecture

  • 64-bit OS is required.
  • Supported architectures: linux/amd64 and linux/arm64.
  • Verified on Ubuntu and Raspberry Pi OS (64-bit).

To check your architecture on Linux / Raspberry Pi:

uname -m 
# x86_64 or aarch64  => OK

getconf LONG_BIT
# 64 => OK 

Docker & Docker Compose

  • Docker installed and running, including Docker Compose.

Quick sanity check:

# Both should output a version
docker version
docker compose version

Getting started

The fastest way to get a Corviont stack running today is the Monaco demo published as a Docker Compose stack on GitHub: github.com/corviont/monaco-demo.

1. Clone the demo

git clone https://github.com/corviont/monaco-demo.git
cd monaco-demo

2. Choose the port

Set the port you want the stack to listen on (3000 is the default used in this documentation). This creates a .env file that Docker Compose will pick up automatically:

echo "CORVIONT_PORT=3000" > .env

3. (Optional) Enable CORS

If you want to call Corviont APIs from a browser app running on a different origin (e.g. http://localhost:3001), append this to your .env:

# Supports a comma-separated allowlist (e.g. http://localhost:3001,http://localhost:5173) or "*" to allow any origin
echo "CORVIONT_CORS_ALLOWED_ORIGINS=http://localhost:3001" >> .env

4. Start the stack

Start all services in the background. On some Linux / Raspberry Pi setups you may need to prefix commands with sudo.

docker compose up -d

Once the stack starts, open http://localhost:3000/ in your browser. You should see:

  • A Monaco map rendered
  • Search results when typing (e.g. cafe)
  • A route line + turn-by-turn directions after selecting two points in Directions mode
Need Corviont beyond Monaco (your region + deployment)? Join Waitlist.

5. Stop the stack

To stop all services and free ports:

docker compose down
See the FAQ below for common issues around missing CORVIONT_PORT or Docker permissions.

Examples

A running stack exposes a single HTTP entrypoint, for example http://localhost:3000. All examples below assume that base URL.

Use case 1: Render a map (managed style)

Use this if you want the “it just works” path. Corviont provides a ready-to-use MapLibre style based on OpenMapTiles that already references the correct tiles and assets for the dataset version.

<html>

<head>
  <!--
	NOTE: For simplicity, this example uses unpkg for MapLibre.
    Corviont deployments bundle MapLibre (and all other assets) locally for fully offline use.
  -->
  <script src='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js'></script>
  <link href='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css' rel='stylesheet' />
  <style>
    html, body, #map { height: 100%; width: 100%; padding: 0;  margin: 0; }
  </style>
</head>

<body>
  <div id="map"></div>
  <script type="text/javascript">
    async function initMap() {
      // dataset.json provides the active dataset version (used for versioned asset URLs)
      const dataset = await (await fetch("/dataset.json")).json();

      new maplibregl.Map({
        container: "map",
        center: [7.42, 43.732], // Monaco
        zoom: 15,
        // Corviont styles use relative URLs; MapLibre requires absolute URLs.
        // rewrite any relative request to an absolute one.
        transformRequest: (url) => ({ url: /^https?:\/\//i.test(url) ? url : `${window.location.origin}/${url}` }),
      }).setStyle(`map-style/${dataset.version}.json`, {
        // make sprite/glyph URLs absolute (style contains relative paths)
        transformStyle: (_, next) => ({
          ...next,
          sprite: `${window.location.origin}/${next.sprite}`,
          glyphs: `${window.location.origin}/${next.glyphs}`,
        })
      });
    }

    initMap().catch(console.error);
  </script>
</body>

</html>

Use case 2: Render a map (custom style)

Use this if you want a custom style (based on Corviont’s default, another OpenMapTiles style, or something you build from scratch) wired directly to the raw vector tiles.

<html>

<head>
  <!--
	NOTE: For simplicity, this example uses unpkg for MapLibre.
    Corviont deployments bundle MapLibre (and all other assets) locally for fully offline use.
  -->
  <script src='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js'></script>
  <link href='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css' rel='stylesheet' />
  <style>
    html, body, #map { height: 100%; width: 100%; padding: 0;  margin: 0; }
  </style>
</head>

<body>
  <div id="map"></div>
  <script type="text/javascript">
    async function initMap() {
      const dataset = await (await fetch("/dataset.json")).json();

      new maplibregl.Map({
        container: "map",
        center: [7.42, 43.732],
        zoom: 15,
        style: {
          version: 8,
          sources: {
            corviont: {
              type: "vector",
              tiles: [`${window.location.origin}/tiles/${dataset.version}/{z}/{x}/{y}.mvt`]
            }
          },
          layers: [
            // minimal example, displays roads only
            { id: "roads", type: "line", source: "corviont", "source-layer": "transportation" }
          ]
        }
      });
    }

    initMap().catch(console.error);
  </script>
</body>

</html>

Use case 3: Routing

Use this to draw routes in your UI or power navigation features.

const input = {
	locations: [{ "lat": 43.7336, "lon": 7.4200 }, { "lat": 43.7370, "lon": 7.4270 }],
	costing: "auto",
	directions_options: { units: "kilometers" },
	// Easiest to render in MapLibre: OSRM response + GeoJSON route geometry
	format: 'osrm',
	shape_format: "geojson"
};

const url = "/router/route?json=" + encodeURIComponent(JSON.stringify(input));
const output = await (await fetch(url)).json();
/router proxies the Valhalla API (see the full Valhalla API overview). In the current Corviont stack, only /router/route is officially supported. Other Valhalla endpoints may be reachable but should be considered experimental.

Use case 4: Search

Use this for a search box (forward geocoding).

// default limit is 5, max is 10 
const output = await (await fetch('/geocoder/search?query=cafe&limit=7')).json();
// outputs [{"id":806,"type":"poi","name":"Loga Café","country":"MC","city":"","street":"Boulevard des Moulins","housenumber":"","postcode":"98000","lat":43.7434398,"lon":7.4283176}, ...]
console.log(output);

Use case 5: Reverse geocoding

Use this for “tap to get address” or “what’s here?” interactions.

// default limit is 5, max is 10 
const output = await (await fetch('/geocoder/reverse?lat=43.7434398&lon=7.4283176&limit=10&radius_m=100')).json();
// outputs [{"id":806,"type":"poi","name":"Loga Café","country":"MC","city":"","street":"Boulevard des Moulins","housenumber":"","postcode":"98000","lat":43.7434398,"lon":7.4283176}, ...]
console.log(output);

Troubleshooting & FAQ

CORVIONT_PORT is missing

When running the stack, make sure you have a .env file in the root of the cloned repository and that it contains:

CORVIONT_PORT=3000

Then restart the stack:

docker compose down
docker compose up -d
I see no matching manifest for linux/arm/v7

Images are built only for 64-bit architectures (linux/amd64 and linux/arm64). If your system is 32-bit (for example armv7l), Docker cannot pull these images.

Check your architecture:

uname -m 
# x86_64 or aarch64  => OK

getconf LONG_BIT
# 64 => OK 
Docker says permission denied for /var/run/docker.sock

On some Linux / Raspberry Pi setups, Docker requires root access. You can either:

  1. Add your user to the docker group (recommended):
    sudo groupadd docker 2>/dev/null || true
    sudo usermod -aG docker "$USER"
    # Log out and log back in so the new group is applied
    groups   # should now include "docker"

    Then retry:

    docker compose up -d
  2. Or prefix commands with sudo:
    sudo docker compose up -d
Does the stack require internet access once it’s running?

After the initial image and data download, Corviont runs fully offline: tiles, routing, and geocoding are all served from containers on your host or device. Your UI talks only to the local HTTP entrypoint.

Where can I find an example deployment?

The Monaco demo shows one way to run a Corviont stack locally: github.com/corviont/monaco-demo.

Stores image for doc - does not display anywhere

Showcase image
Built on Unicorn Platform