SvelteKit Example
A SvelteKit 2 application with Svelte 5 that renders a MapLibre vector tile map and adds places search. Uses a SvelteKit server endpoint as the token proxy.
Prerequisites
- Node.js 18+
- A Geog API key (create one in the console)
Quick Start
git clone https://github.com/geogdev/examples.git
cd examples/frameworks/sveltekit-maplibre
npm install
cp .env.example .env
Add your API key to .env:
GEOG_API_KEY=your-api-key-here
Start the dev server:
npm run dev
Open http://localhost:5173.
Project Structure
| File | Description |
|---|---|
src/routes/api/geog-token/+server.ts | Server endpoint — token exchange with caching at 80% TTL |
src/lib/geog.ts | Typed API client with token exchange and places search functions |
src/routes/+page.svelte | Main page — map rendering and search UI in a single component |
.env.example | Environment variable template |
How It Works
Server Endpoint
The API key stays server-side. A SvelteKit server endpoint handles token exchange:
// src/routes/api/geog-token/+server.ts
import { env } from "$env/static/private";
let cachedToken: TokenResponse | null = null;
let tokenExpiresAt = 0;
export const GET: RequestHandler = async () => {
const now = Date.now();
if (cachedToken && now < tokenExpiresAt) {
return json({
access_token: cachedToken.access_token,
expires_in: cachedToken.expires_in,
});
}
cachedToken = await exchangeToken(env.GEOG_API_KEY);
tokenExpiresAt = now + cachedToken.expires_in * 1000 * 0.8;
return json({
access_token: cachedToken.access_token,
expires_in: cachedToken.expires_in,
});
};
SSR-Safe MapLibre Import
MapLibre requires the DOM, so it's imported dynamically inside onMount to avoid SSR errors:
<script lang="ts">
import { onMount } from "svelte";
let mapContainer: HTMLDivElement;
onMount(async () => {
const maplibregl = await import("maplibre-gl");
// Fetch token from server endpoint
const res = await fetch("/api/geog-token");
const { access_token } = await res.json();
const map = new maplibregl.Map({
container: mapContainer,
transformRequest: (url) => {
if (url.startsWith("https://api.geog.dev")) {
return {
url,
headers: { Authorization: `Bearer ${access_token}` },
};
}
},
// ...
});
});
</script>
Svelte 5 Runes
The example uses Svelte 5 runes for reactive state:
<script lang="ts">
let query = $state("");
let results: Place[] = $state([]);
let isSearching = $state(false);
</script>
Full Source
github.com/geogdev/examples/tree/main/frameworks/sveltekit-maplibre
See Also
- Examples Overview — All examples and the integration pattern
- Token Exchange API — Endpoint specification
- Vector Tiles API — Tile endpoint reference
- Places API — Search endpoint reference
- Styles & Sprites — Hosted themes, sprites, and npm packages