Starter repo
Clone the starter template with build tooling, runtime, and examples
Component reference
Full props documentation for all UI components
When to use data apps vs YAML dashboards
| YAML Dashboard | Data App |
|---|---|
| Standard charts, tables, KPIs | Custom interactive UI (expandable rows, conditional formatting) |
| Multiple tiles in a grid layout | Single full-screen experience |
| Cube/SQL datasets with built-in viz | Custom JavaScript visualizations (ECharts, Perspective.js) |
| Quick to build with Fi | Source-authored React with component library |
| No build step required | Compiled to single HTML via build tool |
How data flows
- app.json declares every data resource the app needs. Each resource has a key, a
kind, and asource(SQL, Cube, or file). - The Definite platform reads the manifest and fetches data server-side from DuckLake, Cube, or GCS. The app never talks to the warehouse directly.
- The runtime loads the fetched data into a browser-side DuckDB WASM instance as local tables.
kind: "dataset"resources become DuckDB tables;kind: "json"resources are returned as plain arrays. - App.tsx queries those local tables via
useSqlQuery(dataset, sql, deps). These queries run in the browser against DuckDB WASM, not against the server.
Column names in your
useSqlQuery SQL must match the aliases in your app.json SQL. If app.json has SELECT foo AS myColumn, the local table column is myColumn. Mismatches cause “Binder Error: Referenced column not found” at runtime.Quick start
Clone the starter repo and create a new app:examples/my-app/ with:
Step 1: Define your data in app.json
Declare the data resources your app needs:Step 2: Build your UI in App.tsx
Step 3: Build
examples/my-app/dist/index.html. The build validates that all useDataset() and useJsonResource() calls reference keys that exist in app.json.
Step 4: Deploy
Uploaddist/index.html to Definite Drive (via the MCP server or UI) and create a Doc with a full-screen HTML tile:
Manifest resources
Resource kinds
| Kind | Hook | Use for |
|---|---|---|
dataset | useDataset(key) | Data loaded into browser DuckDB WASM as a queryable table |
json | useJsonResource(key) | Small lookup lists returned as plain arrays (dropdowns, config) |
Source types
| Type | Description |
|---|---|
sql | SQL executed server-side against DuckLake. Recommended. |
duckdbFile | A .duckdb file downloaded from Drive/GCS and attached locally |
cube | Cube semantic model query. Not recommended for data apps. |
Public embeds
For publicly shared Docs, resources need asnapshot block:
Runtime hooks
The runtime library provides React hooks for data loading and querying:| Hook | Returns | Purpose |
|---|---|---|
useDataset(key) | DatasetHandle | Load dataset into browser DuckDB, get tableRef for SQL |
useSqlQuery(dataset, sql, deps) | QueryState<T> | Run client-side SQL against loaded dataset |
useJsonResource(key) | QueryState<T> | Load JSON resource as array |
useTheme() | { theme, toggleTheme } | Dark/light mode |
usePerspective(dataset) | { client, perspectiveTable } | Initialize Perspective viewer for a dataset |
useDataset, useJsonResource) cache results in IndexedDB with a 24-hour TTL. Call refresh() on the returned handle for a hard refresh.
UI components
The runtime includes a full component library. See the component reference for detailed props.| Category | Components |
|---|---|
| Layout | AppShell, Card, TabGroup |
| Data display | KpiCard, DataTable, ReportTable, Badge |
| Charts | EChart, PerspectivePanel |
| Inputs | Select, MultiSelect, FilterPills, TextInput, DateInput |
| Feedback | LoadingState, ErrorState, Tooltip, ResourceCacheBadge |
Best practices
- Always use SQL resources (
type: "sql") over Cube resources for data apps. You control column names via aliases. - Alias columns to camelCase in
app.jsonSQL. Convert dates withSTRFTIME(col, '%Y-%m-%d'). - Keep client-side SQL simple. Use
app.jsonSQL for joins, CASE WHEN, and complex filters. UseuseSqlQueryonly for GROUP BY, SUM of pre-computed columns, and date range filters. - Cast SUM results to
::INTEGERin client-side SQL. DuckDB WASM may return HUGEINT which JavaScript can’t handle cleanly. - Pre-compute conditional flags in
app.jsonSQL. DuckDB WASM has known issues with compoundCASE WHENexpressions (they silently return 0).
Caching
The runtime caches data loads in IndexedDB with a 24-hour TTL. Cache keys include the resource key, mode, and manifest definition, so rebuilt apps invalidate automatically. UseResourceCacheBadge in your AppShell meta slot to show cache status and provide a “Clear cache & reload” button.
Next steps
Starter Repo
Full starter template with build tooling, examples, and component reference
Agent Reference
Programmatically create data apps via the MCP server or AI agents
Tile Types Reference
Configuration options for all tile types including HTML tiles

