Build custom applications that query your Malloy models via HTTP.
Building a React app? Use the Publisher SDK instead—it wraps these APIs in ready-to-use components with automatic rendering.
Explore the API
Publisher includes an interactive Swagger UI at:
http://localhost:4000/api-doc.htmlUse it to browse endpoints, see request/response schemas, and try API calls directly in your browser.
Full OpenAPI specification: api-doc.yaml
What You Can Do
The REST API lets you:
| Capability | Description |
|---|---|
| Browse models | List environments, packages, and models available on the server |
| Get model schema | Retrieve sources, measures, dimensions, and views defined in a model |
| Execute queries | Run Malloy queries and get JSON results |
| Explore databases | List schemas, tables, and columns from connected databases |
| Check health | Verify server status and initialization |
Quick Example
Run a query against a model. The environment and package below are the samples Publisher serves out of the box, so this works as-is against a server started with no arguments (npx @malloy-publisher/server). If you passed --server_root or --config, substitute your own environment, package and model names.
curl -X POST "http://localhost:4000/api/v0/environments/examples/packages/storefront/models/storefront.malloy/query" \ -H "Content-Type: application/json" \ -d '{"query": "run: order_items -> { aggregate: order_count is count(), total_revenue is sum(sale_price) }", "compactJson": true}'
Response:
{ "result": "[{\"order_count\":25356,\"total_revenue\":2098177.9700000403}]", "resource": "/api/v0/environments/examples/packages/storefront/models/storefront.malloy/query" }
Note that result is a JSON string, not an object, so parse it before use:
JSON.parse(body.result).
compactJson: true gives you the plain array of row objects shown above. Leave it out (the default)
and result contains the full Malloy result instead: the same rows plus the schema and per-cell type
metadata that the renderer needs to draw charts and tables.
Common Patterns
Fetch and Display Data
The query goes in the request body, not the query string. The endpoint accepts POST only.
async function fetchMetrics() { const response = await fetch( 'http://localhost:4000/api/v0/environments/examples/packages/storefront/models/storefront.malloy/query', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: 'run: order_items -> { aggregate: total_revenue is sum(sale_price) }', compactJson: true, }), } ); const body = await response.json(); return JSON.parse(body.result); // -> [{ total_revenue: 2098177.9700000403 }] }
Use Pre-defined Views
Instead of writing queries inline, reference views defined in your model:
// storefront.malloy defines: view: business_overview is { ... } const query = 'run: order_items -> business_overview';
This keeps business logic in the model, not scattered across API calls.
When to Use REST vs SDK
| Use REST API when... | Use Publisher SDK when... |
|---|---|
| Building backend services | Building React frontends |
| Non-JavaScript environments | Want automatic rendering |
| Need full control over requests | Want pre-built components |
| Integrating with existing systems | Rapid dashboard development |
Next Steps
Publisher SDK – React components for embedding analytics
MCP for AI Agents – Connect AI assistants to your models