Web地図で大量のベクターデータをスムーズに表示しようとすると、従来は膨大な数のファイルを出力して管理したり、動的にタイルを生成する専用サーバーやデータベースを構築したりする必要があり、インフラの運用負荷やコストが大きな課題となっていました。
こうした悩みを解決する新しいアプローチとして注目されているのが、MapLibre GL JSとPMTilesを組み合わせた「タイルサーバーレス」なWeb地図構築です。専用のバックエンドを運用することなく、静的なストレージから直接必要なデータだけを取得してレスポンス良く地図を描画できるため、システムの構成を驚くほどシンプルにできます。
複雑なサーバー構築を避け、低コストでメンテナンス性の高いWeb地図を実現したい方は、ぜひ参考にしてみてください!
あわせて読みたい


PMTilesとMapLibre GL JSで実現する「タイルサーバーレス」地図とは?

ウェブ地図で大量のベクターデータやラスターデータを快適に表示するには、地図データを細かい正方形の「タイル」に分割して配信する仕組みが欠かせません。従来は、タイルを多数のファイルとして保存して配信したり、データベースから必要なタイルを動的に生成するタイルサーバーを構築したりする方法が一般的でした。
しかし、PMTilesとMapLibre GL JSを組み合わせると、専用のタイルサーバーを用意せず、HTTP Range Requestに対応した静的ストレージやWebサーバーからPMTilesファイルを直接取得して地図を表示できます。 そのため、タイル生成・配信を担うバックエンドの構成をシンプルにしやすい点が大きな特徴です。
PMTilesとは?1ファイルで地図タイルを配信できる形式の基本
PMTiles(Pyramid Map Tiles)は、地図などのタイルデータを1つのファイルにまとめて保存できるアーカイブフォーマットです。Protomapsが開発するオープンな仕様で、この記事では現在広く利用されているPMTiles Version 3(v3)を前提に解説します。PMTiles v3では、ヘッダー、root directory、メタデータ、必要に応じたleaf directory、実際のタイルデータなどを1つのアーカイブ内に保持します。
地図データは、対象となる地域やズームレベル、データ量によって非常に多くのタイルに分割されます。一般的なXYZ形式では、それらを大量の個別ファイルとして管理する必要があります。
PMTilesでは、これらのタイルを1つの.pmtilesファイルにまとめて保持できるため、ファイルのコピーやバックアップ、ストレージへの配置、バージョン管理などをシンプルにしやすくなります。
巨大な1ファイルから必要な部分だけを取得する「HTTP Range Request」
「数GBもある1つのファイルにまとめると、ブラウザを開くたびにファイル全体をダウンロードするのでは?」と疑問に思うかもしれません。
PMTilesでは、HTTP Range Requestを利用してファイル全体ではなく必要なバイト範囲だけを取得します。そのため、数GBのPMTilesファイルであっても、地図表示に必要な部分を段階的に読み込むことができます。
大まかな処理の流れは次のとおりです。
- ヘッダーとroot directoryを取得する
PMTiles v3のヘッダーは127バイトで、タイルの位置を調べるためのroot directoryはアーカイブ先頭16KiB以内に配置されます。クライアントはこれらをRange Requestで取得し、PMTiles内部の構造を確認します。 - 必要なタイルの位置を特定する
root directoryなどのインデックス情報から、表示したいタイルデータがPMTilesファイル内のどの位置に保存されているかを調べます。 - 必要なバイト範囲だけを取得する
対象タイルが保存されている範囲に対してRange Requestを発行し、必要なデータだけを取得します。 - 取得したタイルをMapLibre GL JSで描画する
取得したベクタータイルなどのデータをMapLibre GL JSが解析し、地図としてレンダリングします。
なお、PMTilesのJSONメタデータやleaf directoryなどは、ファイル構造やアクセス内容に応じて別の位置に保存されるため、すべての情報を最初の1回のリクエストだけで取得するわけではありません。 必要なデータだけを追加で取得できることがPMTilesの特徴です。
静的ストレージとの相性が良い理由
PMTilesは、HTTP Range Requestに対応したWebサーバーやオブジェクトストレージから配信できます。Amazon S3、Cloudflare R2、Google Cloud Storageなどのストレージを利用でき、必要に応じてCDNを組み合わせる構成も可能です。CDN自体はPMTilesの必須条件ではありません。
動的なタイル生成処理を毎回実行する必要がないため、地図タイルを配信するためだけのアプリケーションサーバーを減らし、静的ファイル配信を中心としたシンプルな構成にしやすくなります。
ただし、PMTilesを置くだけで自動的に高速になるわけではありません。ストレージやCDNのRange Request対応、CORS、キャッシュ設定、PMTiles自体のサイズなども、実際の表示性能に影響します。
従来のMBTilesやタイルサーバーとの違い
これまでWeb地図で利用されてきた「XYZ形式(Z/X/Yのディレクトリ配置)」「MBTiles」「動的タイルサーバー」とPMTilesの主な違いを整理すると、次のようになります。
| 比較項目 | XYZ形式(ディレクトリ分散) | MBTiles | 動的タイルサーバー(Tegola / Martin等) | PMTiles |
|---|---|---|---|---|
| データ保持形態 | 大量のタイルファイル | SQLiteデータベース(1ファイル) | データベース + アプリケーション | 単一のアーカイブファイル(1ファイル) |
| ホスティング要件 | 一般的なWebサーバー | SQLite/MBTilesを扱う配信環境など | 動的サーバー + DB | Range Request対応のHTTPサーバー / ストレージ |
| クライアント取得方法 | タイルごとのURLへアクセス | 一般的には配信側を介してタイルを取得 | サーバー経由でタイルを取得 | HTTP Range Requestで必要部分を直接取得 |
| ファイル管理・移行 | 大量のファイル管理が必要 | 1ファイルのため比較的容易 | DBやサーバー環境の移行が必要 | 1ファイルのため比較的容易 |
| サーバー運用 | 静的配信が可能 | 配信方法によって異なる | タイル生成・配信サーバーが必要 | 動的タイルサーバーを省略しやすい |
データ配置と取得プロセスの違い
- XYZ形式は、
/z/x/y.pbfのようなURLでタイルを直接配信できるためシンプルですが、ズームレベルや地域によって大量のタイルファイルを管理する必要があります。 - MBTilesはSQLiteデータベースとして1ファイルにまとめられるため、ファイル自体の管理は容易です。一方、Web地図からHTTP経由でタイルを取得するには、通常はMBTilesを読み取ってタイルを返す配信側の仕組みが必要になります。
- 動的タイルサーバーは、データベースなどからリクエストされたタイルを生成・配信できるため柔軟性がありますが、アプリケーションサーバーやデータベースなどの運用が必要です。
- PMTilesは、タイルを1ファイルにまとめながら、HTTP Range Requestによって必要な部分だけを取得できるため、ファイル管理のしやすさと静的配信のしやすさを両立しやすいことが特徴です。
そのため、あらかじめ生成した地図データをWeb上で効率よく配信したい場合、「動的にタイルを生成する構成」から「静的なPMTilesを配信する構成」へ置き換えられるケースがあります。
MapLibre GL JSとPMTilesの相性が良い理由と基本的な仕組み
MapLibre GL JSは、Webブラウザ上でベクタータイルなどの地図データを描画するオープンソースの地図ライブラリです。WebGLを利用して地図を描画するため、ズームやパンなどの操作に応じて地図を滑らかに更新できます。
一方、PMTilesは地図タイルを1つのアーカイブファイルにまとめ、HTTP Range Requestによって必要な部分だけを取得するためのフォーマットです。
この2つを組み合わせることで、MapLibre GL JSを地図の描画エンジンとして利用しながら、タイルデータはPMTilesファイルから静的に配信する構成を作れます。
ただし、重要な点があります。
MapLibre GL JSはPMTilesを標準のVector Sourceとしてネイティブに読み込む機能を持っているわけではありません。 PMTilesを利用する場合は、PMTilesのJavaScriptライブラリが提供するProtocolをMapLibre GL JSのカスタムプロトコルとして登録します。PMTiles公式のMapLibre GL JSサンプルでも、この方法が使われています。
ブラウザ内部のデータフロー
MapLibre GL JSとPMTilesを組み合わせた場合、ブラウザ内ではおおむね次のような流れでデータが取得されます。
[ ブラウザ画面 ]
│
▼
[ MapLibre GL JS ]
│
▼
[ pmtiles:// のSource URL ]
│
▼
[ PMTiles Protocol ]
│
├─ PMTilesのヘッダー / Directoryを確認
│
├─ 必要なタイルの位置を特定
│
▼
[ HTTP Range Request ]
│
▼
[ 静的ストレージ / Webサーバー / CDN ]
│
▼
[ 必要なバイト範囲を返却 ]
│
▼
[ MapLibre GL JSでタイルを解析・描画 ]実際の処理を順番に見ると、次のようになります。
1.PMTilesのProtocolをMapLibreに登録するpmtilesパッケージからProtocolを生成し、maplibregl.addProtocol('pmtiles', protocol.tile)でpmtilesというカスタムプロトコルを登録します。MapLibre GL JSのaddProtocol()は、指定したカスタムURLスキームのリクエストを独自の処理へ渡すためのAPIです。
2.Vector SourceにPMTilesのURLを指定する
MapLibreのStyle JSONでは、次のようにpmtiles://を付けたURLを指定します。
sources: { example_source: { type: 'vector', url: 'pmtiles://https://example.com/example.pmtiles' } } pmtiles://の後ろにはPMTilesファイルのURLを指定します。/{z}/{x}/{y}をURLの末尾に追加して通常のXYZタイルURLのように指定する必要はありません。PMTiles ProtocolがMapLibreからのタイル要求を受け取り、アーカイブ内部から対応するデータを取得します。
3.PMTiles内部のインデックスからタイル位置を調べる
PMTiles ProtocolはPMTilesファイルのヘッダーやDirectoryを利用して、必要なタイルデータがファイル内のどこに格納されているかを特定します。
4.HTTP Range Requestで必要部分だけ取得する
特定した位置をもとに、PMTilesファイル全体ではなく必要なバイト範囲だけをHTTP経由で取得します。そのため、数GBのPMTilesファイルを使っていても、毎回ファイル全体をダウンロードする必要はありません。
5.取得したタイルをMapLibre GL JSが描画する
取得したベクタータイルのデータをMapLibre GL JSが読み込み、Style JSONで定義されたsource-layerやレイヤー設定に従って画面へ描画します。
このように、MapLibre GL JSは「地図を描画する役割」、PMTilesは「タイルデータを効率よく格納・取得する役割」を担当します。
両者を組み合わせることで、動的なタイルサーバーが毎回データベースからタイルを生成して返す構成ではなく、あらかじめ生成したPMTilesファイルを静的に配信する構成を実現できます。
また、PMTilesライブラリの現在の実装では、MapLibre用のProtocolにPMTilesインスタンスを追加して、同じアーカイブを共有する構成も利用できます。公式のMapLibreサンプルでは、getHeader()で初期表示位置を取得する処理とあわせてこの方式が紹介されています。
なぜ「タイルサーバーレス」にできるのか
従来の動的配信では、ブラウザからタイルを要求するたびに、タイルサーバーがデータベースなどから必要な地理データを取得し、ベクタータイルなどの形式にして返す構成がよく使われます。
PMTilesでは、あらかじめ生成したタイルデータを1つのファイルに格納しておき、クライアント側から必要な部分をRange Requestで直接取得することができます。
そのため、次のような構成にできます。
従来の構成
ブラウザ
│
▼
タイルサーバー
│
▼
PostGISなどのデータベース
│
▼
タイルを生成して返却PMTilesの構成
ブラウザ
│
▼
MapLibre GL JS
│
▼
PMTiles Protocol
│
▼
静的ストレージ / Webサーバー
│
▼
PMTilesこの構成では、タイル配信のたびにアプリケーションサーバーやデータベースで処理を実行する必要がなくなるため、静的な地図データを配信する用途ではインフラをシンプルにできます。
ただし、PMTilesがタイル生成そのものを不要にするわけではありません。GeoJSONやOSMなどの元データからPMTilesを作成する処理や、データ更新時の再生成処理は別途必要です。また、住所検索やルート検索などの機能もPMTiles単体には含まれません。
つまり、MapLibre GL JS+PMTilesは、
「地図を描画する仕組み」と「事前生成したタイルを効率よく配信する仕組み」を組み合わせることで、動的タイルサーバーを使わない構成を選択しやすくする
という関係として理解すると分かりやすいでしょう。
業界最安級、実績・口コミ多数!仕事に繋がるWebスキルを身につけるなら『デイトラ』MapLibre GL JSでPMTilesを表示する手順

MapLibre GL JSでPMTiles形式のWeb地図を表示するには、MapLibre GL JS本体に加えて、PMTilesのJavaScriptライブラリを組み込み、pmtilesというカスタムプロトコルをMapLibre GL JSへ登録します。
ここでは、現在のMapLibre GL JS 6系とPMTiles 4系を前提に、ビルドツールを使うnpm環境と、HTMLだけで動作を確認できるCDN環境の2通りを紹介します。MapLibre GL JSの公式PMTilesサンプルでも、pmtilesのProtocolをmaplibregl.addProtocol()で登録する方法が採用されています。
npmでmaplibre-glとpmtilesをインストールする手順
Vite、Next.js、webpackなどのモジュールバンドラーを利用している場合は、maplibre-glとpmtilesをnpmからインストールします。
パッケージのインストール
ターミナルで以下のコマンドを実行します。
npm install maplibre-gl pmtilesそれぞれの役割は次のとおりです。
maplibre-gl:WebGLを利用して地図を描画し、スタイル、ズーム、パン、クリックなどのインタラクションを処理します。pmtiles:PMTilesアーカイブを読み取り、必要なタイルデータをHTTP Range Requestで取得して、MapLibre GL JSから利用できる形で返します。MapLibre GL JSとの連携ではProtocolを使用します。
2026年10月時点では、npmのMapLibre GL JSは6.11.2が最新バージョンです。記事内のコードを長期間そのまま利用する場合は、実際に使用するバージョンをpackage.jsonで固定しておくと、将来のアップデートによる差分を管理しやすくなります。
ES Modulesでの実装例
JavaScriptまたはTypeScriptからライブラリを読み込み、PMTilesのプロトコルを登録してからMapLibre GL JSを初期化します。
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { PMTiles, Protocol } from 'pmtiles';
// 1. PMTilesプロトコルをMapLibreへ登録
const protocol = new Protocol();
maplibregl.addProtocol('pmtiles', protocol.tile);
// 2. 読み込むPMTilesファイル
const PMTILES_URL =
'https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles';
// 3. PMTilesインスタンスを作成
const p = new PMTiles(PMTILES_URL);
// ProtocolとPMTilesインスタンスを共有
protocol.add(p);
// 4. MapLibre GL JSを初期化
const map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
sources: {
'sample-pmtiles': {
type: 'vector',
url: `pmtiles://${PMTILES_URL}`,
attribution:
'© <a href="https://openstreetmap.org/copyright">OpenStreetMap</a>'
}
},
layers: [
{
id: 'water',
type: 'fill',
source: 'sample-pmtiles',
'source-layer': 'water',
paint: {
'fill-color': '#80b1d3'
}
},
{
id: 'buildings',
type: 'fill',
source: 'sample-pmtiles',
'source-layer': 'buildings',
paint: {
'fill-color': '#d9d9d9'
}
},
{
id: 'roads',
type: 'line',
source: 'sample-pmtiles',
'source-layer': 'roads',
paint: {
'line-color': '#fc8d62'
}
}
]
},
center: [11.2543435, 43.7672134],
zoom: 13
});
// ナビゲーションコントロールを追加
map.addControl(new maplibregl.NavigationControl());urlには、
pmtiles://https://example.com/example.pmtilesのように、pmtiles://に続けてPMTilesファイルのURLを指定します。通常のXYZタイルURLのように/{z}/{x}/{y}を末尾へ追加する必要はありません。PMTilesのProtocolがMapLibre GL JSからのタイル要求を受け取り、PMTiles内部のDirectoryを参照して必要なデータを取得します。
また、protocol.add(p)によって同じPMTilesインスタンスをProtocol側と共有しておくと、ヘッダー取得などを含む処理を同じアーカイブインスタンスで扱えます。MapLibreの公式PMTilesサンプルでもこの方法が使われています。
CSSファイルの読み込みも忘れないようにしてください。
import 'maplibre-gl/dist/maplibre-gl.css';これを読み込まないと、MapLibre GL JSのコントロールや一部のUIが正しく表示されないことがあります。
CDNだけで動かすHTML+JavaScriptのサンプルコード
ビルド環境を用意せずに動作を確認したい場合は、CDNからMapLibre GL JSとPMTilesを読み込む方法があります。
実際の検証では、HTMLをローカルのHTTPサーバーや開発サーバーから配信する方法がおすすめです。PMTilesを別ドメインから取得する場合は、配信元のCORS設定も必要になります。PMTiles公式でも、S3、Cloudflare R2、Google Cloud Storageなどを利用する場合のCORS設定が案内されています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MapLibre GL JS + PMTiles 表示サンプル</title>
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@5.6.0/dist/maplibre-gl.css">
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#map {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/maplibre-gl@5.6.0/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/pmtiles@4.3.0/dist/pmtiles.js"></script>
<script>
// 1. PMTilesプロトコルをMapLibreへ登録
const protocol = new pmtiles.Protocol();
maplibregl.addProtocol('pmtiles', protocol.tile);
// 2. PMTilesファイルのURL
const PMTILES_URL = 'https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles';
// 3. MapLibre GL JSを初期化
const map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
sources: {
protomaps: {
type: 'vector',
url: `pmtiles://${PMTILES_URL}`,
attribution:
'© <a href="https://openstreetmap.org/copyright">OpenStreetMap</a>'
}
},
layers: [
{
id: 'water',
type: 'fill',
source: 'protomaps',
'source-layer': 'water',
paint: {
'fill-color': '#80b1d3'
}
},
{
id: 'buildings',
type: 'fill',
source: 'protomaps',
'source-layer': 'buildings',
paint: {
'fill-color': '#d9d9d9'
}
},
{
id: 'roads',
type: 'line',
source: 'protomaps',
'source-layer': 'roads',
paint: {
'line-color': '#fc8d62'
}
}
]
},
center: [11.2543435, 43.7672134],
zoom: 13
});
map.addControl(new maplibregl.NavigationControl());
</script>
</body>
</html>実際の表示
See the Pen maplibre-pmtiles-sample-01 by watashi-xyz (@watashi-xyz) on CodePen.
このサンプルでは、MapLibre GL JSのvectorソースに
url: `pmtiles://${PMTILES_URL}`を指定しています。
PMTilesプロトコルが登録されているため、MapLibre GL JSはpmtiles://のURLを通常のHTTP URLとして取得するのではなく、登録済みのProtocolへ処理を渡します。そこから必要なPMTilesの範囲が取得されます。
自分で作成したPMTilesを表示する場合は、PMTILES_URLを自身のストレージやWebサーバー上のURLへ変更してください。
addProtocol("pmtiles", protocol.tile)の意味と正しい書き方
PMTilesをMapLibre GL JSで利用するときの中心となる処理が次の2行です。
const protocol = new pmtiles.Protocol();
maplibregl.addProtocol('pmtiles', protocol.tile);addProtocol()は、MapLibre GL JSにカスタムURLスキームの処理を登録するためのAPIです。例えばpmtiles://で始まるURLがStyle JSONのsource.urlに指定されている場合、そのリクエストを登録したprotocol.tileへ渡せるようになります。
各要素の組み合わせと通信プロセス
処理の流れを簡略化すると、次のようになります。
[ MapLibre Style JSON ]
└── url: "pmtiles://https://example.com/map.pmtiles"
│
▼
[ maplibregl.addProtocol('pmtiles', protocol.tile) ]
│
▼
[ pmtiles.Protocol ]
├── PMTilesファイルのURLを取得
├── Header / Directoryを解析
├── 必要なタイルの位置を特定
└── HTTP Range Requestで必要部分を取得
│
▼
[ 静的ストレージ / Webサーバー / CDN ]
│
▼
[ MapLibre GL JS ]
└── 取得したタイルを描画それぞれの役割を整理すると、次のようになります。
new pmtiles.Protocol()
PMTilesとMapLibre GL JSを接続するためのProtocolオブジェクトを生成します。maplibregl.addProtocol('pmtiles', protocol.tile)
MapLibre GL JSに対して、「pmtiles://で始まるURLはこの処理で取得する」と登録します。addProtocol()はカスタムURLスキームに対するロード処理を登録するAPIです。url: pmtiles://${PMTILES_URL}
MapLibreのVector SourceにPMTilesファイルを指定します。pmtiles://はPMTiles Protocolを呼び出すためのスキームです。PMTilesの公式JavaScriptドキュメントでも同じ記述方法が使われています。- PMTiles内部から必要なデータを取得する
ProtocolがPMTilesのHeaderやDirectoryを参照し、対象となるタイルの格納位置を特定したうえで、必要なバイト範囲を取得します。
addProtocol()の登録は、MapLibre GL JSがPMTiles URLを読み込む前に実行してください。
初期表示位置・ズーム・回転・ピッチの基本設定
MapLibre GL JSでは、center、zoom、bearing、pitchなどを使って地図の初期表示状態を設定できます。
const map = new maplibregl.Map({
container: 'map',
style: styleObject,
center: [139.767125, 35.681236], // [経度, 緯度]
zoom: 14,
bearing: 45,
pitch: 60
});centerの座標は、
[経度, 緯度]の順番で指定します。
例えば東京駅付近なら、
center: [139.767125, 35.681236]のようになります。
bearingは地図の回転角度、pitchは地図を傾ける角度を表します。MapLibre GL JSではこれらのカメラ設定を利用して、通常の2D表示だけでなく、地図を回転・傾斜させた表示も構築できます。
PMTilesのヘッダーメタデータから動的に中心座標を取得する
PMTilesには、アーカイブに含まれるタイルのズーム範囲や中心位置などを取得できるヘッダー情報があります。
そのため、地図ごとにcenterやzoomを手動で指定する代わりに、PMTilesのヘッダーから初期表示位置を取得する方法もあります。
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { PMTiles, Protocol } from 'pmtiles';
const PMTILES_URL = 'https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles';
// PMTiles Protocolを登録
const protocol = new Protocol();
maplibregl.addProtocol('pmtiles', protocol.tile);
// PMTilesインスタンスを作成
const p = new PMTiles(PMTILES_URL);
// Protocolと同じPMTilesインスタンスを共有
protocol.add(p);
async function initMap() {
// PMTilesヘッダーを取得
const header = await p.getHeader();
const center = [header.centerLon, header.centerLat];
const zoom = header.centerZoom;
const map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
sources: {
'my-data': {
type: 'vector',
url: `pmtiles://${PMTILES_URL}`
}
},
layers: [
// 必要なレイヤーを定義
]
},
center,
zoom
});
}
initMap();getHeader()を使うことで、PMTiles側に記録されているcenterLon、centerLat、centerZoomなどを取得できます。MapLibre GL JSの公式PMTilesサンプルでも、PMTilesのヘッダーから中心座標を取得して初期位置へ利用する方法が紹介されています。
この方法を利用すれば、PMTilesファイルを変更した際にも、データの中心位置を手動で書き換える必要を減らせます。
なお、ヘッダーに記録された中心座標は、必ずしも「データ全体を画面内に収めるための最適な表示位置」と同じではありません。 データ全体を確実に画面内へ収めたい場合は、PMTilesのバウンド情報を利用してMapLibreのfitBounds()などで表示範囲を調整する方法もあります。
PMTilesを作る方法|GeoJSON・OpenStreetMap・国土地理院データを変換

