When you are building mission-critical geospatial infrastructure, the architecture decision usually collapses into two unappealing options.
High-level dynamic frameworks — Python, Node.js — give you developer ergonomics and a rich geospatial ecosystem. Under sustained CPU-bound load, they can also bring higher memory usage and bottlenecks such as Python’s GIL.
Pure compiled binaries — Rust, C++ — give you execution speed and small memory footprints. They also give you complex distributed state management, a steep learning curve for ordinary web routing, and real maintenance overhead once business logic gets involved.
We built TileserveX to find out whether that trade-off is actually necessary: a vector tile engine combining Elixir (Plug and Cowboy 2) with Rust (Rustler NIFs), implementing the OGC API specifications on top.
Architecture
TileserveX deliberately bypasses a full framework like Phoenix in favor of a minimal HTTP execution pipeline, separating web concurrency, state orchestration, and native CPU computation into three layers.
Bare-metal routing: Plug and Cowboy 2
Phoenix has excellent ergonomics for full-stack interactive applications. Serving high-throughput binary vector tiles is a different problem: what you want is minimal pipeline overhead.
Wiring Plug.Router directly into Cowboy 2 avoids controller pipeline stack allocations, parameter parsing overhead, and channel pub/sub setup. Requests are routed and matched directly, streaming packed Protocol Buffer payloads from the storage layer or cache straight to network sockets.
Spatial computation in Rust NIFs
Computational geometry is CPU-bound by nature — line simplification, polygon clipping (Liang-Barsky, Sutherland-Hodgman), coordinate transformations, MVT 2.1 protobuf encoding.
Rather than letting that math block the primary BEAM schedulers, those operations are delegated to Rust NIFs through Rustler, configured on dirty CPU schedulers. Two properties matter here:
- Zero-copy serialization. Vector geometry buffers pass between BEAM memory and the compiled Rust code with effectively no serialization overhead.
- Memory and thread safety at compile time. Rust’s guarantees keep memory leaks and segmentation faults out of the Erlang VM, which is not a place you want either.
OGC API compliance
TileserveX implements the standards a geospatial platform is evaluated against:
- OGC API — Tiles (Part 1): pre-rendered or dynamic vector and raster tiles in standard pyramid schemas.
- OGC API — Features (Parts 1–3): queryable vector datasets with spatial filtering, property constraints, and flexible CRS support.
- OGC API — Processes (Part 1): asynchronous execution of heavy spatial jobs — buffers, centroids, convex hulls — managed through BEAM GenServers.
What the design buys
The hypothesis behind this design is narrow: an Elixir service stripped down to Plug and Cowboy 2 and accelerated by Rust NIFs should keep OTP’s fault tolerance without paying for a framework it does not use.
Process isolation and dirty schedulers are what make that plausible. CPU-bound geometry never blocks the schedulers that answer requests, and a failure in one request stays in that request. When a database goes away, the server answers 503 with Retry-After instead of hanging.
The useful takeaway for anyone making this decision: the choice between compiled execution speed and actor-model concurrency is less binary than it looks. Elixir for connection routing and process isolation, Rust for the heavy spatial math, is a combination worth considering before you commit to either extreme.
