Documentation

MapLibre 6

MapLibre v6 loads vector tiles in a Web Worker (maplibre-gl-worker.mjs, which imports maplibre-gl-shared.mjs). Under Next.js (Turbopack and webpack), Vite, Rollup, and similar bundlers, that worker URL is not resolved correctly unless the host calls setWorkerUrl before the first map mounts.

If you skip this step the map canvas often appears but basemap tiles never load. A blank or grey shell with no tile network requests almost always means the worker URL is missing or pointing at the wrong path.

Next.js

You need two things:

  1. Serve the worker files from public/ (same-origin URLs).
  2. Call setWorkerUrl once on the client before any PlatformMap / BaseMap.

1. Copy workers on dev / build

Use the same approach as demo-next/scripts/copy-maplibre-workers.mjs:

// scripts/copy-maplibre-workers.mjs
import { copyFileSync, mkdirSync, existsSync } from 'node:fs'
import path from 'node:path'
import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url'

const require = createRequire(import.meta.url)
const appRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')

const maplibrePackageJson = require.resolve('maplibre-gl/package.json', {
  paths: [appRoot],
})
const maplibreDist = path.join(path.dirname(maplibrePackageJson), 'dist')
const publicDir = path.join(appRoot, 'public', 'maplibre')
const files = ['maplibre-gl-worker.mjs', 'maplibre-gl-shared.mjs']

mkdirSync(publicDir, { recursive: true })

for (const file of files) {
  const source = path.join(maplibreDist, file)
  if (!existsSync(source)) {
    throw new Error(`Missing MapLibre worker asset: ${source}`)
  }
  copyFileSync(source, path.join(publicDir, file))
}
{
  "scripts": {
    "predev": "node scripts/copy-maplibre-workers.mjs",
    "prebuild": "node scripts/copy-maplibre-workers.mjs",
    "dev": "next dev",
    "build": "next build"
  }
}

Add public/maplibre/ to .gitignore. Optional: also run the script from postinstall if CI does not call prebuild.

2. Point MapLibre at the worker (client only)

// components/maplibre-worker.ts
'use client'

import { setWorkerUrl } from 'maplibre-gl'

let configured = false

export function ensureMapLibreWorker() {
  if (configured || typeof window === 'undefined') return
  setWorkerUrl('/maplibre/maplibre-gl-worker.mjs')
  configured = true
}

ensureMapLibreWorker()

Import that module once, before any map mounts — for example at the top of your map client entry.

'use client'
import '@/components/maplibre-worker'
// then render PlatformMap

Vite

import { setWorkerUrl } from 'maplibre-gl'
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url'

setWorkerUrl(workerUrl)

If TypeScript complains about the import:

// vite-env.d.ts
declare module '*?worker&url' {
  const workerUrl: string
  export default workerUrl
}

Upgrading from MapLibre 5

Checklist

StepTypeDefaultDescription
1deps—Bump maplibre-gl to ^6.9.0 (or at least ≥ 6.4.1) and @infoplaza/platform to a MapLibre 6 release.
2deps—Ensure react-map-gl is ≥ 8.1.2 (this package pins ^8.1.3). Older 8.1.0/8.1.1 crash on map.transform.
3deps—This package uses @deck.gl/maplibre (not @deck.gl/mapbox) with deck.gl 9.4+ so weather overlays work on MapLibre 6.
4host—Add the worker copy + setWorkerUrl steps (Next) or the Vite snippet.
5css—Keep CSS imports as maplibre-gl/dist/maplibre-gl.css — path unchanged.
6api—Platform APIs (Providers, BaseMap, auth route, timeseries/ensemble) stay the same for this upgrade.