Pack Lifecycle
A Spatial Pack moves through four stages: build, validate, publish, and load. Each stage enforces a specific guarantee — reproducibility, correctness, immutability, or accessibility — so that every pack reaching a consumer is trustworthy and complete.
Building a pack starts with a Pipeline — a YAML file that declares data sources, processing stages, and output formats. The spatialpack CLI reads the Pipeline, executes each stage in dependency order, and writes the results to an output directory.
# Build a pack from a pipeline definitionspatialpack pack build pipeline.yaml -o ./wa-solar-pack/pipeline: name: wa-solar-feasibility version: "1.0"
pack: id: "spatial.properties:wa:solar-feasibility:v1" version: "2025.01.31" theme: solar-feasibility region: bbox: [115.0, -34.5, 117.5, -31.0] crs: "EPSG:4326"
sources: cadastre: path: "data/cadastre.shp" license: CC-BY-4.0
stages: - name: convert_cadastre action: convert.shp input: cadastre output: "layers/cadastre.parquet" options: bbox: ${pack.region.bbox}The build stage produces GeoParquet, PMTiles, and H3-indexed files alongside a spatialpack.json manifest that records every layer, its schema, and its provenance.
Key principle: Reproducibility
Section titled “Key principle: Reproducibility”Given the same Pipeline YAML and the same source data, the build produces identical output. No timestamps or random values are injected unless explicitly configured.
Validate
Section titled “Validate”Validation checks the built pack against the Spatial Pack schema. The validator examines the manifest structure, verifies that every declared layer file exists on disk, and optionally checks integrity hashes.
# Validate a built packspatialpack validate ./wa-solar-pack/
# Strict mode: treat warnings as errorsspatialpack validate ./wa-solar-pack/ --strict
# Output a machine-readable conformance reportspatialpack validate ./wa-solar-pack/ -o report.jsonValidation produces a conformance report with a status of pass, warn, or fail. A failing pack cannot be published.
What gets checked
Section titled “What gets checked”| Check | Description |
|---|---|
| Schema conformance | Manifest matches the JSON Schema (required fields, types, patterns) |
| Layer file existence | Every layer declared in the manifest has a corresponding file on disk |
| Integrity hashes | If the manifest includes SHA-256 hashes, they match the actual file contents |
| License completeness | Every source has a license identifier |
| Provenance | Source attribution is present and non-empty |
Key principle: Governance
Section titled “Key principle: Governance”Validation enforces governance gates before a pack leaves the developer’s machine. License and provenance checks prevent unlicensed data from reaching consumers.
Publish
Section titled “Publish”Publishing uploads a validated pack to a CDN at a versioned, immutable path. The CLI rewrites manifest URIs to point at the CDN domain and sets appropriate cache headers.
# Publish to S3-backed CDNspatialpack pack publish ./wa-solar-pack/ \ --bucket spatial-packs-cdn \ --cdn-domain cdn.spatial.propertiesThe published pack lives at a path like:
https://cdn.spatial.properties/packs/spatial.properties:wa:solar-feasibility:v1/2025.01.31/Key principle: Immutability
Section titled “Key principle: Immutability”Every version publishes to a new path. No file is ever overwritten. If you need to update data, increment the version and publish again. Consumers referencing a specific version always get the same data.
Consumers access a published pack by fetching the manifest and loading individual layers. The manifest acts as an index — it tells the consumer what layers are available, where each file lives, and what schema each layer follows.
import requestsimport geopandas as gpd
# Fetch the manifestmanifest_url = "https://cdn.spatial.properties/packs/.../spatialpack.json"manifest = requests.get(manifest_url).json()
# Load a specific layercadastre = next(l for l in manifest["layers"] if l["id"] == "cadastre")gdf = gpd.read_parquet(cadastre["parquet"])-- Query a remote GeoParquet layer directlySELECT lot_number, area_m2FROM read_parquet('https://cdn.spatial.properties/packs/.../layers/cadastre.parquet')WHERE area_m2 > 5000;// Load PMTiles in a web mapimport { PMTiles, Protocol } from "pmtiles";
const protocol = new Protocol();maplibregl.addProtocol("pmtiles", protocol.tile);
const TILES_URL = "https://cdn.spatial.properties/packs/.../layers/cadastre.pmtiles";map.addSource("cadastre", { type: "vector", url: `pmtiles://${TILES_URL}`,});Key principle: Portability
Section titled “Key principle: Portability”A Spatial Pack is a self-contained directory. Copy it to a USB drive, host it on S3, or serve it from a local file server — the format works everywhere. No proprietary runtime or database server is required.
Full lifecycle
Section titled “Full lifecycle”flowchart LR
A[Pipeline YAML] --> B[Build]
B --> C[Spatial Pack]
C --> D[Validate]
D -->|pass| E[Publish]
D -->|fail| F[Fix & Rebuild]
F --> B
E --> G[CDN]
G --> H[Load]
Summary of principles
Section titled “Summary of principles”| Principle | Stage | Guarantee |
|---|---|---|
| Reproducibility | Build | Same inputs produce same outputs |
| Governance | Validate | License, provenance, and schema compliance |
| Immutability | Publish | Versioned paths, no overwrites |
| Portability | Load | Works offline, on USB, or via CDN |
Next steps
Section titled “Next steps”- Build your first pack — Follow the Getting Started guide to walk through the full lifecycle hands-on.
- Learn the CLI — See the CLI Reference for the complete list of
spatialpackcommands includingpack build,validate, andpack publish.