PMTilesをWeb地図で利用するには、まず元となる地理空間データをタイル化し、PMTilesファイルへ変換します。
代表的な方法は、次の3パターンです。
- GeoJSONなどからTippecanoeで直接PMTilesを生成する
- 既存のMBTilesをPMTilesへ変換する
- OpenStreetMapなどの大規模データをPlanetilerでPMTiles化する
データの種類や規模によって適した方法が異なります。小〜中規模のGeoJSONデータならTippecanoe、大規模なOpenStreetMapデータならPlanetilerを使う構成が分かりやすいでしょう。
GeoJSONをTippecanoeやPMTiles CLIでPMTilesに変換する
GeoJSONをベクタータイル化する代表的なツールがTippecanoeです。
TippecanoeはGeoJSONだけでなく、FlatGeobufやCSVなどのデータからベクタータイルセットを生成できます。現在のTippecanoeは出力ファイルの拡張子として.pmtilesを指定できるため、GeoJSONからPMTilesまでを1回のコマンドで生成できます。(Tippecanoe公式リポジトリ)
処理フローのパターン
GeoJSONからPMTilesを作成する場合、現在は主に次の2通りの方法があります。
【直接生成】
GeoJSON
│
▼
Tippecanoe
│
▼
output.pmtiles【MBTiles経由】
GeoJSON
│
▼
Tippecanoe
│
▼
output.mbtiles
│
▼
PMTiles CLI
│
▼
output.pmtiles通常は、最初からPMTilesを出力する方法がシンプルです。
一方、すでにMBTilesファイルが存在する場合は、PMTiles CLIのconvertコマンドを利用して変換できます。PMTilesの公式リポジトリでも、pmtiles convert INPUT.mbtiles OUTPUT.pmtilesという変換方法が案内されています。(PMTiles公式リポジトリ)
1. TippecanoeでGeoJSONから直接PMTilesを出力する
ターミナルで以下のコマンドを実行します。
tippecanoe \
-o output.pmtiles \
-l my_layer_name \
-zg \
--drop-densest-as-needed \
--extend-zooms-if-still-dropping \
input.geojson主なオプションは次のとおりです。
o output.pmtiles:出力ファイルを指定します。.pmtilesを指定するとPMTiles形式で出力されます。l my_layer_name:生成するベクタータイルのレイヤー名を指定します。MapLibre GL JSでは、この名前をsource-layerとして参照します。zg:入力データの密度などをもとに、適切と考えられる最大ズームレベルを自動的に推測します。-drop-densest-as-needed:タイルが大きくなりすぎた場合に、必要に応じて密度の高い部分のフィーチャーを削減します。-extend-zooms-if-still-dropping:最大ズームでもフィーチャーの削減が必要な場合、さらにズームレベルを追加して詳細を保持しやすくします。
Tippecanoe公式でも、-zg、--drop-densest-as-needed、--extend-zooms-if-still-droppingを組み合わせた使い方が例示されています。(Tippecanoe公式リポジトリ)
2. MBTiles経由でPMTiles CLIを利用する
すでにMBTilesがある場合や、既存のデータ変換パイプラインをそのまま利用したい場合は、PMTiles CLIでMBTilesからPMTilesへ変換できます。
# MBTilesを作成
tippecanoe \
-o intermediate.mbtiles \
-l my_layer_name \
-zg \
input.geojson
# MBTilesからPMTilesへ変換
pmtiles convert intermediate.mbtiles output.pmtilesPMTilesのconvert処理では、MBTilesに格納されているタイルとメタデータを読み取り、PMTiles v3形式のアーカイブとして書き出します。(PMTiles公式リポジトリ)
すでにMBTilesを利用している環境では、「既存のMBTiles生成処理は維持し、最終工程だけPMTilesへ変換する」という構成も利用できます。
ファイルサイズと表示品質を左右する重要パラメータ
PMTilesへ変換しただけで、元データの情報量が自動的に最適化されるわけではありません。
ベクタータイルでは、ジオメトリの頂点数やフィーチャー数、属性データなどが増えるほどタイルサイズも大きくなります。そのため、用途に合わせてズーム範囲や属性、ジオメトリの詳細度を調整することが重要です。
代表的な設定には次のようなものがあります。
| オプション | 概要・効果 | 主な用途 |
|---|---|---|
-Z 6 -z 14 | 最小・最大ズームを6〜14に制限 | 必要なズーム範囲だけ生成したい場合 |
-y attribute_name | 指定した属性だけを保持 | 不要な属性を削減したい場合 |
-x attribute_name | 指定した属性を除外 | 一部の不要な属性だけ削除したい場合 |
-S 10 / --simplification=10 | ライン・ポリゴンの簡略化量を調整 | ジオメトリをさらに軽量化したい場合 |
--simplify-only-low-zooms | 最大ズームでは通常の簡略化を行わず、低ズーム側で簡略化 | 高ズームでの形状精度を優先したい場合 |
Tippecanoeではラインやポリゴンに対してズームレベルに応じた簡略化が標準で行われます。-S / --simplificationで簡略化のスケールを調整でき、--simplify-only-low-zoomsを使うと最大ズームではライン・ポリゴンの簡略化を抑えることができます。(Tippecanoe公式リポジトリ)
特に属性の削減は、ポップアップやスタイルに使用しないデータをタイルへ持ち込まないという意味で有効です。
例えば、nameとcategoryだけを残したい場合は次のように指定できます。
tippecanoe \
-o output.pmtiles \
-l places \
-zg \
-y name \
-y category \
input.geojson逆に、不要な属性が明確な場合は-xを利用できます。
tippecanoe \
-o output.pmtiles \
-l places \
-zg \
-x internal_id \
-x created_at \
input.geojsonTippecanoe公式でも、属性が多い場合には-yを使って必要な属性だけを残す方法が案内されています。(Tippecanoe公式リポジトリ)
OpenStreetMapをPlanetilerでPMTiles化してMapLibreで表示する
OpenStreetMap(OSM)の広い範囲を扱う場合は、Planetilerを利用する方法があります。
PlanetilerはOpenStreetMapなどの大規模データからベクタータイルセットを生成するためのツールで、PMTilesを直接出力できます。公式READMEでも、--output=australia.pmtilesのように.pmtilesを指定する方法が紹介されています。(Planetiler公式リポジトリ)
Planetilerによる変換と配信の全体フロー
OSM PBFファイル
│
▼
Planetiler
│
▼
japan.pmtiles
│
▼
静的ストレージ / CDN
│
▼
MapLibre GL JS1. PlanetilerでOSMデータをPMTilesへ変換する
Planetilerでは、既存の.osm.pbfを指定する方法と、対応するエリアのデータを自動ダウンロードする方法があります。
例えば、既存のOSM PBFを指定してPMTilesを生成する場合は、次のような形になります。
java -Xmx8g -jar planetiler.jar \
--osm-path=japan.osm.pbf \
--output=japan.pmtiles入力データを自動ダウンロードできる環境では、--downloadと--areaを組み合わせる方法もあります。
java -Xmx8g -jar planetiler.jar \
--download \
--area=japan \
--output=japan.pmtilesPlanetilerでは--outputで出力先と形式を指定でき、.pmtilesを指定するとPMTilesアーカイブとして出力されます。また、--osm-pathを使えば手元にあるOSM PBFを入力できます。(Planetiler公式リポジトリ)
大量のOSMデータを処理する場合は、Javaプロセスへ十分なメモリを割り当てる必要があります。Planetiler公式では、-XmxでJVMのメモリ上限を設定する方法が案内されており、入力PBFのサイズなどに応じて必要なメモリ量は変わります。したがって、-Xmx8gはあくまで一例であり、すべての地域・データセットに共通する必要量ではありません。(Planetiler公式リポジトリ)
OSMデータを利用するときに確認したいライセンス
OpenStreetMapのデータを利用してPMTilesを作成する場合は、PMTilesやMapLibre GL JSのライセンスとは別に、元データであるOSMの利用条件を確認する必要があります。
特に、地図上へ表示する出典表記や、加工したデータセットを配布する場合のライセンス条件などは、データの利用方法によって扱いが変わります。
そのため、OSMデータを自分でPMTiles化して公開する場合は、OpenStreetMapの著作権・ライセンス情報を確認したうえで、必要なクレジットやライセンス情報を適切に掲載してください。
国土地理院・PLATEAU・自治体オープンデータをPMTiles化する
日本国内の地理空間データをPMTiles化する場合は、データの提供形式に応じた前処理が必要になることがあります。
すべてのオープンデータをダウンロードして、そのままTippecanoeへ渡せるわけではありません。まずGeoJSONなどTippecanoeが扱える形式へ変換し、必要に応じて座標系や属性を調整します。
[ PLATEAU / 3D都市モデル ]
│
├─ 必要な2D要素・属性を抽出
│
[ 国土地理院データ ]
│
├─ XMLなどをGISデータへ変換
│
[ 自治体オープンデータ ]
│
├─ Shapefile / GeoPackage / CSVなどを変換
│
▼
GeoJSONなどへ変換
│
▼
Tippecanoe
│
▼
output.pmtiles1. 国土地理院データの変換(基盤地図情報・数値地図)
国土地理院が提供する地理空間データには、GISソフトや変換ツールを利用して取り扱う必要がある形式が含まれます。
例えば、基盤地図情報などをGeoJSONへ変換した後、Tippecanoeでベクタータイル化するという流れが考えられます。
基盤地図情報など
│
▼
GIS / 変換ツール
│
▼
GeoJSON
│
▼
Tippecanoe
│
▼
PMTiles座標系を変換する場合は、GDALのogr2ogrなどを利用できます。
ogr2ogr \
-f GeoJSON \
-t_srs EPSG:4326 \
output.geojson \
input.gpkgただし、実際に利用できる変換方法は元データの形式によって異なります。国土地理院のデータを公開・再利用する場合は、対象データの最新の利用条件や出典表示の要件も確認してください。
2. PLATEAU(国土交通省)のデータを変換する
PLATEAUの3D都市モデルでは、CityGMLなどの形式で都市データが提供されています。
PMTilesで2D地図として利用する場合は、建築物の外形や属性など、必要な要素を抽出してGeoJSONやGeoPackageなどのGIS形式へ変換し、その後Tippecanoeでベクタータイル化する方法があります。
例えば、GeoPackageなどへ変換済みのデータをGeoJSONへ変換する場合は、次のようなコマンドを利用できます。
ogr2ogr \
-f GeoJSON \
-t_srs EPSG:4326 \
building.geojson \
input_plateau.gpkg建物の高さなどの属性を保持しておけば、MapLibre GL JSのfill-extrusionレイヤーを使って、PMTiles化したデータを3D表示へ利用することもできます。
ただし、PLATEAUではデータセットや提供形態によって確認すべき利用条件があるため、実際に公開・再配布する際は対象データの最新の利用規約・ライセンスを確認してください。
3. 自治体オープンデータ(Shapefile / CSV)
自治体が公開している避難所、AED、公共施設などのデータをPMTiles化する場合も、まずGISデータとして扱える形式へ変換します。
CSVに経度・緯度が含まれている場合は、GeoJSONへ変換してからTippecanoeへ渡す方法が分かりやすいでしょう。
自治体CSV
↓
GeoJSONへ変換
↓
Tippecanoe
↓
output.pmtilesShapefileやGeoPackageなどの場合は、GDALのogr2ogrを使ってGeoJSONへ変換できます。
ogr2ogr \
-f GeoJSON \
-t_srs EPSG:4326 \
output.geojson \
input.shp出典表記と利用規約を確認する
公的機関や自治体が公開しているデータをPMTiles化する場合は、PMTilesへの変換方法だけでなく、元データの利用条件も確認することが重要です。
同じ「オープンデータ」でも、出典表示、改変、再配布、商用利用などの条件が同一とは限りません。
そのため、PMTilesをWebサイトで公開するときは、
- 使用した元データの名称
- データ提供元
- 必要な出典表示
- 二次利用・再配布に関する条件
- 商用利用の可否
などを対象データの最新の規約で確認してから公開するようにしましょう。
特に、PMTilesファイルへ変換したことで元データの利用条件がなくなるわけではありません。「PMTilesはOSSだから、元データも自由に再配布できる」という考え方は避け、元データのライセンスを基準に確認することが重要です。
TVCMで話題の【ココナラ】無料会員登録はこちらPMTilesをオフライン・大規模データで活用する方法|高速化と運用のポイント

