Every web map you have ever panned — Google Maps, your food-delivery app, a hiking planner — is built from tiles: small square pieces of map, fetched one by one and stitched together in the browser. This guide explains the whole machine: the tile pyramid, how raster and vector tiles are made, how Leaflet and MapLibre draw them, what retina means, why caching decides everything, and how to choose. Each section links to a live example you can open and copy.
A web map is a pyramid of zoom levels. At zoom 0 the whole world fits on one 256×256 px
tile. Each zoom level doubles the resolution in both directions, so the number of tiles quadruples:
zoom 1 has 4 tiles, zoom 2 has 16… and zoom 19 has about 275 billion. A tile is addressed
by three numbers — z/x/y (zoom, column, row) — which is exactly what you see in a tile URL:
https://tilezza.eu/raster/voyager/12/2264/1432.png
└z┘ └─x─┘ └─y─┘
When you pan or zoom, the map library computes which tiles the viewport touches (typically 6–16 of them), requests the missing ones, and slides the rest. That trick — invented for Google Maps in 2005 and standardised as the "slippy map" scheme — is why a map of the whole planet feels instant: you only ever download the handful of squares you are looking at.
Coordinates use the Web Mercator projection (EPSG:3857). It distorts areas near the poles, but it has one killer property: north is always up and squares stay squares at every zoom.
A raster tile is a finished picture: a 256×256 PNG in which the server has already drawn the roads, water, labels — everything. The browser just displays images; there is nothing left to compute.
OpenStreetMap data (planet, ODbL) → Protomaps build → one big .pmtiles archive (vector data, zooms 0–14) → tileserver-gl + MapLibre GL Native renders the style on the server (~0.3–1 s per tile) → nginx caches the finished PNG on disk for 30 days → every later request for that tile: ~0.6 ms (measured), like any static file
The expensive step is the render. That is why the first visitor to an unexplored corner of the map at a deep zoom waits noticeably, while everyone after them gets the tile instantly — see caching below. It is also why raster tiles cost more of your monthly quota than vector tiles (3 units vs 1 on our pricing): we do the heavy lifting.
A vector tile (.mvt, Mapbox Vector Tile format) contains no pixels at all. It is a compact
binary package of the geometry and attributes inside that square: road centrelines with their class, building
footprints, water polygons, place names with their importance rank. Think of it as "the map's database, cut into
squares".
The drawing happens in your visitor's browser, on the GPU, using a style document — a JSON file that says "motorways are orange, 4 px wide at zoom 10; city labels use Noto Sans 14 px…". The same tiles can look completely different under different styles, and the style can change at runtime without downloading the map again.
| Piece | What it is | On Tilezza |
|---|---|---|
| Tiles | the .mvt data squares | /tiles/{z}/{x}/{y}.mvt |
| Style JSON | colors, widths, fonts, rules | /api/style/voyager (+10 more) |
| Glyphs | pre-rendered font atlases for labels | /fonts/… self-hosted |
| Sprite | one image with all the little icons | /sprites/… self-hosted |
| Renderer | a JS library (MapLibre GL) | served from us too |
Because the browser does the work, the server's job is trivial — it streams bytes out of an archive. Our vector endpoint serves a tile in 1.8 ms median and sustains over 13,000 requests/second on modest hardware. That efficiency is why the free tier is vector-first.
| Raster (PNG) | Vector (MVT + style) | |
|---|---|---|
| Who renders | our server, once, then cached | the visitor's browser, every frame |
| Client requirements | anything that can show images | JS library + WebGL (any phone since ~2016) |
| Zoom feel | steps, slight blur between levels | continuous, always sharp |
| Rotation / tilt | no | yes |
| Restyle / recolor | pick another pre-made style | anything, at runtime, per-URL |
| Label language | as rendered | ?lang=de — your choice |
| Bandwidth | ~15–70 KB / tile | ~5–50 KB / tile + one-time fonts |
| Integration effort | 1 line in Leaflet | 2 script tags + 3 lines |
| Cost to serve (us) | render CPU + cache disk | almost nothing |
| Quota weight (Tilezza) | 3 units (retina 5) | 1 unit |
Neither is "better". Raster is the universal, zero-effort option; vector is the modern, flexible, cheap-to-serve option. Big consumer maps (Google, Apple, Mapbox-based apps) are vector; embedded widgets, e-mail maps, print workflows and very-low-end device audiences are raster.
The most popular map library on the web. DOM/Canvas based, tiny, thousands of plugins, wonderfully simple: one line adds a raster layer. It does not render vector tiles natively — with Leaflet, use our raster endpoints. Ideal for: content sites, dashboards, anything embedded.
The open-source successor of Mapbox GL JS (forked when Mapbox closed its license in 2020). Renders vector tiles on the GPU via WebGL: continuous zoom, rotation, pitch, runtime styling, collision-aware labels. This is what "app-like" maps use. Ideal for: products, SaaS dashboards, anything interactive.
The veteran GIS workhorse. Reads practically every geo-format ever invented (WMS, WMTS, GeoJSON, KML, MVT…), strong in projections and scientific/enterprise GIS. Renders vector tiles on Canvas — functional, somewhat less silky than GL. Ideal for: GIS-heavy applications that already live in the OpenLayers ecosystem.
All three work with Tilezza — raster with any of them, vector best with MapLibre (see the MapLibre quickstart).
Modern phone screens pack 2–3 physical pixels into each CSS pixel. A normal 256 px tile gets stretched and
looks slightly soft. A @2x tile is rendered at 512×512 for the same geographic square, so labels stay
razor-sharp. The cost: roughly 3–4× the bytes and double the render work — which is why it counts 5 quota units and
lives in the paid tiers. In Leaflet it is literally one option: detectRetina: true
(example 5). Vector maps do not need any of this: they render at the screen's native
resolution by definition — another point for vector on mobile.
Tile serving is a cache game. The pyramid is enormous, but visitors cluster on the same places: city centres at z10–16, whole countries at z6–8. Three cache layers work for you:
Browser cache — we send Cache-Control: public, max-age=604800; a returning visitor re-downloads
nothing. Our disk cache — every rendered raster tile is kept ~30 days; measured effect: a cold render takes
~0.3–1 s, a cached hit 0.6 ms — a ~1000× difference. Your CDN (optional) — you may put your own CDN
in front of Tilezza; its hits never reach us and cost you nothing (we count only requests that arrive at our
servers — that is the metering rule, in writing).
Raster: choose among 11 pre-made styles (10 raster + the vector-only indigo). Vector: the same styles become starting points — override colors straight in the style URL, no build step:
https://tilezza.eu/api/style/voyager?key=YOUR_KEY
&water=0088ff ← any layer color (water, land, parks, forest,
&boundaries=cc3355 roads, highway, buildings, boundaries, labels)
&labels=333333
&lang=de ← label language
&font=Montserrat ← label typeface (self-hosted glyphs)
&hide_pois=1 &lite=1 ← decluttering / mobile mode
Beyond the URL parameters, MapLibre lets you change anything at runtime
(map.setPaintProperty('water','fill-color','#004')). This split is worth internalising:
raster = pick a look, vector = own the look. Play with it live in
example 3.
Every tile request carries the visitor's IP address and referer to whoever hosts the tiles. If your map loads tiles, fonts or the map library from US-controlled CDNs, your visitors' data crosses jurisdictions before your page even finishes loading — the exact pattern European DPAs sanctioned in the Google-Fonts rulings.
Tilezza's answer is boring on purpose: everything first-party, everything in the EU. Tiles, styles, font glyphs, sprites — and even the JS libraries — come from one EU-operated host. Our access logs are IP-free by design (we cannot leak what we never store), and there are no third-party requests to disclose in your privacy policy.
The last stray third-party request on most map pages is the library itself (unpkg, jsDelivr, cdnjs — all US-controlled). Skip it: we serve pinned, immutable copies of both libraries. Copy-paste and your page makes zero non-EU requests:
<!-- Leaflet 1.9.4 (raster maps) --> <link rel="stylesheet" href="https://tilezza.eu/lib/leaflet-1.9.4.css"> <script src="https://tilezza.eu/lib/leaflet-1.9.4.js"></script> <!-- MapLibre GL 5.6.0 (vector maps) --> <link rel="stylesheet" href="https://tilezza.eu/lib/maplibre-gl-5.6.0.css"> <script src="https://tilezza.eu/lib/maplibre-gl-5.6.0.js"></script>
Versioned filenames, long immutable caching, open CORS. The default Leaflet marker images are
included (/lib/images/…). We add new versions under new names — your pinned URL never changes
behaviour under you.
| Your situation | Use |
|---|---|
| "I want a map on my site with the least effort" (blog, contact page, WordPress) | Raster + Leaflet — 5 lines, done |
| Product / dashboard with interaction, custom brand colors | Vector + MapLibre + style API |
| Audience on very old / weak devices | Raster |
| Mostly mobile audience, sharpness matters | Vector (native-resolution rendering) |
| Existing GIS stack, exotic projections, WMS neighbours | OpenLayers (raster or vector) |
| Free tier, maximum value | Vector — 1 unit per tile, all 11 styles, full zoom |
Get a free API key Open the live examples
You hit uncached raster tiles: the server renders each one (~0.3–1 s). The result is cached for weeks, so this is a first-visitor cost, concentrated in rarely-visited areas. Vector tiles do not have this problem.
No — a renderer (MapLibre/OpenLayers) must run in the browser. If you cannot add scripts, use raster tiles, which work as plain images.
Yes. The endpoints are standard XYZ (raster) and TileJSON+MVT (vector) — QGIS, MapLibre Native (iOS/Android), and most SDKs accept them directly with your API key.
Every tile request that reaches our servers, weighted by cost: vector 1, raster 3, retina 5 units. Your own CDN's cache hits are free. Full details on the pricing page — or watch it live on the usage meter.
OpenStreetMap contributors (ODbL license), packaged through the Protomaps pipeline, refreshed monthly. Attribution is embedded in every style — please keep it visible.