Skip to content
GuidesBlogPlaygroundDashboard

PlazaQL Overview

Plaza's query language for geospatial data. LINQ-style method chaining, type-safe, compiles to optimized SQL.

PlazaQL is Plaza’s query language for geospatial data. It uses LINQ-style method chaining to express searches, spatial filters, routing, geocoding, and set operations in a single readable query. Every PlazaQL query compiles to optimized SQL with automatic H3 tile indexing — you write what you want, Plaza figures out how to get it fast.

A bare expression like search(amenity: "cafe"); is treated as an implicit output — equivalent to writing $$ = search(amenity: "cafe");. Use explicit $$ = assignment when contrasting with named outputs ($$.name =) or when you prefer the clarity.

search(amenity: "cafe")
.around(distance: 500, geometry: point(38.9, -77.0));

Search for cafes within 500 meters of a point in Washington, DC. The result is a GeoJSON FeatureCollection with every matching node.

$berlin = boundary(name: "Berlin");
search(amenity: "cafe")
.within(geometry: $berlin)
.limit(count: 50);

Resolve Berlin’s boundary, then find cafes inside it. Variables ($berlin) store intermediate results so you can reuse them.

$r = route(origin: point(40.748, -73.993), destination: point(40.755, -73.970), mode: "auto");
search(amenity: "pharmacy")
.around(distance: 200, geometry: $r)
.sort(distance($r))
.limit(count: 10);

Compute a driving route across Midtown Manhattan, then find the 10 closest pharmacies within 200m of it, sorted by distance.

Send PlazaQL via the /api/v1/query endpoint:

Terminal window
curl -X POST https://plaza.fyi/api/v1/query \
-H "x-api-key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "search(amenity: \"cafe\").around(distance: 500, geometry: point(38.9, -77.0));"
}'
import Plaza from "@plazafyi/sdk";
const client = new Plaza();
const cafes = await client.v1.query.run({
query: `search(amenity: "cafe")
.around(distance: 500, geometry: point(38.9, -77.0));`,
});
for (const cafe of cafes.features) {
console.log(cafe.properties.name);
}
import plaza
client = plaza.Client()
cafes = client.v1.query.run(
query='search(amenity: "cafe").around(distance: 500, geometry: point(38.9, -77.0));'
)

Response is always a GeoJSON FeatureCollection.

Variables start with $, are assigned with =, and are immutable:

$center = point(48.85, 2.35);
$radius = 1000;
search(amenity: "museum")
.around(distance: $radius, geometry: $center)
.limit(count: 20);

Rules:

  • Variables must be assigned before use (no forward references)
  • Variables are immutable — assign once, use many times
  • Variable names are $lowercase_with_underscores

Variables make queries readable and let you reuse expensive computations:

$berlin = boundary(name: "Berlin");
$$.cafes = search(amenity: "cafe").within(geometry: $berlin);
$$.bars = search(amenity: "bar").within(geometry: $berlin);

The boundary() call resolves once and both searches reuse the result. When multiple outputs share the same filters, use global directives to avoid repetition:

#within(boundary("Berlin"))
#limit(50)
$$.cafes = search(amenity: "cafe");
$$.bars = search(amenity: "bar");
$$.restaurants = search(amenity: "restaurant");

Named outputs ($$.name) are also referenceable as values in later statements — see Multiple outputs. Use $var for shared intermediate values that aren’t outputs, and $$.name for values that are both outputs and reused later.