PMTilesは静的ファイルとして地図タイルを配信できるため、オンラインのWebサービスだけでなく、ローカル環境や閉域網、オフラインに近い環境でも利用できます。
ただし、PMTilesはHTTP Range Requestを利用して必要なデータを取得する仕組みのため、配信環境がRange Requestに対応していることが重要です。また、大規模データを扱う場合は、ズーム範囲、属性、ジオメトリを調整してタイルサイズを抑えることも重要になります。
ここでは、ローカルでの検証方法から、PMTilesの軽量化、CDNキャッシュ、CORS、CI/CDまで、本番運用で押さえておきたいポイントを整理します。
ローカルPMTilesを使ったオフライン地図を構築する
PMTilesはHTTP Range Requestを利用してデータを取得するため、HTMLファイルをfile://で直接開き、Web上のPMTiles URLを通常のHTTP通信のように読み込む構成は基本的に適していません。
特に、ブラウザから別のローカルファイルを直接参照する場合は、ブラウザのセキュリティ制約やOriginの扱いが問題になります。
そのため、ローカルで検証するときは、次のような構成にするのが分かりやすい方法です。
【避けたい構成】
index.html (file://)
│
└── local_data.pmtiles (file://)
【推奨するローカル検証】
ブラウザ
│
▼
ローカルHTTPサーバー
(http://localhost:8080)
│
└── local_data.pmtilesなお、PMTiles JavaScriptライブラリにはブラウザのFile APIを使ってローカルファイルを読み込むFileSourceも用意されています。そのため、オフライン利用では「HTTPサーバー経由」と「ユーザーが選択したローカルファイルをFile APIで読み込む方法」の両方を検討できます。
オフライン環境でPMTilesを読み込む3つのアプローチ
ネットワーク接続のない環境や、閉域網・ローカル環境でPMTilesを利用する場合は、主に次の方法が考えられます。
1. ローカルHTTPサーバーを立ち上げる
開発・検証用途では、ローカルHTTPサーバーからHTMLとPMTilesを配信する方法がシンプルです。
PMTiles公式CLIには、PMTilesをHTTP経由で配信するpmtiles serveコマンドがあります。
pmtiles serve .デフォルトではローカルの8080番ポートが利用され、必要に応じて--corsなどのオプションも指定できます。公式ドキュメントでも、ローカル配信や本番前の検証用途に利用できるCLIサーバーとして紹介されています。
例えば、
pmtiles serve . --port=8080として起動し、
http://localhost:8080/からWebページを開きます。
ローカルサーバーを選ぶ際は、Range Requestを正しく処理できることを確認してください。Protomaps公式は、本番のHTTPサーバーとしてCaddyやNginxを例示しています。
なお、python3 -m http.server 8080は簡易HTTPサーバーとしてHTMLなどを配信する用途には使えますが、PMTiles用のRange配信を検証する目的では、実際に206 Partial Contentが返るかを確認してください。
2. ローカルファイルをFile APIから読み込む
Webアプリケーション側でユーザーにPMTilesファイルを選択してもらう構成では、JavaScriptのFile APIを利用できます。
PMTilesライブラリにはFileSourceが用意されており、ブラウザのFileオブジェクトから必要なバイト範囲を切り出して読み込めます。
例えば、
const file = input.files[0];
const source = new pmtiles.FileSource(file);のような方法で、サーバーへアップロードせずにローカルのPMTilesを扱う構成も作れます。
この方法は、インターネットに接続できない端末で、ユーザー自身が地図データを持ち込んで表示するような用途にも利用できます。
3. Service Workerやデスクトップアプリへ組み込む
PWAなどでオフライン対応を行う場合は、Service WorkerとCache APIなどを組み合わせて、事前にPMTilesをキャッシュしておく方法もあります。
また、ElectronやTauriなどのデスクトップアプリでは、アプリ内にPMTilesを同梱してローカルファイルとして扱う構成も考えられます。
ただし、この場合は単にPMTilesファイルを置くだけではなく、アプリ側でどのようにファイルを取得し、ブラウザ側へ渡すかを設計する必要があります。
ズーム範囲・データ簡略化・属性削減でPMTilesを軽量化する
「PMTiles形式に変換したから、自動的に地図データが大幅に軽くなる」というわけではありません。
PMTilesは、タイルを1つのアーカイブにまとめ、必要な範囲だけを取得しやすくするフォーマットです。元となるベクタータイルそのものに大量のフィーチャー、複雑なジオメトリ、多数の属性が含まれていれば、取得するタイルのサイズやブラウザ側の処理量も増えます。
そのため、大規模な地図データでは、PMTiles化する前のベクタータイル生成条件を見直すことが重要です。
タイルサイズと軽量化の3大ステップ
Tippecanoeには、タイルサイズが大きくなった場合にフィーチャーを削減して500K程度に収めるための--drop-densest-as-neededがあります。ただし、これはTippecanoeの生成処理における目安であり、すべてのWeb地図で「500KB以下が推奨」「100KBが理想」と一律に決まっているわけではありません。 実際にはデータ内容、通信環境、端末性能、ズームレベルなどを考慮して調整します。
軽量化するときは、次の3点から確認すると分かりやすくなります。
[ 元データ ]
├─ Step 1. 必要なズーム範囲だけ生成
│
├─ Step 2. 不要な属性を削減
│
└─ Step 3. ジオメトリやフィーチャー数を調整
▼
[ 軽量化されたベクタータイル ]
│
▼
[ PMTiles ]Step 1: ズーム範囲(minzoom / maxzoom)を調整する
利用しないズームレベルまでデータを生成すると、ファイルサイズだけでなく生成時間も増える場合があります。
例えば、ズームレベル6〜14だけを利用する場合は、次のように指定できます。
tippecanoe \
-o output.pmtiles \
-Z 6 \
-z 14 \
input.geojsonZが最小ズーム、zが最大ズームです。
必要以上に高いズームレベルまで生成する必要がないデータでは、対象範囲を絞ることで生成するタイル数を抑えられます。
Step 2: 不要な属性(プロパティ)を削減する
GeoJSONのプロパティには、住所、作成日時、内部ID、管理用フラグなど、地図表示では使わない情報が含まれていることがあります。
MapLibre GL JSのスタイルやポップアップで使用しない属性を削減すれば、ベクタータイルに保持する情報量を減らせます。
必要な属性だけを残す場合は-yを使います。
tippecanoe \
-o output.pmtiles \
-l places \
-y name \
-y category \
input.geojson逆に、削除する属性が明確なら-xを使えます。
tippecanoe \
-o output.pmtiles \
-l places \
-x internal_id \
-x created_at \
input.geojsonTippecanoe公式でも、不要な属性を-xで除外したり、必要な属性だけを-yで残したりする方法が案内されています。属性が多いデータでは、軽量化を検討する重要なポイントです。
Step 3: ジオメトリの簡略化とフィーチャー数の調整
ラインやポリゴンはズームレベルに応じて簡略化できます。
Tippecanoeでは、--simplificationまたは-Sでライン・ポリゴンの簡略化量を調整できます。値を大きくすると簡略化の度合いが強くなるため、ファイルサイズと形状の精度を実データで確認しながら調整します。
tippecanoe \
-o output.pmtiles \
--simplification=10 \
input.geojsonただし、--simplificationはあくまでジオメトリの簡略化を調整するための設定です。実際の軽量化では、ズーム範囲、不要な属性、フィーチャー数などもあわせて見直します。
PMTiles更新時のファイル公開とキャッシュを設計する
本番環境でPMTilesを更新する場合は、同じURLのファイルを上書きする運用と、バージョン付きURLで新しいファイルを公開する運用の2つを考えられます。
同じURLを更新する方式では、ブラウザやCDNに残っているキャッシュとの整合性を考慮する必要があります。現在のPMTiles JavaScriptライブラリには、ETagを利用してアーカイブの変更を検出し、ETagの不一致や一部の416応答が発生した場合に再試行する仕組みがあります。
一方、運用を分かりやすくするなら、次のように更新ごとにファイル名やURLを変更するイミュータブル運用が扱いやすくなります。
data-20261003.pmtiles
data-20261101.pmtiles新しいPMTilesを先に公開し、MapLibreのStyle JSONなどが参照するURLを切り替えたあと、古いファイルを一定期間保持してから削除します。こうすると、CDNやブラウザのキャッシュと新旧データを分離しやすくなります。
S3・R2などでCORSとRange Requestを確認する
PMTilesをWebアプリとは別のオリジンから配信する場合は、ストレージ側のCORS設定が必要になります。同一オリジンで配信する場合は、CORS自体が不要なケースもあります。
本番公開前には、少なくとも次の3点を確認してください。
- HTTP Range Requestを処理できること
- 別オリジンからのGETをCORSで許可していること
- 必要に応じてETagをブラウザから参照できるようにすること
Protomapsのクラウドストレージ設定例では、CORSの許可ヘッダーとしてrangeやif-matchを設定し、レスポンスヘッダーとしてetagをExposeする構成が案内されています。実際の設定値は利用するストレージの仕様にあわせて調整してください。
CDNを使う場合はCache-Controlを設計する
CDNはPMTilesの必須条件ではありませんが、同じPMTilesを多数のユーザーへ配信する場合はキャッシュを利用しやすくなります。
特にバージョン付きURLでPMTilesを公開する場合は、古いファイルを上書きせずにURLそのものを変更できるため、長めのキャッシュ期間を設計しやすくなります。
例えば、次のような考え方です。
https://example.com/tiles/data-20261003.pmtilesこのファイルを後から上書きせず、更新時はdata-20261101.pmtilesのように新しいURLへ切り替えます。これにより、「古いPMTilesがCDNに残っているため、新しいデータへ切り替わらない」といった問題を減らしやすくなります。
ただし、キャッシュ期間や削除タイミングは、データ更新頻度やストレージ料金、CDNの仕様を考慮して決めてください。
CI/CDでPMTilesの生成と公開を自動化する
定期的に地理データを更新する場合は、PMTilesの生成から公開までをCI/CDに組み込むと、手作業を減らせます。
例えば、次のような流れです。
元データを取得
↓
Tippecanoe / PlanetilerでPMTiles生成
↓
生成物を検証
↓
バージョン付きPMTilesをストレージへアップロード
↓
Webアプリが参照するURLを更新
↓
本番配信GitHub Actionsなどを利用する場合は、元データの取得、PMTiles生成、アップロード、参照先の更新を別ステップに分けると、どこで失敗したのかを確認しやすくなります。
また、生成処理が成功しただけで公開を完了とせず、実際に配信先のPMTilesへRange Requestを送って正常な部分応答が返ることを確認してから参照先を切り替える流れにすると、本番反映時のトラブルを減らしやすくなります。
本番公開前にRange Requestを確認する
PMTilesは必要なバイト範囲だけを取得することが前提なので、公開先がRange Requestを正しく処理できるかを事前に確認しておくと安心です。
例えば、次のように先頭128バイトだけを要求して動作を確認できます。
curl -i -H "Range: bytes=0-127" \
https://example.com/data.pmtilesレスポンスが206 Partial Contentになり、要求した範囲のデータが返ることを確認します。200 OKでファイル全体が返る場合は、配信サーバーやCDNがRange Requestを正しく処理していない可能性があるため、設定を見直してください。
ブラウザの開発者ツールでも、PMTiles読み込み時のネットワーク通信を確認できます。実際の本番ドメイン、CORS、CDNを含めた状態で検証することが重要です。
MapLibre+PMTilesを採用するメリット・デメリット|コストとライセンスも確認

MapLibre GL JSとPMTilesを組み合わせると、動的なタイルサーバーを使わず、静的ストレージやWebサーバーから地図タイルを配信する構成を作れます。
一方で、PMTilesへ移行すれば地図システムに必要なインフラや料金がすべてなくなるわけではありません。PMTilesの生成、オブジェクトストレージ、データ転送、必要に応じたCDN、検索・ルート案内などの外部サービスについては、引き続き設計・運用が必要です。
また、MapLibre GL JSやPMTilesがオープンソースであっても、使用する地図データのライセンスは別に確認する必要があります。
PMTilesでタイルサーバーを減らせる仕組みとサーバーレス構成
PMTilesを利用する大きなメリットの一つは、あらかじめ生成したタイルデータを静的ファイルとして配信できるため、タイルリクエストごとにデータベースからタイルを生成する専用タイルサーバーを構成しなくてもよいことです。
削減できるインフラコンポーネントと残るインフラ
「サーバーレス構成」といっても、コンピューティング資源が完全になくなるわけではありません。
例えば、動的にタイルを生成するシステムでは次のような構成が考えられます。
【動的タイルサーバー構成】
ブラウザ
│
▼
CDN / リバースプロキシ
│
▼
[ タイルサーバー ]
│
▼
[ PostGISなどの空間DB ]PMTilesを利用する場合は、次のような構成へ簡略化できます。
【PMTilesによる静的配信構成】
ブラウザ
│
▼
MapLibre GL JS
│
▼
PMTiles Protocol
│
▼
[ オブジェクトストレージ / Webサーバー ]
│
└── data.pmtilesこの構成では、タイルをリクエストするたびにアプリケーションサーバーやデータベースでベクタータイルを生成する処理を省略できます。
削減しやすいもの
- 動的なベクタータイルを生成するタイルサーバー
- タイル生成・レスポンス処理を行うアプリケーションサーバー
- タイル配信のためだけに常時稼働させていた空間データベース
引き続き必要になるもの
- PMTilesを保存するオブジェクトストレージやWebサーバー
- 必要に応じたCDN
- 元データからPMTilesを生成するビルド環境
- データ更新を自動化するCI/CD
- ジオコーディングやルート検索など、PMTilesに含まれない機能のためのサービス
また、CDNはPMTilesの必須条件ではありません。HTTP Range Requestに対応したストレージやWebサーバーから直接配信することもできます。PMTiles公式でも、S3互換ストレージなどの静的ストレージへアップロードして利用する方法が案内されています。
そのため、「PMTilesを使えばサーバーがなくなる」というより、タイルの動的生成・配信を担当するサーバーを静的ファイル配信へ置き換えられる場合があると理解するのが適切です。
Mapbox・Google MapsからMapLibre+PMTilesへ移行する考え方
Google Maps PlatformやMapboxからMapLibre GL JS+PMTilesへ移行する場合は、単純に「どちらが上位か」という比較ではなく、どこまでの機能を自分たちで用意する必要があるのかを確認することが重要です。
Google Maps PlatformやMapboxは、地図の表示だけでなく、検索、場所情報、ルート案内など複数の地理空間サービスを提供しています。たとえばGoogle Maps JavaScript APIでは、地図表示とPlaces関連機能などが別々のSKUとして扱われています。Mapbox GL JSについてもWebのMap Loadを基準とした料金体系が用意されています。
一方、MapLibre GL JSは地図の描画ライブラリであり、PMTilesはタイルデータを格納・配信するフォーマットです。住所検索やルート検索などのサービスまで一体で提供するものではありません。
サービス機能範囲の比較
| 機能要素 | Google Maps / Mapboxなど | MapLibre GL JS + PMTiles | 移行時の考え方 |
|---|---|---|---|
| 地図描画 | 各サービスのJavaScript SDK | MapLibre GL JS | MapLibre GL JSを描画エンジンとして利用 |
| 背景地図データ | 各サービスが提供する地図データ | 自分で選択・生成したPMTiles | OSM、Protomaps、国土地理院などから用途に応じて選択 |
| タイル配信 | 各サービス側のホスティング | 自分のストレージ / Webサーバー | S3、R2などからPMTilesをRange Requestで配信 |
| ジオコーディング | 関連API・サービスで提供 | 含まれない | Nominatim、Photon、各種商用APIなどを別途利用 |
| ルート検索 | 関連API・サービスで提供 | 含まれない | OSRM、Valhalla、GraphHopperなどを別途構築・利用 |
| POI・場所情報 | 各サービスのデータ・APIを利用可能 | PMTilesには含まれない | OSMなどのデータや独自DB、外部サービスを利用 |
したがって、MapLibre+PMTilesへの移行では、「地図表示を自前化する」ことと「地図サービス全体を自前化する」ことを分けて考える必要があります。
例えば、背景地図だけを自前のPMTilesとして配信し、住所検索は外部API、ルート検索は別のサービスを利用するという構成も可能です。
コスト構造の比較
MapLibre+PMTilesと商用地図サービスでは、料金が発生する場所そのものが異なります。
商用地図サービス
Google Maps Platformでは地図ロードやPlacesなどがSKU単位で課金されます。Mapbox GL JSもWebではMap Loadを基準とした料金体系です。具体的な料金や無料枠はサービスや契約内容によって変わるため、導入時点の公式料金表を確認する必要があります。
MapLibre+PMTiles
MapLibre GL JSとPMTilesのリファレンス実装はオープンソースとして公開されていますが、実運用では次のようなコストが発生する可能性があります。
- PMTilesを保存するオブジェクトストレージの容量・リクエスト料金
- PMTilesをユーザーへ転送するデータ転送料
- CDNを利用する場合のCDN料金
- 大規模データを生成・更新するためのコンピューティング資源
- ジオコーディング、ルート検索、POIなどを外部サービスで補完する場合の利用料金
つまり、MapLibre+PMTilesが必ず安くなるわけではありません。
一方で、動的タイルサーバーや空間データベースを常時稼働させる必要がない構成にできるため、サービス内容によってはインフラ構成をシンプルにできます。
特に、あらかじめ生成した同じPMTilesを多数のユーザーへ配信するような用途では、CDNキャッシュを利用して同じデータを効率よく配信できる可能性があります。
そのため、移行前には、
現在の構成
↓
タイルサーバー費
DB費
API費
CDN費
転送量
↓
PMTiles構成
↓
ストレージ費
CDN費
転送量
生成処理費
外部API費のように、実際のアクセス数やデータ量をもとに比較することが重要です。
OSM・MapLibre・Protomaps・国土地理院のライセンスと出典表記を確認する
MapLibre GL JSやPMTilesがオープンソースだからといって、そこで利用する地図データまで同じ条件で利用できるわけではありません。
ライブラリ、PMTiles仕様、地図データ、地図スタイルは、それぞれ別のライセンスや利用条件を持つ場合があります。
特にPMTilesでは、「PMTilesの仕様」「PMTilesのリファレンス実装」「PMTilesファイルに格納されているデータ」を分けて考える必要があります。
主要コンポーネントおよびデータソースのライセンス一覧
| コンポーネント / データソース | ライセンス・利用条件 | 主な注意点 |
|---|---|---|
| MapLibre GL JS | BSD 3-Clause | 商用利用・改変が可能なOSS。再配布時はライセンス条件を確認します。 |
| PMTiles リファレンス実装 | BSD 3-Clause | リファレンス実装のライセンス。ソース・バイナリの再配布時はライセンス条件を確認します。 |
| PMTiles仕様 | Public Domain / CC0(該当範囲) | リファレンス実装のBSD 3-Clauseとは分けて考えます。 |
| OpenStreetMap | ODbL | OSMデータを利用する場合は帰属表示が必要。加工・構築したデータベースの配布ではODbLの条件を確認します。 |
| Protomaps Basemaps | 入力データに応じて条件が異なる | OSM由来のタイルセットはOSMのProduced WorkとしてODbL条件が適用され、Web地図などではOSMの表示が必要です。スタイル自体はCC0として公開されています。 |
| 国土地理院のコンテンツ | 国土地理院コンテンツ利用規約等 | 原則として出典表示が必要。編集・加工した場合は、その旨も明記します。対象コンテンツによって追加条件があります。 |
| PLATEAU | CC BY 4.0等のオープンライセンス | データによって政府標準利用規約、CC BY 4.0、ODC BY、ODbLなどがあり、対象データの条件を確認します。商用利用も可能です。 |
| 自治体オープンデータ | 自治体・データセットごとに異なる | 出典表示、商用利用、加工、再配布などの条件を対象データごとに確認します。 |
特に注意したいのが、「Protomaps=単一のライセンス」「PLATEAU=必ずCC BY 4.0」などと一律に判断しないことです。
ProtomapsのBasemapsでは入力データによってライセンス・出典条件が変わります。OSMをもとにしたタイルセットではOSMのライセンス条件が関係する一方、スタイルの著作権はCC0として公開されています。
PLATEAUについても、国土交通省の公式FAQではCC BY 4.0だけでなく、政府標準利用規約、ODC BY、ODbLなど複数のオープンライセンスが使われていると説明されています。
ライセンスに関する2つの重要点
- 「OSSだから地図データも自由」とは限らない
MapLibre GL JSやPMTilesのリファレンス実装にはOSSライセンスが適用されますが、PMTilesに格納するOSMなどの地理データには別の利用条件があります。 例えばOpenStreetMapはODbLで提供されており、利用時にはOpenStreetMapと貢献者への適切なクレジットが必要です。また、データベースとして配布する場合にはODbLの条件を確認する必要があります。 - 加工・変換した場合も元データの利用条件を確認する
GeoJSONやOSM、国土地理院、PLATEAUなどをPMTilesへ変換しても、それによって元データの利用条件がなくなるわけではありません。 例えば国土地理院では、コンテンツを利用する際の出典記載が求められ、編集・加工した場合にはその旨も記載する必要があります。 また、OpenStreetMapではODbLに基づく帰属表示などが必要です。Web地図で利用する場合は、地図画面上に適切なクレジットを表示します。
MapLibre GL JSではAttributionControlやStyle JSONのattributionなどを利用してクレジットを表示できます。ただし、実際に表示すべき内容は使用している地図データやタイルセットの利用条件に従って決める必要があります。
例えばOSM由来のデータを利用する場合は、
© OpenStreetMap contributorsなどの帰属表示を適切な形で掲載します。OpenStreetMap公式でも、Web上での利用について帰属表示とライセンス情報への導線を求めています。
このように、MapLibre+PMTilesは地図タイルの配信構成をシンプルにできる一方、「データをどこから取得し、どの条件で利用・再配布するのか」まで含めて設計することが重要です。
よくある質問(FAQ)
-
MapLibre GL JSでPMTilesを表示するには何が必要ですか?
-
maplibre-glに加えて、PMTilesのJavaScriptライブラリであるpmtilesを利用します。PMTiles公式のMapLibre GL JS向け実装では、
Protocolを作成してmaplibregl.addProtocol('pmtiles', protocol.tile)で登録し、Vector SourceのURLにpmtiles://を指定します。(PMTiles JavaScript README)基本的なコードは次のとおりです。
import { Protocol } from 'pmtiles'; const protocol = new Protocol(); maplibregl.addProtocol('pmtiles', protocol.tile);そして、MapLibre GL JSのStyle JSONでは、
sources: { example: { type: 'vector', url: 'pmtiles://https://example.com/example.pmtiles' } }のように指定します。
pmtiles://のURLに通常のXYZ形式の/{z}/{x}/{y}を追加する必要はありません。PMTiles ProtocolがMapLibreからのタイル要求を受け取り、PMTiles内部のDirectoryを参照して必要なデータを取得します。(PMTiles JavaScript README)
-
PMTilesをAmazon S3やCloudflare R2に置いてMapLibreから読み込めますか?
-
はい。HTTP Range Requestを処理できるように設定すれば、S3やCloudflare R2などのオブジェクトストレージからPMTilesを配信できます。PMTiles公式でもS3互換ストレージを利用する構成が案内されています。(PMTiles公式リポジトリ)
WebアプリとPMTilesの配信元が異なるオリジンになる場合は、ストレージ側のCORS設定も確認してください。
特に確認したいのは次の点です。
- HTTP Range Requestを利用できること
- CORSでWebアプリからのGETリクエストを許可すること
- PMTilesの更新検知に利用されるETagを必要に応じて公開できること
Protomaps公式のS3/R2設定例では、
rangeやif-matchを許可し、etagをExposeする構成が案内されています。(Protomaps PMTiles Cloud Storage)なお、同一オリジンで配信する場合はCORSそのものが不要なケースもあります。
-
PMTilesはオフライン環境(ローカル環境)で使えますか?
-
はい。オフライン環境でも利用できます。
最も分かりやすい方法は、ローカルHTTPサーバーからHTMLとPMTilesを配信する方法です。PMTiles CLIにはローカル配信用の
pmtiles serveコマンドがあります。(Protomaps公式ブログ)pmtiles serve .また、PMTilesのJavaScriptライブラリには
FileSourceが用意されているため、ブラウザのFile APIでユーザーが選択したローカルのPMTilesファイルを読み込む方法もあります。(PMTiles公式リポジトリ)一方、HTMLを
file://で直接開き、通常のHTTP配信と同じ方法で別のローカルファイルを取得する構成は、ブラウザのセキュリティ制約やRange Requestの扱いで問題が起きやすいため、ローカルHTTPサーバーまたはFileSourceを利用する方法が分かりやすいでしょう。
-
GeoJSONからPMTilesに変換するにはどのツールを使えばよいですか?
-
GeoJSONなどをベクタータイル化する場合は、Tippecanoeが代表的な選択肢です。
Tippecanoeは
.pmtilesを直接出力できるため、例えば次のように実行できます。tippecanoe \ -o output.pmtiles \ -l my_layer \ -zg \ --drop-densest-as-needed \ input.geojsonすでにMBTilesを生成するパイプラインがある場合は、PMTiles CLIの
convertコマンドで変換することもできます。pmtiles convert input.mbtiles output.pmtiles大規模なOpenStreetMapデータなどでは、Planetilerを利用してPMTilesを生成する方法もあります。(Planetiler公式リポジトリ)
-
PMTilesやMapLibre GL JSを商用サイトで使えますか?
-
ライセンス条件を確認したうえで、商用サイトやサービスで利用できます。
MapLibre GL JSはBSD 3-Clause Licenseで公開されています。PMTilesについても、リファレンス実装はBSD 3-Clause Licenseで公開され、PMTiles仕様自体はPublic DomainまたはCC0として扱われています。(PMTiles公式リポジトリ)
ただし、PMTilesやMapLibreのライセンスと、PMTilesの中に格納する地図データのライセンスは別です。
例えばOpenStreetMapのデータを利用する場合はODbLに基づく条件を確認し、適切なクレジットを表示する必要があります。(OpenStreetMap公式の著作権・ライセンス情報)
そのため、商用サイトで利用する場合は、
- MapLibre GL JSのライセンス
- PMTiles実装のライセンス
- 使用する地図データのライセンス
- 必要な出典・クレジット
- 再配布や加工に関する条件
をそれぞれ確認してください。

まとめ
従来の動的タイルサーバーの運用や、大量の小分けファイルに悩まされていた開発者にとって、HTTP Range Requestに対応した静的ストレージへ「.pmtiles」ファイルを1つ置くだけで済む構成は、インフラコストと運用負荷を劇的に抑えてくれる画期的なソリューションです。
PMTilesとMapLibre GL JSの組み合わせは、描画エンジンとデータ配信基盤の役割を明確に分担させることで、非常にシンプルで堅牢なWeb地図システムを構築できます。ジオコーディングやルート検索などは別途サービスを組み合わせる必要がありますが、背景地図や各種データの表示・配信に関しては、静的化によるコスト削減と運用効率化のメリットが絶大です。
あわせて読みたい


