Build custom data applications with the Publisher SDK. Embed live, governed analytics from your Malloy models directly into React apps.
Try the Example App
The fastest way to understand the SDK is to run the example data app:
# Clone the publisher repo git clone https://github.com/malloydata/publisher.git cd publisher # Start the Publisher server npx @malloy-publisher/server --server_root ./malloy-samples # In a new terminal, run the example app cd examples/data-app cp .env.example .env npm install npm run dev
Open http://localhost:5173 to see a working dashboard with embedded Malloy visualizations.
The example app demonstrates:
Malloy Samples Dashboard – Pre-configured charts from the names dataset
Single Embed – Embedding a single query result
Dynamic Dashboard – Adding charts at runtime
Interactive Dashboard – Using raw data with custom Recharts visualizations
Core Concepts
The SDK has two fundamental building blocks. For complete documentation, see the Publisher SDK README.
1. ServerProvider
Wraps your app and connects to a Publisher server:
import { ServerProvider } from "@malloy-publisher/sdk/client"; import "@malloy-publisher/sdk/styles.css"; function App() { return ( <ServerProvider> <YourDashboard /> </ServerProvider> ); }
By default, connects to http://localhost:4000. For production:
<ServerProvider server="https://analytics.yourcompany.com/api/v0"> <YourDashboard /> </ServerProvider>
2. EmbeddedQueryResult
Renders a Malloy query result. The component picks the visualization automatically—tables for flat data, bar charts for single-dimension aggregates, or whatever renderer tag you specify in your model (e.g., # line_chart).
import { EmbeddedQueryResult } from "@malloy-publisher/sdk"; function MyChart() { const embeddedQuery = JSON.stringify({ modelPath: "orders.malloy", query: "run: orders -> { group_by: region; aggregate: total_revenue }", optionalPackageName: "ecommerce", optionalProjectName: "production" }); return <EmbeddedQueryResult embeddedQueryResult={embeddedQuery} />; }
The optionalPackageName and optionalProjectName parameters are required when your Publisher serves multiple projects or packages—they tell the SDK which model to use.
Installation
npm install @malloy-publisher/sdkImportant: Import the CSS styles in your app entry point:
import "@malloy-publisher/sdk/styles.css";Project Structure
A typical SDK project structure:
my-data-app/ ├── src/ │ ├── main.tsx # App entry with ServerProvider │ ├── Dashboard.tsx # Dashboard with EmbeddedQueryResult │ ├── constants/ │ │ └── widgets.json # Saved embed configurations │ └── components/ │ └── CustomChart.tsx ├── .env # VITE_PUBLISHER_API=http://localhost:4000 ├── package.json └── vite.config.ts
CORS Configuration
If your React app runs on a different port/domain than Publisher, configure CORS or use a proxy.
Vite proxy example (vite.config.ts):
export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:4000', changeOrigin: true, }, }, }, });
Then use relative paths in ServerProvider:
<ServerProvider server="/api/v0">Next Steps
Example App Source – Full working example
REST API – Direct HTTP integration
Explorer – Build queries visually before embedding