Looking to hire Laravel developers? Try LaraJobs

laravel-vector-tiles maintained by itsjustvita

Description
Serve Mapbox Vector Tiles directly from PostGIS in Laravel
Last update
2026/04/09 16:36 (dev-main)
License
Links
Downloads
0

Comments
comments powered by Disqus

Laravel Vector Tiles

Serve Mapbox Vector Tiles (MVT) directly from PostGIS in Laravel. No separate tile server required.

Requirements

  • PHP 8.4+
  • Laravel 13+
  • PostgreSQL with PostGIS extension

Installation

composer require itsjustvita/laravel-vector-tiles
php artisan vector-tiles:install

Usage

Defining Layers

Layers can be defined in config/vector-tiles.php for static definitions, or via the fluent API in a service provider for dynamic, auth-aware layers.

Config-based:

// config/vector-tiles.php
'layers' => [
    'glasfaser_trassen' => [
        'table' => 'trassen',
        'geometry' => 'geom',
        'srid' => 4326,
        'properties' => ['id', 'typ', 'status', 'ausbaustufe'],
        'min_zoom' => 10,
        'max_zoom' => 18,
    ],
],

Fluent API:

use ItsJustVita\VectorTiles\Facades\VectorTiles;

// In a service provider's boot() method
VectorTiles::layer('glasfaser_trassen')
    ->from(Trasse::query()->where('status', 'aktiv'))
    ->geometry('geom')
    ->properties(['id', 'typ', 'status', 'ausbaustufe'])
    ->minZoom(10)
    ->maxZoom(18);

Tiles are served at GET /tiles/{layer}/{z}/{x}/{y}.mvt.

Auth-Aware Tiles

Combine middleware for access control with scopes for per-user data filtering:

VectorTiles::layer('glasfaser_trassen')
    ->from(Trasse::query())
    ->middleware(['auth:sanctum'])
    ->scope(fn (Builder $query, ?User $user) =>
        $user?->isAdmin() ? $query : $query->where('kunde_id', $user?->kunde_id)
    );

Cache Invalidation

Tile cache is automatically flushed when observed models change:

VectorTiles::layer('glasfaser_trassen')
    ->from(Trasse::query())
    ->invalidateOn(Trasse::class);

GeoJSON Endpoint

Each layer also exposes a GeoJSON endpoint with required bounding box filtering:

GET /geojson/{layer}?bbox=9.0,48.0,9.5,48.5&limit=500

MapLibre Integration

Generate source configuration for MapLibre GL JS:

$source = VectorTiles::maplibreSource('glasfaser_trassen');
// Returns: ['type' => 'vector', 'tiles' => [...], 'minzoom' => 10, 'maxzoom' => 18]

$allSources = VectorTiles::maplibreSources();

Configuration

Key Default Description
prefix tiles URL prefix for tile routes
middleware [] Global middleware for all routes
cache.enabled true Enable tile caching
cache.store null Cache store (null = default)
cache.ttl 3600 Cache TTL in seconds
geojson.prefix geojson URL prefix for GeoJSON routes
geojson.default_limit 1000 Default feature limit
geojson.max_limit 5000 Maximum feature limit

Testing

The package provides a fake driver for testing without PostGIS:

use ItsJustVita\VectorTiles\Facades\VectorTiles;

VectorTiles::fake();

$response = $this->get('/tiles/trassen/14/8532/5765.mvt');
$response->assertOk();

VectorTiles::assertTileRequested('trassen', 14, 8532, 5765);

How It Works

The package uses PostGIS functions ST_AsMVT and ST_AsMVTGeom to render vector tiles server-side. Eloquent query builders are supported as layer sources, enabling standard Laravel scopes, relations, and authorization patterns to control tile content.

Tile caching uses Laravel's cache system with a key-registry approach for efficient per-layer flushing. Model observers can automatically invalidate cached tiles when source data changes.

License

MIT