evidence Documentation

Business intelligence as code: build fast, interactive data visualizations in SQL and markdown

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy evidence on any server, homelab, or cloud container platform.

Technical Documentation: evidence-dev/evidence

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

How It Works

Evidence is an open-source, code-based alternative to drag-and-drop business intelligence tools.

  • Create reports in code using SQL and markdown
  • Develop using Evidence's Agent, or on your local machine with Claude Code / Cursor etc
  • Self-host or publish on Evidence Studio

Install

macOS / Linux

bash
curl -fsSL https://evidence.studio/install.sh | sh
evidence help

Windows

powershell
irm https://evidence.studio/install.ps1 | iex
evidence help

Create a Project

bash
evidence init my-project
cd my-project
evidence dev

Publish

Publish your project on Evidence Studio for hosted reports, or self-host the generated static site on your own infrastructure. See the publishing docs for options.

Join the Evidence Community

Join our Slack channel to get involved in the community's discussion, share what you're working on, or ask for help.

Contributing

Contributions are welcome — see CONTRIBUTING.md for how pull requests are reviewed and merged.

License

Evidence is licensed under the MIT license. See LICENSE for details.


Overview (`cli/README.md`)

EVD

Evidence Studio local development CLI.

Quick Start

bash
# Install dependencies (from monorepo root)
pnpm install

# Run a CLI command from source — instant, no build (defaults to cli/test-environment)
pnpm evd query "select 1"
pnpm evd help

# Run the dev server from source against the test playground
pnpm evd dev

# Build the CLI binary (requires Bun installed globally)
pnpm cli:build

# Run the binary
./cli/dist/evidence
./cli/dist/evidence --help
./cli/dist/evidence dev --port 8080

Architecture

text
/* Detailed source-code truncated for AI context efficiency. */

Project Structure

text
.
├── adapter/
│   └── index.js          # Custom SvelteKit adapter
│                         # - Discovers & embeds static assets
│                         # - Generates manifest
│                         # - Compiles binary with Bun
│
├── cli/
│   ├── index.ts          # CLI entry point
│   ├── args.ts           # Argument parsing, help, banner
│   └── server.ts         # Bun HTTP server + SvelteKit integration
│
├── src/
│   ├── routes/           # SvelteKit routes (the actual app)
│   ├── lib/              # Shared components
│   └── app.html          # HTML template
│
├── static/               # Static assets (favicon, etc.)
├── dist/                 # Build output (gitignored)
│   └── evd               # The compiled binary
│
├── svelte.config.js      # SvelteKit config (uses ./adapter)
├── vite.config.ts        # Vite config
└── package.json

How It Works

1. Asset Embedding

The magic that makes a single binary possible. During build:

javascript
// adapter/index.js generates imports like:
import favicon_SVG_a1b2 from '../client/favicon.svg' with { type: 'file' };

export const assetMap = new Map([
	['/favicon.svg', favicon_SVG_a1b2]
	// ... all static files
]);

Bun's { type: "file" } import attribute embeds the file contents into the binary.

2. The Adapter

adapter/index.js is a custom SvelteKit adapter that:

  1. Writes SvelteKit output - client assets, prerendered HTML, server code
  2. Generates asset imports - creates assets.generated.ts with embedded file references
  3. Generates manifest - SvelteKit's routing manifest
  4. Compiles - runs bun build --compile to create the binary

3. The CLI

cli/ contains the runtime code that gets compiled:

  • args.ts - Parses --port, --help, --version, etc.
  • server.ts - Starts Bun.serve(), handles static assets & SSR
  • index.ts - Wires it together, handles commands

4. Request Flow

text
Request → Bun.serve()
            │
            ├─→ Static asset? → Serve from embedded assetMap
            │
            ├─→ Prerendered route? → Serve embedded HTML
            │
            └─→ Otherwise → SvelteKit SSR

Development

Prerequisites

  • Bun v1.2.18+ (required for running CLI source and for binary compilation)
  • pnpm (for package management)

Day-to-day workflow

What you're working on Run Build needed?
evidence dev flow / Svelte routes pnpm evd dev no
Other CLI commands pnpm evd <cmd> no
Final binary smoke test pnpm cli:build yes

Both scripts default to the cli/test-environment playground regardless of where you invoke them from. Pass --project to override the target directory.

Quick Install: Add `evidence` to Your PATH

After building the CLI binary, you can add it to your PATH for convenient global access:

bash
# Symlink the binary to a directory in your PATH (requires sudo)
sudo ln -sf "$(pwd)/cli/dist/evidence" /usr/local/bin/evidence

# Verify it works
which evidence
evidence --version

Benefits of this approach:

  • Always reflects the latest dist/evidence after rebuilds (no re-install needed)
  • Works everywhere (scripts, subshells, GUI tools)
  • Easy to revert (see below)

Undo the symlink:

bash
# Remove the symlink
sudo rm /usr/local/bin/evidence

# If you want to restore the previous binary (backup created during install)
sudo mv /usr/local/bin/evidence.old /usr/local/bin/evidence

Note: If you built the CLI elsewhere, replace the path accordingly. You can also prepend a user bin directory to your PATH instead of using /usr/local/bin if you prefer not to use sudo.

Examples — all run from the monorepo root

bash
pnpm evd help
pnpm evd query "select 1"                  # against cli/test-environment (NDJSON)
pnpm evd --project ./some/dir validate     # override to an arbitrary project
pnpm evd dev --port 5173                   # extra flags forward to the dev server

Output formats

Data commands are machine-readable by default; the human view is opt-in via
--verbose. Output is identical whether or not stdout is a terminal (there is
no TTY detection). All formatting is centralized in cli/output.ts
(printResult / renderResult / fail) — commands never call JSON.stringify
or render tables directly.

Defaults (no flags):

  • Result sets (query, describe, schema) → NDJSON, one JSON object per line.
  • Name lists (tables) → plain schema.table, one per line.
  • Structured/list results (connectors, models, lineage, docs) → compact JSON.
  • No ANSI color and no box-drawing characters, ever, by default.

Shared flags on every data command:

Flag Effect
--verbose Human view: pretty aligned table + full/extra columns
--format <fmt> json, ndjson, csv, table (table = pretty). Wins over --verbose.
--columns <a,b,c> Select and order columns
--limit <n>, -l Limit rows (query defaults to 1000; a stderr note flags truncation)
--all Remove the row limit
--no-color Disable color (the NO_COLOR env var is also honored)

Errors go to stderr; under --format json/ndjson they are emitted as
{"error":<msg>,"code":<str>}. Status/progress chatter also goes to stderr.

Breaking changes (vs. the previous human-first defaults):

  • Default output is now NDJSON/plain/compact-JSON instead of pretty tables.
    Use --verbose for the old human view.
  • -v now means --verbose. Use --version (or the version subcommand)
    for the version.
  • --columns now takes a value (column selection) instead of being a boolean
    "columns-only" toggle — that role is now describe's default.
  • --format is long-form only; -o/--output keeps its "write to
    file" meaning. --json still works as an alias for --format json.
  • query no longer pretty-prints by default and caps output at 1000 rows
    unless --all is passed.

evd dev detects that it's running from source (via process.execPath) and routes through vite dev automatically — same auth + Studio health check as the binary, then spawns vite dev. Browser auto-open defaults to off in source mode (pass --open to opt back in); the binary still auto-opens by default.

What works under `evd` (no build)

The commands that are pure TypeScript and don't need the SvelteKit bundle: help, version, login, logout, whoami, orgs, switch, token, query, tables, describe, schema, connectors, models, lineage, upgrade.

What still needs `cli:build` (or the dev server)

validate and docs go through SvelteKit's HTTP layer, which uses import.meta.glob — a vite-only construct. Two options:

  • Run pnpm cli:build once, then ./cli/dist/evidence validate reflects the latest source. (You only need to rebuild when SvelteKit-side code changes.)
  • Or run pnpm evd dev and hit the same endpoints directly: curl http://localhost:3000/api/validate.

Other commands

bash
pnpm cli:build       # Build production binary
pnpm cli:check       # Type check
pnpm cli:lint        # Lint & format check
pnpm --filter @evidence/cli format

Dev vs Production

Aspect pnpm evd dev ./dist/evidence
Server Vite dev server (spawned) Bun.serve()
Assets Served from disk Embedded in binary
HMR Yes No
Auto-open No (pass --open) Yes
SSR Yes Yes
Size N/A ~50MB single file

Adding CLI Commands

Edit cli/args.ts to add new commands:

typescript
// In parseArgs():
if (firstArg === 'mycommand') command = 'mycommand';

// In cli/index.ts:
case 'mycommand':
  // do something
  break;

Data-producing commands should route their results through printResult (from
cli/output.ts) using the shared args.output options, rather than calling
JSON.stringify or rendering tables themselves — this keeps the machine-first
defaults, --format, --columns, --limit, and color handling consistent
across every command.

Modifying the Adapter

The adapter in adapter/index.js controls the build process. Key functions:

  • discoverAssets() - Finds all files to embed
  • generateAssetImports() - Creates the import statements
  • adapt() - Main build orchestration

Docker Image

The CLI is published as a Docker image, evidencedev/serve (Docker Hub), so that self-hosting a project is a two-line Dockerfile:

docker
FROM evidencedev/serve:latest
COPY --chown=evidence:evidence . /project

That's the whole point of the image — a user self-hosting a project should never have to figure out how to install the CLI inside a container. cli/Dockerfile handles fetching the right binary for the architecture, CA certificates (without them, TLS to the warehouse fails at runtime), a non-root evidence user, /project as the working directory, honouring a platform-provided $PORT, and starting evidence serve --host 0.0.0.0. The user's layer is just "copy my project in".

It ships on a version bump

The image does not build the CLI. Its first stage downloads an already-published binary from Vercel Blob:

text
https://.../cli/v${EVIDENCE_VERSION}/evidence-${target}

So a new image only appears when a new CLI version is released. In .github/workflows/cli-release.yml, the docker job has needs: release — it cannot run until the release job has uploaded binaries for that version. There is no way to rebuild the image against unreleased CLI code: bump VERSION in cli/cli/args.ts, add the cli-release label to the PR, and merge.

Also bump the ARG EVIDENCE_VERSION default in cli/Dockerfile to match. CI overrides it, but anyone running docker build -f cli/Dockerfile . by hand gets whatever the default says.

Tags and platforms

  • evidencedev/serve:<version> on every release.
  • evidencedev/serve:latest only for stable versions — a version containing - (0.9.2-alpha.1) never moves latest.
  • Built for linux/amd64 and linux/arm64 via QEMU + Buildx. Pushed with the DOCKERHUB_USERNAME / DOCKERHUB_TOKEN secrets.

The docker job lives in the release workflow rather than its own file because the cli-v* tag is pushed with GITHUB_TOKEN, which cannot trigger another workflow.

Telemetry

The CLI reports anonymous usage — to opt out run evidence telemetry disable, or set EVIDENCE_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1. The full payload is documented at https://docs.evidence.studio/cli#telemetry.

Events go to POST /api/cli/event in studio (studio/src/routes/api/cli/event/), which allow-lists fields and forwards to PostHog. Three rules keep the "unique users" number honest: serve runs and the daily serve_heartbeat never create a PostHog person (count deployments by project_id instead), a machine id that cannot be persisted is sent as null rather than a fresh UUID per run, and the first run inside an agent sandbox or container is flagged sandbox and recorded personless. Authenticated CLI usage of Studio is captured server-side as cli_studio_request in authenticateCliRequest, keyed to the user's email and organization group, so it is not subject to client opt-out.

License

MIT


Overview (`docs/README.md`)

Evidence Docs

Autogenerated Components and Data Sources Docs

The following directories are autogenerated by scripts in the scripts/docs:

  • components - All user components
  • data-sources - All data sources

Do not edit these files manually! Instead run the docs generation scripts:

text
npm run docs:generate-components
npm run docs:generate-connectors

Development

Install the Mintlify CLI to preview the documentation changes locally. To install, use the following command

text
npm i mint

Run the following command at the root of your documentation (where docs.json is)

text
mint dev

Overview (`cli/test-environment/README.md`)

CLI dev playground

This directory is the local Evidence project the CLI is exercised against during development. Drop a connection.yaml here (gitignored) pointing at your dev warehouse and the scripts below will pick it up.

Setup

Create cli/test-environment/connection.yaml. Snowflake + dbt source files for this directory will be added in follow-up work — for now a minimal config is enough to exercise CLI commands.

Run from the monorepo root

bash
# A CLI command, against this directory (the default)
pnpm evd help
pnpm evd query --sql "select 1"

# Dev server, against this directory (vite dev under the hood, no binary build)
pnpm evd dev

validate and docs go through the SvelteKit HTTP layer (which uses vite-only constructs), so they need either a binary build (pnpm cli:build) or a running dev server. See the main cli/README.md for the full breakdown.

These scripts work from anywhere inside the monorepo — they don't cd into this directory, they pass --project cli/test-environment to the CLI so process.cwd() semantics still resolve correctly. To target a different project, append --project ./other/path to either script.

Behind the scenes

  • --project chdirs the CLI process and sets EVIDENCE_PROJECT_CWD so the SvelteKit dev server (which runs with cwd = the cli package) can find your project files via getProjectCwd().
  • evd dev detects "running from source" via process.execPath and routes through vite dev instead of the compiled Bun server. Browser auto-open is off by default in source mode; pass --open to opt in.

Overview (`docs/components/README.md`)

Component Docs

Autogenerated Components Docs

These docs are autogenerated by the scripts/generate-components-docs.ts script. Do not edit these files manually!

To regenerate the docs, run the following command:

text
npm run docs:generate-components

Overview (`docs/data-sources/README.md`)

Data Source Docs

Autogenerated Data Source Docs

These docs are autogenerated by the scripts/generate-connector-options.ts script. Do not edit these files manually!

To regenerate the docs, run the following command:

text
npm run docs:generate-connectors

Overview (`core/src/user-components/UserComponentModel/README.md`)

UserComponentModel

UserComponentModel is the foundation for all of our user-facing data components (tables, dimensions, measures, pivots, etc).
Think of it like the blueprint for every component: it defines the rules for how components talk to each other, what data they hold, and how they can be serialized/deserialized during SSR.

Why is it abstract?

An abstract class is like a "template" that you can't use directly.
You don't create a UserComponentModel on its own—you only create subclasses like TableModel or DimensionModel that fill in the blanks.

This lets us:

  • Define shared rules once (e.g. parent/child validation, attribute reactivity, serialization).
  • Ensure every subclass plays by the same rules, while still giving them the freedom to customize.

Analogy:

  • Abstract class = "You must have wheels, but you can decide if you're a car, a bike, or a skateboard."

Attributes

Every UserComponentModel accepts a MaybeGetter for the component's attributes in its constructor argument. MaybeGetter is used to allow the attributes to be either a plain value (Record<string, unknown>) or a function that returns a value (a getter: () => Record<string, unknown>). Accepting a function is necessary for reactivity when passing state around. Reactivity isn't always necessary (like on the server during SSR)
so its a MaybeGetter.

In the constructor, the attributes use something called useStable. This prevents reactivity churn when the user is typing in the editor. When the user types, a new Markdoc RenderableTree is generated with every keystroke (after a debounce). This means that every model gets a brand new attributes object each time, which would cause all of the queries to re-run. To prevent this, useStable only returns a new value if the state has actually changed by doing a recursive comparison of values all the way down objects and arrays.

Parents and Children

  1. Parent

    • The "container" this model lives inside.
    • Example: A DimensionModel can only exist inside a TableModel.
  2. Children

    • Models that live inside this one.
    • Example: A TableModel can contain multiple DimensionModel and MeasureModel children.

This creates a tree structure with our models that mimics the RenderableTree from markdoc. It enables parents and children to depend on and interact with each other to run queries.

Why we check parent/child at runtime

Even though TypeScript checks parent/child relationships at compile time, we also validate them at runtime (isValidParent and isValidChild). This is necessary because the user's input is completely dynamic and they could build components with invalid parent/child relationships, which would result in us creating models with invalid parent/child relationships. By checking the types of parents/children, we make sure we fail fast with a clear error rather than something failing obscurely down the line.

ts
const dimension = new DimensionModel(...);
table.addChild(dimension); // ✅ Works

const measure = new MeasureModel(...);
dimension.addChild(measure); // ❌ Throws runtime error

Serialization and SSR

Serialization and Deserialization is the process of converting a complex object into a JSON representation and then back again. This process is necessary because only JSON can be sent from the server to the client, not classes, functions, or other complex entities.

If a component needs to be serializable, it should specify its serialized type via the Serialized generic, implement the toSerialized function to return its serialized data, and perform necessary deserialization using the serialized data in the model constructor.

Note: We don't have to serialize all the way down to JSON! SvelteKit uses devalue under the hood which supports some more complex types like Date and Map.

Generics

What even are generics?

Generics are a way of writing code that is flexible but still type-safe.

Think of them as placeholders for types. Instead of hard-coding "this must always be a string" or "this must always be a number," we say "this can work with any type, but once you pick the type, it stays consistent."

For example, imagine we need a function that ensures something is always an array. We can pass it an argument that may or may not be an array, and it will ensure that what is returned is an array. This kind of function doesn't care if we're dealing with an array of strings, numbers, or anything else. We can use generics to make the types behave nicely with any kind of input.

ts
function makeArray<T>(input: T | T[]): T[] {
	return Array.isArray(input) ? input : [input];
}

const example1 = makeArray(1); // -> number[]
const example2 = makeArray(['a', 'b', 'c']); // -> string[]
const example3 = makeArray(new SomeClass()); // -> SomeClass[]

UserComponentModel's generic types work fundamentally the same. They ensure consistency between the types of attributes, parents, children, and the serialized version of a model.

Why do they look weird/extra complex for UserComponentModel?

You'll notice the type definition uses a big object of options rather than simple type parameters:

ts
type TableModelGenerics = WithDefaults<{
	Attributes: TableAttributes;
	Serialized: SerializedTableModel;
	ValidChildren: [typeof DimensionModel, typeof MeasureModel, typeof PivotModel];
}>;

Why?

  1. Clarity - Instead of positional generics (<A, S, P, C>), we structure them in an object where each type has an explicit name from its key. This is more readable when there are a lot of generic types.
  2. Flexibility - You don't always need to set all options. Using the WithDefaults helper, you can override just the parts you need, and leave the rest at defaults.

State in models

For reactivity, use $state and $derived (or $derived.by) for models' member variables.

Use $state for data that is changed during reactivity (e.g. page, search, order in TableModel)

Use $derived (or $derived.by) for state that is computed (derived) from other state like $state declarations, the model's attributes, etc (e.g. queryConfig in TableModel)

Note: Use $derived or derived.by for computed state, NOT getters (get myField() { }). Getters will be re-executed whenever they are read resulting in performance issues.


Overview (`core/src/user-components/common/README.md`)

Common Utilities

This directory contains shared utility functions used across user components.

Date System Architecture

The Problem We Solved

When building a data visualization platform, dates are everywhere but behave differently depending on context. Users want to:

  • Filter data by date ranges ("Show me last 30 days")
  • Compare time periods ("How does this month compare to last month?")
  • Group data by time periods ("Monthly sales trends")

The challenge: date logic was scattered across components with inconsistent behavior. Some components parsed "Last 30 days" differently, comparison tooltips showed placeholder dates, and we had duplicate parsing logic everywhere.

Our Solution: Three Clear Use Cases

We identified that all date operations fall into three distinct patterns, each requiring different technical approaches:

1. Explicit Date Filtering ("Show me sales from last month")

The Use Case: User wants to see data from a specific time period. They select "Last 30 days" from a dropdown, and we filter the entire dataset.

Why This Exists: Most basic date filtering - users want to slice data by time ranges. Common in dashboards where you want to focus on recent data.

How It Works: We convert "Last 30 days" into SQL like WHERE date >= '2024-01-01' AND date <= '2024-01-31'

For Comparisons: We shift the date boundaries - if current period is "last month", comparison period becomes "two months ago"

The Use Case: User wants to see data grouped by time periods (daily, monthly, yearly) and compare each period to its predecessor. A table showing "Monthly Revenue" where each row is a month, and they want to see how each month compares to the previous month.

Why This Exists: Time-series analysis is core to business intelligence. Users don't just want to see monthly totals - they want to see "Is this month better than last month?" for every month.

How It Works: Instead of filtering dates, we group by time periods using date_grain="month". For comparisons, we shift the date expressions themselves: toStartOfMonth(date - INTERVAL 1 MONTH).

The Tricky Part: Each row represents a different time period, so the comparison logic needs to be applied per-row, not per-query.

3. Dashboard-Wide Date Controls ("Apply this date range to everything")

The Use Case: User sets a date range at the dashboard level and wants it applied to all components. Common in executive dashboards where you want to see "Q3 performance" across all metrics.

Why This Exists: Consistency - users want to change one date filter and have it affect multiple charts/tables simultaneously.

How It Works: Similar to explicit filtering but propagated across multiple components. The date range logic is reused but applied at a higher level.

Key Technical Decisions

MIN/MAX Aggregates for GROUPING SETS

Problem: Comparison tooltips showed "Jan 1/70" (ClickHouse null date placeholders) for total rows.

Solution: Wrap date expressions in MIN/MAX aggregates:

sql
-- Before
formatDateTime(toStartOfMonth(date), '%b %e/%y')

-- After
formatDateTime(MIN(toStartOfMonth(date)), '%b %e/%y')

Why: GROUPING SETS automatically calculates correct date ranges for both individual rows and totals without manual conditional logic.

Centralized Date Parsing

Problem: Duplicate parsing logic across multiple files.

Solution: Single parseDateRange() function in date-options.ts handles all patterns:

  • "Last X days/months/years"
  • "MTD/WTD/YTD"
  • Case insensitive matching
  • Singular/plural forms

Structured Return Values

Problem: Functions returned SQL strings that were then parsed with regex.

Solution: Return structured objects:

typescript
{ whereClause: string; startDate: string } | undefined

Functions Overview

`processDateRange(date_range)`

  • Converts date range objects to SQL WHERE clauses
  • Returns both SQL and parsed start date
  • Handles all supported date range patterns
  • Uses date column from the DateRangeObject

`calculateComparisonDateRange(dateRange, offset)`

  • Calculates comparison date ranges
  • Handles both range-based and dimension-based shifting
  • Uses centralized parsing logic

`parseDateRange(dateRange)`

  • Central parsing for all date range strings
  • Returns structured ParsedDateRange object
  • Includes ClickHouse-specific fields

Common Patterns

Date Range Patterns

  • "Last 30 days" → 30 days ago to today
  • "Last month" → Previous calendar month
  • "MTD" → Month to date
  • "YTD" → Year to date

Comparison Calculations

  • Range-based: Shift boundaries by offset periods
  • Dimension-based: Shift expressions by adding/subtracting intervals

When to Use What

Use Normal Range when:

  • Adding explicit date filters to components (date_range="Last 30 days")
  • User selects a date range from a dropdown
  • You want to filter the entire dataset

Use Dynamic Range when:

  • Component has date_grain and you want period-over-period comparisons
  • Data is already grouped by time periods
  • Each row represents a different time period

Use Table Range when:

  • Applying dashboard-wide date filters
  • Multiple components need the same date range

Common Gotchas

  1. "Jan 1/70" in tooltips → Use MIN/MAX aggregates around date expressions
  2. Comparison dates off by one → Check if you need the +1 day adjustment in processDateRange
  3. Case sensitivity → All parsing is case-insensitive, but double-check your strings
  4. MTD/YTD not working → Ensure you're using the startDateFunction from parseDateRange

Migration Notes

  • Eliminated generateDateSql wrapper function
  • Consolidated calculatedateDimensionComparisonDateRange into main function
  • Removed string parsing in favor of structured returns
  • No backwards compatibility maintained (as requested)

Other Utilities

  • comparisons.ts - Comparison query generation
  • sql-options.ts - SQL expression utilities
  • format-options.ts - Value formatting helpers

Index (`docs/index.mdx`)


title: What is Evidence?
keywords:

  • business intelligence
  • BI tool
  • business intelligence and analytics (ABI)
  • data products
  • dashboards
  • reporting platform
  • analytics platform
  • data visualization
  • business intelligence tools
  • SQL reports

Evidence is a business intelligence and analytics (ABI) platform for building data products with SQL, markdown, and AI. Use it as a BI tool to write SQL reports, build dashboards, and publish an analytics platform your team can explore. It's a reporting platform for data visualization — one of the business intelligence tools your whole organization can use. Evidence comes in two parts: an open-source framework you can run yourself, and a hosted platform built on top of it.

Evidence Core

Evidence Core is an MIT-licensed framework for building data apps from SQL and Markdown. You write reports in Markdown with embedded SQL and components, query your own warehouse through direct connectors, and preview locally with the CLI. It builds to a static site you can self-host anywhere — Vercel, Netlify, Docker, or your own infrastructure. No account required.

Evidence Studio

Evidence Studio is the hosted platform built on Evidence Core. Alongside everything in Core, it adds:

Studio-only pages in these docs are marked with a badge.

Getting Started

Create your first report in minutes.

Create an Evidence Studio account and start building in your browser. Build locally with Evidence Core.

Learn More

Build reports to share with your team.

Add charts, tables and interactive components to your reports Write SQL queries to power your reports Publish your reports online to share with your team Build interactive reports with the help of the Evidence AI Agent

Quickstart (`docs/quickstart.mdx`)


title: 'Quickstart'
keywords:

  • getting started
  • build a dashboard
  • business intelligence example
  • business report example
  • data analytics tutorial

Get started on our managed platform Get started with open source

Create an Account

This quickstart is the getting started guide for Evidence — a hands-on data analytics tutorial that walks you through building a business report example from scratch, taking you from an empty report to a published page in under 5 minutes. By the end, you'll build a dashboard and have a working business intelligence example you can share with your team.

Register at [Evidence Studio](https://login.evidence.studio/sign-up) and create a new account. You can SSO with Google, Github or Microsoft, or sign up with an email and password. You'll start on an empty report. Type markdown in the editor on the left hand side, and you'll get a preview of the report on the right hand side. When you are happy with your changes, click the "Share" button in the top right corner, and then choose the "Publish" button. After a few seconds, you'll see a link to your report.

Cli Index (`docs/cli/index.mdx`)


title: 'CLI'

The Evidence CLI lets you run and develop Evidence projects locally from the command line.

It includes a development server for previewing your reports locally as you work, commands for running queries, viewing metadata, and validating your code.

If you are going to use the CLI for development, you should set up the GitHub Integration.

Install

```bash curl -fsSL https://evidence.studio/install.sh | sh ```
text
Installs to `/usr/local/bin` (falls back to `~/.local/bin` if not writable).
```powershell irm https://evidence.studio/install.ps1 | iex ```
text
Installs to `%LOCALAPPDATA%\Evidence\bin` and adds it to your user PATH. Restart your terminal after install.

Both evidence and evd commands are available after install.

Supported Platforms

  • macOS arm64 (Apple Silicon)
  • macOS x64 (Intel)
  • Linux x64
  • Linux arm64
  • Windows x64

Verify Installation

bash
evidence version

Getting Started

  1. Create a project in Evidence Studio and connect it to a GitHub repo.
  2. Clone the repo to your local machine.
  3. Log in to your Evidence account via the CLI:
    bash
    evidence login
  4. Start developing from inside your cloned project directory:
    bash
    evidence dev
  5. Open a pull request on the repo. Evidence Studio will reply with a preview link. Merging the PR releases your changes.

Upgrade

bash
evidence upgrade

The CLI checks for updates on startup. If a newer version is available, you'll see a warning. If your version is below the minimum supported version, the CLI will require an upgrade before running.

Telemetry

The CLI reports anonymous usage so we can tell how many people use Evidence, which commands matter, and which versions are still in the wild. Nothing about your data, queries, file paths, or repository is ever sent.

Opting out

Any one of these turns telemetry off:

bash
evidence telemetry disable      # persists in ~/.evd/telemetry.json
export EVIDENCE_TELEMETRY_DISABLED=1
export DO_NOT_TRACK=1           # the cross-tool convention

evidence telemetry status shows the current state and why. Telemetry is also skipped automatically on CI (CI, GITHUB_ACTIONS, GITLAB_CI, CIRCLECI, BUILDKITE, TF_BUILD, JENKINS_URL).

What is sent

One cli_command event per invocation, one cli_installed event from the install script, and — for evidence serve only — a serve_heartbeat once every 24 hours so long-running deployments stay counted, plus a serve_preflight_failed event (with a reason such as no_connection_yaml) when serve refuses to start, so we can spot broken self-host deployments.

Field Example Purpose
machineId random UUID Stored in ~/.evd/machine-id on first run (or in your temp dir if home isn't writable); counts developer machines without knowing who you are
id_source home / tmp Where the machine id was stored
command dev Which command ran
version 0.9.3 CLI version
os, arch darwin, arm64 Platform mix
connector direct / managed Whether the project has a connection.yaml or uses the managed warehouse
logged_in false Whether a Studio login exists on this machine
project_id random UUID telemetry.id from evidence.config.yaml; counts deployments of a project rather than restarts of a container
agent cursor Set when a coding agent (Cursor, Claude Code, Codex, Gemini) is driving the CLI
tty true Whether a person is at an interactive terminal
runtime docker / bare Whether the CLI is running in a container
first_run true Whether this is the first run on this machine
sandbox false First run inside an agent or container; these never count as users
instance_id random UUID Per-process id, used only to count restarts of a deployment

Requests carry your IP like any HTTP request; it is used for country-level geolocation only.

Project id

evidence init writes a random telemetry.id into evidence.config.yaml. It identifies the project, not you or your machine, and is what lets us count a self-hosted deployment once rather than once per container restart. Delete the key to opt a project out of that count.

When you are logged in

Commands that talk to Evidence Studio (launch, link, publish, models, and others) are authenticated API calls, and Studio records that your account and organization used the CLI, the same way it records use of the web app. Anonymous local usage is never linked to an account.


Mcp Overview (`docs/mcp/overview.mdx`)


title: 'Overview'

What is MCP?

The Model Context Protocol is an open standard that enables AI applications to connect to external data sources and tools. Evidence provides two MCP servers.

Connect an AI client to your live Evidence workspace — search reports and query your data. Requires authentication. A developer tool that searches the Evidence documentation. No authentication required.

Which one do I want?

  • Querying your own data and reports? Use the Studio MCP — it connects to your live workspace with your permissions.
  • Developing reports? Use the Docs MCP — it searches the docs and component reference.

Self Host Index (`docs/self-host/index.mdx`)


title: 'Self Host'

Evidence projects can be self-hosted with the official Docker image.

The image runs evidence serve, which is similar to evidence dev but hardened as a production server.

Self-hosted projects must use a direct connector (configured in connection.yaml).

Docker containers can run on many platforms, major cloud providers or your own machine. See the below guides for some tested options:

Should you self host?

Self hosting is appropriate if:

  1. Your organization requires data does not leave your infrastructure
  2. You have a hobby project and do not want to pay for a managed service

However, you should be aware that there are tradeoffs associated with self hosting Evidence projects:

  • Several platform features (e.g. User Auth, Access Controls, Evidence Agents) are not built in
  • There are no platform fees, but you will incur costs from infrastructure and maintenance
  • You need to handle security, monitoring, and scaling on your own

Generic Docker Deployment

Details may differ, but these steps are required for all Docker deployments.

  1. Add a Dockerfile:

    docker filename="dockerfile"
    FROM evidencedev/serve:latest
    COPY --chown=evidence:evidence . /project
  2. Move secrets out of connection.yaml, replacing them with ${VAR} environment references

  3. Commit connection.yaml (it is gitignored by default)

  4. Add environment variables

    Env Var Purpose Required?
    EVIDENCE_BASIC_USER HTTP Basic Auth username Yes*
    EVIDENCE_BASIC_PASSWORD HTTP Basic Auth password Yes*
    ${VAR} references All variables referenced in connection.yaml Yes
    EVIDENCE_AUTH_DISABLED Skip auth entirely on trusted private networks -
    PORT Port the server listens on (default: 3000) -
    EVIDENCE_TELEMETRY_DISABLED Turn off the anonymous startup event and daily heartbeat (details) -

    * Unless auth disabled

  5. Start the server

Self Host vs. Evidence Studio

Self-hosting allows you to render your SQL + markdown into interactive reports — but the Evidence Studio platform has many additional features:

Feature Self Host Evidence Studio
Rendering reports ✓ ✓
Direct connectors ✓ ✓
Evidence Warehouse — ✓
SQL models — ✓
Auth HTTP Basic Auth SSO with viewer, developer & admin roles
Access controls — ✓
Row-level security — ✓
Developer Agent — ✓
Viewer Agent — ✓
Web editor & real-time collaboration — ✓
Embedded analytics — ✓
Studio MCP server — ✓

Authentication

Self-hosted sites are protected by HTTP Basic Auth. The browser caches credentials in memory until the browser is exited (there is no logout button).

To force all viewers to re-authenticate, change EVIDENCE_BASIC_PASSWORD and redeploy.

For deployments only reachable over a trusted private network (VPN, Tailscale, internal VPC), set EVIDENCE_AUTH_DISABLED=true to skip authentication entirely.

To authenticate users against your organization's identity provider, deploy evidence serve behind an authenticating reverse proxy — see Authentication & SSO.


Changelog (`docs/changelog.mdx`)


title: 'Changelog' rss: true

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

✨ AI chat in embedded reports

Embedded reports can now show the Evidence AI chat, so your users can ask questions about a report without leaving your application. Embedding customers opt in per session with the enableAIChat parameter on the embed API.

🐛 Organization switching for viewers

Fixed an issue that blocked viewers from switching organizations in the published app.

🚀 Big values fit two to a line on phones

On phones, big values now sit two to a line instead of stacking one per line.

🚀 Render html blocks without a card

On pages with card mode enabled, {% html card=false %} renders the block directly on the page background instead of inside a card.

✨ Preview pages at mobile width in the editor

A new toggle on the editor's preview pane narrows the preview to phone width, so you can check how a page reads on mobile without resizing your browser.

  • Mobile-specific behavior shows in the preview too: details honors open_mobile, and modals open as they would on a phone, inside the preview.
  • dimension_grid now wraps based on its own width rather than the browser's, so it lays out correctly in narrow columns as well as on phones.

🐛 Stacked areas no longer have holes

Fixed gaps in stacked area charts on date axes when a series has no data for some dates.

✨ Hide or show content in print without grouping it

New {% hidden_in_print %} and {% only_in_print %} blocks control what appears in printed pages and PDFs, without the blank gaps print_group can leave.

Reopening an invitation you've already accepted while signed in now takes you into that organization instead of showing an error.

🐛 Improved PDF exports

Fixed charts that could be missing from PDF exports.

✨ Commentary per input selection

Commentary can now be kept separately for each selected value of one or more inputs, alongside the reporting period.

View Documentation

✨ Page download options

Hide download options from a published page's menu with the downloads page setting.

✨ Period selector component

Added a period selector input, which can also place a page's reporting period anywhere on the page.

View Documentation

Show content only in printed pages and PDFs with {% print_group print_only=true %}.

🚀 Improved row layout

Rows can now spread their contents across the full width, for example a heading on the left and a button on the right.

View Documentation

✨ Generate Excel Report

A new Generate Excel Report option exports the page as an Excel workbook with a snapshot of the report on the first sheet and a data sheet per component; Download Data now also appears in the CLI.

  • Download Data is unchanged and still exports data only; pick Generate Excel Report when you want the report snapshot included.
  • Hide it with downloads: { excel: false } in page frontmatter. It is also hidden when image or data downloads are turned off.
  • The local CLI viewer now has Download Data and Generate Excel Report in its page menu.

🚀 Improved info tooltips

Info tooltips now support text across multiple lines.

🐛 Improved date axis labels

Improved the layout of date labels on chart axes.

✨ Attach files to reports

Drop or paste a file into the editor to upload it and insert a file card showing its icon, name, type, and date.

🚀 Set down_is_good for a whole page

Add down_is_good: true to a page's frontmatter to treat decreases as good for every delta on that page.

  • Applies to big_value, delta, and table delta columns. A component's own down_is_good still overrides it.
  • down_is_good=true on a benchmark_comparison or target_comparison option is now respected when a component uses that comparison_selector.

🐛 Tables inside repeat blocks now read page inputs

A table inside a {% repeat %} block now resolves page inputs referenced in its where, having, order, and qualify attributes instead of running with the value missing.

  • Previously the table only looked at the repeat's own scope, so {{my_input}} in these attributes interpolated as empty and the query failed with a syntax error.
  • Titles and other text attributes on the same table also resolve page inputs correctly now.

🐛 CLI runs direct-connector projects without reaching Evidence Studio

evidence dev no longer refuses to start when evidence.studio is unreachable for projects with a connection.yaml, evidence upgrade now works on Windows, and the home page honours page_width and cards like every other page.

  • Projects with a connection.yaml skip the Studio reachability check entirely; projects on the Evidence Warehouse get a warning (with the failure reason and a proxy hint) instead of a hard exit.
  • evidence dev prints which mode it is in — direct connector or managed warehouse — so it is clear whether a login is needed.
  • evidence upgrade supports Windows x64 and Linux arm64, keeps evd.exe in sync on Windows, and points to the installer when the update check fails.
  • evidence serve is listed in evidence help.
  • pages/home.md now respects page_width, cards, table_of_contents and frontmatter theme, matching subpages.

🐛 Viewer log out fix

Fixed logging out from a published report showing a "Page not found" error and leaving you signed in.

🚀 Details start state on mobile

The details component has a new open_mobile attribute to choose whether it starts open or collapsed on mobile screens, independently of open

View Documentation

✨ Validation summary in the editor

A new indicator in the editor toolbar shows how many validation errors are on the open file. Click it to see every error with its line number, and click an error to jump to it in the editor.

  • Covers component errors, inline SQL query errors, and config file (yaml) validation.
  • Each entry is labeled with the component, query, or config key it belongs to.
  • Clicking an error scrolls the editor to the line and highlights it.

🐛 CLI keeps input selections in the URL

Input components in evidence dev and self-hosted CLI pages now write their selections to the URL and restore them from it, so filtered views can be refreshed, bookmarked and shared like in Studio.

🐛 Commentary save fix

Fixed an issue where some commentary saves did not persist.

View Documentation

🐛 Filter defaults no longer appear in URL

A table_filter with initial_values no longer writes its default into the page URL, so other pages keep showing their own data instead of inheriting that default and filtering against the wrong values.

✨ Commentary supports workflow periods

Commentary components can now keep separate notes for each reporting period with scope="period".

  • Period-scoped commentary follows the page's workflow.period picker, including in PDF renders.
  • Commentary without scope remains page-wide.

View Documentation

✨ Waterfall chart

The waterfall_chart component is now available - useful for growth decomposition, revenue bridges, and reconciliations

View Documentation

✨ Search team members

Filter your team settings page by name or email with a new search field.

🐛 Slack channel picker finds every channel the bot is in

Fix the scheduled report Slack channel dropdown missing channels the Evidence bot had joined in large workspaces with many channels.

🚀 Improved content selection in PDF download menu

Simpler click behaviour to select and deselect content in nested sections.

🐛 Table cells only merge within their parent group

Fix table dimension cells merging across rows whose parent dimension values differ, such as after sorting by a measure.

🚀 Resume GitHub Enterprise connections

GitHub Enterprise Cloud connections can now resume after another organization owner installs the app, with clearer errors and controls for unfinished attempts.

  • Finish connecting from GitHub integration settings when the installation callback is missed.
  • Allow up to seven days for installation after app registration.
  • Resume or cancel an unfinished connection instead of creating another app on each retry.
  • See an error message and request ID when a connection needs support.

✨ Reporting periods

Turn a page into a periodic report with a workflow.period block in frontmatter.

  • Adds a period picker at the top right of the page, listing complete calendar periods (day, week, month, quarter or year)
  • The selected period is available as the period variable — {{ period.label }} in markdown, {{ period.between }} in SQL
  • Only finished periods are offered, so a published report doesn't change while its period is still running
  • The selection is kept in the URL, so a link points at a specific period

View Documentation

Fix data-driven dropdowns returning no options when connected to a Cube warehouse.

✨ Scheduled report using email or Slack

Scheduled report using email or Slack

View Documentation

✨ More control over color scales

Color scales in tables and map layers now support diverging midpoints and custom value-to-color breakpoints, and behave consistently across both.

  • Set midpoint to anchor a diverging scale at a value such as 0, and min/max to fix the scale bounds.
  • Use color_stops to pin specific colors to specific values.
  • Diverging scales stay correct even when every value falls on one side of the midpoint.

🚀 Improved error display

Components now display syntax and query errors more prominently in the editor.

🐛 Reliable map layer filter updates

Area, point, and heatmap layers now reliably update when filters change their data.

🐛 Table filter values on Snowflake

Fix the table filter returning no selectable values on Snowflake and other uppercase-folding warehouses.

✨ Folder-Level Access Rules

Add folder-level access rules to access.yaml — grant or restrict every page in a directory subtree with a single entry.

✨ Scheduled Reports

Email reports to your users on a regular schedule, or send one-off reports on demand.

View Documentation

✨ Access Viewer AI inside Slack

Connect a Slack workspace in Integration settings and message the Evidence bot to get answers from your data without leaving Slack.

  • An admin adds the app from Settings → Integrations → Slack, then each person connects their own account — the bot only reads what you can already see.
  • Direct message the bot, or @mention it in a channel.
  • Answers can display charts, save insights to your library, and link back into Evidence.
  • Admins can turn the bot off for the whole organization, and choose whether each person's first answer in a channel is shown to them before the channel sees it.

🐛 Partial filter initial values now apply on parent pages

Fixed an issue where filter initial values defined in partials could be empty when rendered on parent pages.

🐛 Filters load in partial page previews

Filters in partials now load when using View another page in the editor.

Link buttons now navigate correctly with portable relative URLs across edit, preview, and published reports.

🐛 Table filters close safely without selections

Table filters now remain visible when a numeric or date picker is closed without a selection.

🐛 Sorting a table by a column it does not show

Sorting a table by a column that is not one of its dimensions or measures no longer splits the rows into extra groups, and no longer fails on Postgres, Fabric and Cube.

🐛 ClickHouse conditional aggregates

Fix sumIf and its -If siblings breaking date-filtered measures and comparison targets on ClickHouse, and no longer warn that they are missing an aggregation.

🐛 Snowflake table conditional colors

Fix conditional colors on table dimensions in Snowflake for literal colors and SQL expressions.

🐛 Sorting a table by a grouped date column

Sorting a table by a date column that has a date_grain now sorts by the grouped date instead of failing with a grouping error.

  • order="my_date desc" alongside {% dimension value="my_date" date_grain="day" /%} sorted by the raw column, which the warehouse never grouped. ClickHouse rejected the query and the table rendered empty.
  • A hidden sort column on a table with subtotals is now aggregated, so it no longer breaks the subtotal and total rows.

🐛 Creating files and folders is disabled on protected branches

The sidebar's create page, partial, SQL, component, folder, and agent-file actions are now disabled when the current branch is protected on GitHub, matching the existing branch-protection guard on Commit.

✨ Bring your own model API key

Enterprise organizations can now point both AI agents at their own OpenAI, Anthropic, AWS Bedrock, or Google Vertex account from Settings → AI Agent.

  • Both the editor agent and the viewer agent use your provider and model, so your provider bills you for inference directly and Evidence AI credits are neither consumed nor charged.
  • Credentials are stored in the WorkOS Vault and never sent back to the browser. Saving verifies the credential against your provider first, so a wrong key or model ID is rejected rather than stored.
  • There is no fallback to Evidence's models: if your credential stops working, chat reports a clear error instead of quietly switching back and billing you for credits.

🚀 Big value titles are clickable when linked

Setting link on a big value now turns the title into a styled link instead of the number, matching typical score card conventions.

✨ Metrics

Evidence now has a metrics layer. Define metrics in metrics/*.yaml and reference them in charts and tables. Ask the agent to build one for you to get started.

✨ MCP Visualize Tool

The Evidence Studio Claude Connector and ChatGPT Plugin can now generate charts inline in the chat with the new visualize tool.

✨ Reports page for run history and schedules

A new top-level Reports page (next to Models) for viewing report run history and managing schedules.

  • History tab: View all report runs with status, trigger type (manual/schedule/API), author, timing, and recipient count
  • Schedules tab: View and manage recurring report schedules with pause/resume and delete actions
  • Admin-only actions: Pause/resume schedules, delete schedules, re-run past reports, download PDFs
  • Developer access: Developers (members) can view the page; admins can take all actions
  • Entitlement gate: Available on Team, Pro, and Enterprise plans

View Documentation

✨ GitHub Enterprise Cloud support

Enterprise organizations can now connect Evidence Studio and the Evidence CLI to GitHub Enterprise Cloud accounts hosted on dedicated *.ghe.com domains.

  • Create and install a private, organization-owned GitHub App through Organization Settings.
  • Select accessible enterprise repositories in Project Settings and use Studio branches, pull requests, checks, and publishing as usual.
  • Run evidence launch or evidence link from HTTPS and SSH GHE.com remotes.

🐛 Feature request dialogs remain accessible with long descriptions

Feature request dialogs now constrain long descriptions to a scrollable area so their controls remain accessible.

Table links now navigate to their destination while viewing a report in fullscreen presentation mode.

✨ MotherDuck direct connector

Connect Evidence directly to a MotherDuck database to build reports on live data without syncing it first.

View Documentation

✨ Custom Maps

Use the custom_map component to build fully customized maps with Mapbox GL or MapLibre GL.

  • Write map code directly in the component body — pull page data with evidence.query, read and write page filters, and react to variables and theme changes.
  • No key needed by default: keyless MapLibre out of the box, or Mapbox using Evidence's shared token under the hood.
  • Import map-ecosystem plugins (mapbox-gl-draw, deck.gl, turf, and more) straight from a CDN.

🐛 Custom HTML and ECharts blocks work in the CLI

{% html %} and {% custom_echart %} blocks now render when running a project locally with the Evidence CLI.

  • Both blocks previously rendered blank in evidence dev — the sandbox runtime they load was only built by the hosted app, so the CLI served nothing for it
  • Requires CLI v0.7.4 or later
  • If a sandbox runtime is ever missing, the block now reports an explicit error instead of staying blank

🚀 AI chat now consumes far fewer credits

We've significantly reduced how many credits AI chat consumes, so your balance goes much further.

✨ Cube Connector

Connect Evidence directly to your Cube semantic layer through its Postgres-wire SQL API.

  • Query your cubes and views live from Evidence — metrics stay defined in Cube.
  • Configure it in Connectors → Warehouse → Cube (host, port, user, password, SSL), or via connection.yaml (type: cube) in the CLI.
  • The SQL editor validates expressions against Cube's documented function subset, so unsupported functions are flagged before you run a query.

✨ PDF "Use page colors" option

Preserve the exact colors from your page when generating PDFs.

  • New "Use page colors" checkbox in the PDF settings modal (Cmd+P)
  • When enabled, PDFs retain the theme's actual background colors (including dark mode or custom theme backgrounds)
  • When disabled (default), PDFs use white backgrounds optimized for printing
  • Preview updates to show how the PDF will look with the selected option

✨ Postgres Direct Connector

Connect Evidence directly to Postgres — including Amazon RDS/Aurora, Supabase, Neon, and Timescale — and query it live.

  • Add Postgres under Settings → Warehouse: enter host, port, database, user, password, and SSL mode, test the connection, and save.
  • Works with any Postgres-wire source: generic Postgres, Amazon RDS / Aurora, Supabase, Neon, and Timescale.
  • Full SSL/TLS support with disable / require / verify-ca / verify-full modes, plus an optional CA bundle and mutual-TLS client certificate.
  • The schema browser lists tables, views, and materialized views.
  • Also available from the CLI via connection.yaml (type: postgres) or evidence init --warehouse postgres, with certificates referenced by file path.

✨ Search across your reports with Cmd+K

Press Cmd/Ctrl+K to instantly search across every report you have access to.

✨ Viewer AI & Insights

Report viewers can now ask questions of your data in a chat assistant and save the answers as insights to revisit later.

🐛 Fixed editor inserting characters at the wrong position on older reports

Typing in the editor now appears where you clicked on reports created before mid-2026.

✨ Evidence Studio MCP Server

Search your reports and query your data from your favorite AI client. Connect Claude, ChatGPT, and other MCP clients to your live Evidence workspace — every request runs as the signed-in user, so access policies and page controls are respected.

View Documentation

🐛 CLI dev server no longer crashes when a subfolder has an index.md

Nested index.md / home.md / README.md files are no longer treated as the home page in the sidebar, so evidence dev renders normally instead of crashing with a duplicate-key error when a project has a root home page plus an index.md in a subfolder.

✨ Point Map Clustering

You can now include up to 100,000 points in a point layer by using cluster=true. Nearby points are grouped into aggregated bubbles that split apart as you zoom in, so large datasets stay fast and readable.

✨ 50 New Data Connectors

Connect 50 more data sources to Evidence, including Zendesk, Intercom, Mixpanel, Amplitude, Square, QuickBooks, Recurly, Pipedrive, Gong, LinkedIn Ads, and more. Set them up in a few clicks from the Connectors page.

✨ 50 More Data Connectors

Another 50 data sources are now available, including Jira, Airtable, Asana, Notion, Slack, Klaviyo, Mailchimp, Braze, SendGrid, TikTok Ads, Amazon Ads, Google Search Console, ServiceNow, and Okta. Set them up in a few clicks from the Connectors page.

✨ Lemlist Connector

Connect your Lemlist data to Evidence. Sync campaigns, leads, and activities from your email outreach.

View Documentation

🚀 Improved chart x-axis and tooltip labels

Better handling of dates and numbers on chart x-axes and tooltips.

✨ Table Access Restrictions

Restrict tables to a chosen set of users

Restrict specific tables to a chosen set of users from the Access Rules settings page. Unrestricted tables stay open to everyone in the organization, and restricted tables show a lock badge in the editor's schema list.

View Documentation

✨ Image component accepts data queries

Add data and column props to the image component to load the image URL from a query and respond to filter changes — e.g. show the top-selling product's photo, a client logo driven by a dropdown, or a dark-mode variant via dark_column.

✨ Radar, Treemap, and Chord charts

Three new charts now available: radar_chart, treemap, and chord_chart

✨ Mix single and multi select columns in table filters

Add single_select and multi_select to table_filter to set the selection mode per column — e.g. restrict a client column to one value at a time while keeping region and product filters multi-select.

🐛 Y-axis titles stay legible above chart data

Chart contents no longer overlap the y-axis title — bars, areas, and lines that reach the top of the axis now render beneath the title instead of covering it. Gridlines are cut off cleanly behind the title rather than showing through the text, the title is vertically aligned with the top axis tick label, and a subtle text outline keeps it readable when data passes directly beneath it. Applies to both left and right (y2) axis titles.

🐛 range_calendar "all time" no longer breaks raw SQL

Referencing {{ date_filter.between }} in a where or SQL template while "all time" was selected previously produced an empty string, which broke the query (where date → syntax error). .between now emits IS NOT NULL for "all time", so where="date {{ date_filter.between }}" matches all rows and just works.

The new all_time_range attribute controls what "all time" means for a specific range_calendar:

  • all_time_range="none" restores the previous empty-string behavior — pair it with [[ ]] conditional blocks or a | fallback when the whole clause should drop (e.g. to keep NULL-date rows, which IS NOT NULL otherwise excludes).
  • Set it to a bounded range — a preset key ("last 12 months"), a custom_ranges label, or a range expression ("from 2022-12-01") — and "all time" resolves to that range everywhere (.between, .start, .end, and the date_range value). If you were faking this with a | fallback in your where clause, set all_time_range to that range and delete the fallback.

.start / .end stay empty for unbounded "all time" (so date spines and axes fail loudly rather than silently wrong), and .filter / a filters=[...] reference stay a true no-op that keeps NULL rows.

🐛 Fix for AI chat losing conversation context

Fixed an issue where the AI chat could respond to an earlier message in long conversations instead of the one you just sent.

🐛 Sparkline hover values now use theme foreground

Sparkline hover values and the vertical tracking line follow the theme's foreground and muted-foreground tokens, restoring contrast in light mode (most visible on big_value sparklines).

✨ AI Agent Multi-File Edits

The AI dev assistant can now edit multiple files in a single turn — as well as create, rename, and move files.

✨ Extra tooltip rows on chart series

Add tooltip_fields to any bar_chart / line_chart / area_chart / scatter_chart / bubble_chart — or to bar, line, area, scatter, bubble inside a combo_chart — to surface additional aggregated values on hover, with optional labels, format codes, and color_by_sign / down_is_good for delta-style coloring.

Add connect_group to charts to sync their tooltips, axis-pointer, and zoom across any charts sharing the same id — e.g. stack a price chart above a volume chart, align KPIs that share a time axis, or coordinate small multiples.

✨ Customize built-in charts with ECharts options

Override any ECharts option on built-in charts via echarts_options (chart-wide) or echarts_series_options (looped across every series).

✨ Attach images to editor AI chat

Click the image button in the editor chat composer to attach screenshots or other images for the AI agent to see alongside your message.

✨ Custom components

Build your own Markdoc tags from components/*.md files — each component declares its attributes in frontmatter and gets autocomplete, slash-command, and AI-tool support just like a built-in.

✨ Pin color scale values in tables

Anchor a measure's color scale to specific data values with color_stops.

✨ Custom HTML in reports

Embed your own HTML and JavaScript anywhere in a report with the new {% html %} block. Build custom visualizations that integrate with Evidence's filters, queries, and theme — using any library, like D3 or deck.gl.

🐛 Hide unneeded subtotal rows in tables

Tables now hide duplicative subtotal rows that only summarize a single item, while keeping the grand total.

✨ Expanded theme options

Themes now include fonts, colors, corner roundness, spacing density, and chart defaults, applied consistently across the whole report. Override the theme for a single page when you need to.

✨ Custom date ranges

Add custom_ranges to {% range_calendar %} to generate named presets — e.g. fiscal years, seasons, and retail calendars.

🐛 Smoother schema panel refresh

The refresh button no longer pushes content down or hides the schema list while reloading, and long table or column names truncate instead of forcing horizontal scroll.

✨ Show size dimension in bubble and scatter chart tooltips

Bubble and scatter chart tooltips now display the size dimension value, with a new size_fmt attribute for formatting.

🐛 Faster, more reliable editor preview on heavy pages

Fixed an issue where the editor could lock up on pages with many charts and tables.

🐛 Fix heatmap collapsing at wider screen widths

Fixed heatmap charts collapsing into a small box at certain screen widths.

✨ Impersonate

Create and manage access tokens for programmatic API access from the new Access Tokens settings page. Admins and developers can impersonate team members to see exactly what they see (disabled by default).

🐛 Fix dropdown search failing on BigQuery

Fixed an issue with searching a dropdown or table filter for BigQuery direct connections.

✨ Failed Publishes No Longer Affect Viewers

If a publish fails, your project keeps serving the last successful version — viewers never see broken content.

🐛 Fix spurious markdown validation errors on PRs

Fixed the PR markdown-validation check reporting false-positive undefined-translation-key and undefined-frontmatter-variable errors on pages using translations and on partials that receive variables from the pages including them.

✨ Publish History & Rollback

View your project's publish history and roll back to any previous version.

✨ ClickHouse direct connector

Connect Evidence directly to your own ClickHouse instance to build reports on live data without syncing it first.

View Documentation

✨ Make the selected option in `button_group` and `input_tabs` more noticeable

The selected button in button_group and the active tab in input_tabs now stand out more clearly.

✨ New share menu and additive page access

The redesigned share menu lets you grant page-level access on top of project access, so you can share a single dashboard with a stakeholder who shouldn't see anything else.

✨ Vibe code any visualization with the custom_echart component

Need a chart Evidence doesn't have out of the box — a waterfall, a bridge, a radar, something bespoke? The new custom_echart component lets you build any visualization you can imagine. Describe what you want to the assistant and it writes the chart for you, wired up to your data, filters, and theme automatically.

✨ Pre-select the top N options in a multi-select dropdown

Multi-select dropdowns now accept a default_top_n attribute that pre-selects the first N options on load. Combine it with order to control which N are selected by default — which viewers can then change.

✨ New Publish Menu in Editor

View pending changes and open pull requests directly from Studio.

✨ See what each user, group, and customer can access

Admins and developers can now see every project and page a user, group, or customer can access, plus how that access was granted.

🐛 Share menu now lets you grant page access to any team member

The Page tab of the share menu now lists every internal team member, so you can grant page access directly without first adding them to the parent project.

🚀 Add users to groups when inviting, and see group memberships in the team table

Admins can now pick groups when inviting or manually creating users, and the Team settings page shows each member's group memberships in its own column.

🚀 HubSpot Connector

Updated the HubSpot connector with more reliable syncs and broader table coverage.

View Documentation

✨ Microsoft Fabric direct connector

Connect Evidence directly to a Microsoft Fabric Warehouse or Lakehouse SQL endpoint to build reports on live data without syncing it first.

View Documentation

🐛 PDF exports preserve dropdown filter values

PDF exports of pages with a select_first=true dropdown no longer revert the filter to its auto-selected default when the URL specifies a different value.

✨ Map area layer min, max, and midpoint

Map area_layer and point_layer now accept min, max, and midpoint props so you can pin a diverging color scale at zero (or any other value).

🐛 Fixed bar chart tooltip not displaying point_title

Fixed an issue where the point_title attribute on bar, line, and area charts was ignored in the tooltip.

✨ File change indicators in editor sidebar

Files with uncommitted changes now show colored status badges (M/A/D) in the editor sidebar file tree, so you can see which files have been modified without switching to the Version Control tab.

Copy a shareable link to the current page from the page menu, with option to include the current filters.

✨ Download report as PNG

Save a full page as a PNG image from the page menu.

🚀 Dedicated Groups settings page

Groups now have their own page under Settings → Groups, separate from team members, with a detail view for managing each group's members and access.

✨ Snowflake and BigQuery direct connectors

Link Evidence to Snowflake or BigQuery directly to build reports without syncing data.

View Documentation

🚀 Improved discoverability of date input components in AI chat

Added search keywords to range_calendar, date_grain_selector, and comparison_selector so the AI assistant can find them when users ask for "date range filter", "date picker", "date input", etc.

🚀 Long chart label rotation

Charts now rotate long x-axis labels automatically so category names are easier to read without hovering.

🐛 Map area layer filter updates

Fixed a bug where area charts did not respond to filter changes.

🚀 Data download title filenames

Data downloads now use titles in file names.

🐛 Horizontal bar chart axis bound validation

The horizontal_bar_chart now reports a validation error when x_axis_options.min is greater than or equal to x_axis_options.max.

✨ Evidence CLI now available on Windows

The Evidence CLI now ships a Windows x64 binary, installable via PowerShell: irm https://gaamozau3jchzs3r.public.blob.vercel-storage.com/cli/install.ps1 | iex.

View Documentation

🚀 Default tab selection

Add default=true to a {% tab %} to pre-select it on page load instead of always defaulting to the first tab.

🐛 Data labels render on area and line charts

Fixed data_labels not appearing on area_chart, line_chart, and combo_chart line/area series.

✨ Add today and yesterday range calendar presets

Range calendars can now opt into Today and Yesterday preset ranges.

🚀 Faster Page Create and Rename

Creating, renaming, and reorganizing pages and folders in the editor sidebar is noticeably faster.

🐛 Mobile sidebars close after navigation

Fixed mobile sidebars staying open after selecting a navigation link.

🐛 Improved SQL file support in GitHub integration

Improved how SQL files sync between Studio and GitHub.

Editor link autocomplete and validation now include pages that exist only on the current branch, and AI chat no longer flags them as broken.

🐛 AI chat current date awareness

Fixed AI chat date context so the agent knows today's date when answering in editor and viewer chats.

🐛 Locally-authored pages now appear in Studio

Fixed an issue where files created locally and synced to GitHub were not appearing in Studio.

🐛 Stable heading logo sizing

Fixed an issue where logos inside headings could briefly render at the wrong size on page load.

🐛 Fix unquoted variables in partial attributes

Fixed an issue where unquoted variable references in component attributes failed when rendered from partials.

🐛 Fix x_sort="data" imposing an x-axis sort

Fixed an issue where setting x_sort="data" on bar and line charts still sorted by the x-axis instead of preserving the source query's row order.

🐛 Embedded page centering without TOC

Fixed an issue where embedded pages could stay shifted to the left after the table of contents was turned off.

🐛 Stable logo sizing on load

Fixed an issue where logos in headings could briefly render at the wrong size while the page was loading.

🐛 Improved models table readability

Fixed an issue where the models table was not sorted by name by default and long descriptions were hard to scan.

✨ Select content for PDF exports

Choose which sections and components to include when exporting a PDF.

🐛 Source failure modal fix

Fixed an issue where opening a failed source status could show a blank blocking modal instead of the failure details.

🚀 Longer AI chat sessions

Increased the maximum AI chat response time so longer agentic conversations no longer time out.

🚀 Collapsible projects in published and preview sidebars

Projects in the sidebar can now be collapsed and expanded by clicking the project name, with state persisted across sessions.

🚀 Table Actions

Download and Fullscreen buttons now available in Table footers.

🚀 Claude Opus 4.7

The Evidence agent now uses Claude Opus 4.7 by default.

✨ Connector renaming

You can now rename connectors directly from the connectors page or the connector detail page by clicking the pencil icon next to the name.

Fixed an issue where searching in a dropdown could fail when the value or label column contained empty values.

✨ Data lineage

See where your connectors and tables are used across projects, pages, models, and queries. Available in the connectors page, connector detail pages, models page, AI chat, and the CLI.

🚀 Resizable SQL console schema panel

The SQL console schema panel can now be resized by dragging its edge so long table names are easier to inspect.

✨ Connector and model health status

Connectors page now shows health status and sync schedule for all connector types. New connectors and models CLI commands let you check health statuses from the command line.

🐛 Fixed theme settings loading state while editing colors

Fixed an issue where editing theme color values could cause a broken loading state in settings.

🐛 Fixed inline SQL editor query references

Fixed an issue where inline SQL editor queries could fail when referencing other inline queries.

🐛 Fixed unexpectedly large branch diffs

Fixed an issue where small edits in Git-connected branches could appear as much larger diffs than expected.

🐛 Fixed stacked combo charts on time-based axes

Fixed an issue where stacked combo charts on time-based axes could render blank or incorrect series data.

🐛 Fixed filter bar not floating on scroll in published pages

Fixed an issue where the filter bar would not stay pinned to the top of the page when scrolling in published mode.

✨ Usage Analytics

Track how your team uses Evidence with built in analytics tables for sessions, users and page views.

🐛 AI theme updates apply instantly

Fixed an issue where theme changes made by the AI assistant only appeared after a page refresh.

✨ Audio Component

Embed an audio player in your reports with {% audio url="..." /%}. Supports mp3, wav, ogg, and other formats, with options for looping, autoplay, and preload behavior.

🐛 Calendar heatmap dark mode colors

Fixed an issue where calendar heatmaps could show white empty-day cells in dark mode instead of blending with the page or card background.

✨ Conditional colors for dimensions and rows

Apply conditional background colors to entire rows or individual dimension cells using SQL expressions.

🐛 Fixed table SQL error overlay spacing

Fixed an issue where table SQL errors could overlap content below the table.

🐛 Expanded background color options for AI theme updates

Expanded the background color options the AI agent can change in theme updates.

✨ YouTube Analytics Connector

Connect your YouTube Analytics data to Evidence. Sync channel reports, content owner reports, and metadata tables.

View Documentation

🐛 Fixed combo chart SQL with toggle-driven inline queries

Fixed an issue where combo charts could fail when inline queries used toggle values in SQL conditions.

✨ Multiplayer editor

Collaborate with your team in real-time with live cursors and presence indicators.

✨ Axis titles for heatmaps

Heatmaps now support x_axis_title and y_axis_title so you can label both axes directly on the chart.

Fixed an issue where adding a link attribute to a table dimension would cause all column groups to disappear.

🐛 Fixed spacing in the back-to-partial label

Fixed an issue where the "Back to partial" label appeared without a space in preview mode.

🐛 Horizontal bar chart axis min/max now apply exactly

Fixed an issue where x_axis_options.min and x_axis_options.max on horizontal bar charts could be ignored instead of enforcing the requested axis range.

✨ SAP HANA Connector

Connect your SAP HANA data to Evidence. Sync data from SAP ECC and SAP S/4HANA systems running on the HANA platform.

View Documentation

🐛 Fix slider lockup with invalid step values

Fixed an issue where sliders could freeze the page when configured with an invalid step value.

✨ Third-party analytics for published pages

You can now add your own Google Analytics (GA4) or PostHog tracking to published and embedded pages. Configure your analytics provider in Organization Settings under Third-Party Analytics. Available on Enterprise plans.

🚀 Collapsible folders in published and preview sidebars

Added click-to-expand and collapse behavior for sidebar folders in published and preview pages to make navigation easier in larger projects.

✨ Added This Month and Next Month date presets

Range calendars now support this month and next month presets so you can filter full calendar months including upcoming dates.

Fixed an issue where dropdown initial values could fail to apply when option values were provided as numbers.

🚀 Loading indicator for map components

Map components now show a loading indicator while map data is being fetched so blank maps are less confusing during slow queries.

🐛 Fix for occasional AI chat timeouts

Fixed an issue where the AI agent could appear to run out of time when working with large queries.

Fixed an issue where searching in tables could produce errors or fail to recover after clearing a search.

🐛 Fix table sorting when subtotal rows are hidden

Fixed an issue where sorting by measure columns in tables could produce incorrect order when subtotal rows were hidden.

🚀 Add mmm-yy date format

Added a built-in mmm-yy format code so dates can be displayed as month and two-digit year, like Jan-22.

🐛 Fix mobile sidebar close animation flicker

Fixed an issue where the sidebar would briefly flash back into view at the end of its close animation on mobile devices.

🚀 Resizable Sidebar

The sidebar can now be resized by dragging its edge.

🐛 Comparison column formatting fix

Fixed an issue where prior period comparison columns in tables did not apply the same number format as the main value column.

✨ Evidence CLI

Develop Evidence Studio projects locally from the command line with evidence dev.

View Documentation

🐛 Improve filter value visibility in the editor sidebar

Fixed an issue where filter values in the editor sidebar could be hard to read by showing each value on its own line.

🐛 Recent AI chats update instantly

Fixed an issue where new AI chats would not appear in Recent chats until the page was refreshed.

🐛 Improved spacing for small tables

Fixed an issue where tables with only a few rows could show unnecessary empty space.

🚀 Clearer error when defining queries inside components

Added a validation error when inline queries are defined inside components like tabs, accordion, or details. Queries should be defined at the top level of the page.

🐛 Accordion items now maintain their original order

Fixed an issue where accordion items could reorder themselves based on when they were last updated instead of their original document order.

🐛 Support for branch names with slashes in GitHub integration

Fixed an issue where branches containing slashes (e.g., feature/my-branch) would break navigation across the editor, preview, published views, and PDF generation.

🐛 Button group and dropdown initial value fix

Fixed an issue where button groups and dropdowns could not set an initial value when using a numeric value column.

🐛 Fixed organization logo display in dark mode on published pages

Fixed an issue where the organization logo in the sidebar could appear as a dark image on a dark background when viewing published pages in dark mode.

🚀 Option to hide axis title arrow

Added a title_arrow option to x_axis_options that lets you hide the arrow (→) on chart axis titles.

🚀 Demo data table references updated

Demo data tables have moved to the demo schema (e.g. demo_daily_orders → demo.daily_orders). You may need to update references in existing projects and models.

🐛 Fixed model save failing after validation

Fixed an issue where saving a model could fail if the SQL query contained leading or trailing whitespace.

🐛 PDF downloads from editor now use working version

Fixed an issue where downloading a PDF from the editor would always produce the committed version instead of the current working draft.

Fixed an issue where wrapping components in a print group with cards layout enabled would remove the spacing between cards.

Fixed an issue where the Google Analytics connector setup page linked only to the Fivetran docs instead of the Evidence docs page.

🚀 More reliable PDF generation

Improved PDF generation reliability, especially for pages with conditionals, partials, and many components.

🐛 PDF downloads from preview now use working version

Fixed an issue where downloading a PDF from the preview route would always produce the published version instead of the working draft.

🐛 Fixed chart rendering error on published pages with point_title

Fixed an issue where charts using the point_title attribute could fail to render on published pages.

🐛 Fixed scatter chart tooltip with point_title and series

Fixed an issue where the point_title attribute on scatter charts was ignored in the tooltip when a series attribute was also set.

🐛 Fixed scatter chart size attribute

Fixed an issue where the size attribute on scatter charts was ignored, causing all points to render at the same size.

✨ Date range support for map layers

Map layers (point_layer, area_layer, and heatmap_layer) now support the date_range attribute for filtering data by time period.

✨ PayPal Connector

Connect your PayPal data to Evidence. Sync transactions, invoices, payments, subscriptions, and billing plans.

View Documentation

🚀 Connection string autofill for PostgreSQL connections

You can now paste a PostgreSQL connection string into any field when setting up a PostgreSQL connection, and all fields will be automatically filled in.

✨ RevenueCat Connector

Connect your RevenueCat subscription data to Evidence. Sync subscribers, transactions, entitlements, offerings, and products.

View Documentation

🚀 Invite team members from the Share menu

Added a quick link to Team Settings from the Share menu so you can invite new team members while managing page or project access.

🐛 Fix for dimension grid with inline queries

Fixed an issue where the dimension grid component could not use inline SQL queries as its data source.

🐛 Fix legend color for lines with explicit color in combo charts

Fixed an issue where lines in combo charts with an explicit color option (e.g., options={color="black"}) would display the palette color in the legend instead of the specified color.

🚀 Improved component search with keyword aliases

Added search keywords to component schemas so components can be found by common alternative names (e.g., "scatter plot" for scatter chart, "donut" for pie chart, "KPI" for big value).

🐛 Fix filters with multiple consecutive spaces in values

Fixed an issue where filter values containing multiple consecutive spaces would fail to match data correctly.

🐛 Fix collapsible table arrows not showing with hide_row_totals

Fixed an issue where collapsible table arrows were not visible when measures had hide_row_totals enabled.

🐛 Fix branch deletion when branch was already deleted on GitHub

Fixed an issue where deleting branches from the Evidence UI would fail with an error when the branch had already been deleted on GitHub (e.g., by GitHub's auto-delete on merge feature).

✨ Candlestick chart component

Added a new candlestick chart component for visualizing OHLC financial data with optional volume bars.

View Documentation

🐛 Fix for overlapping content in PDF exports

Fixed an issue that could cause overlapping content in PDF exports.

✨ Percentage labels for pie charts

Added pct and pct_fmt options for pie charts to display percentage values directly on slice labels.

View Documentation

🐛 Fix AI chat generating dropdowns and date range filters

Fixed an issue where AI chat could fail when generating dropdowns or date range filters.

✨ Salesforce Connector

Connect your Salesforce CRM data to Evidence. Sync accounts, contacts, opportunities, leads, and campaigns.

View Documentation

🐛 Fix x_fmt not applying to chart tooltips

Fixed an issue where setting x_fmt on charts would format the axis labels but not the date value shown in the tooltip.

🐛 Improved AI chat reliability

Fixed an issue where AI chat could error out during longer conversations.

✨ Date Range Support for Input Components

Input components (dropdown, button_group, input_tabs, slider, dimension_grid) now support the date_range attribute, allowing you to filter options by a specific time period or a range_calendar selection.

🐛 Fix dropdown with manual options showing SQL error

Fixed an issue where dropdowns using manual child option tags (no data attribute) would show an "Unknown table function WHERE" error.

✨ Multiplayer editor now in beta

Multiplayer editor is now available in beta. Turn it on from Project Settings to collaborate with your team in real-time.

🐛 Graceful redirect when page not found after branch switch or rename

Fixed an issue where switching branches or renaming a page could result in a 404 when the current page doesn't exist on the target branch or at the old URL.

Fixed an issue where clicking dimension links in tables would result in a 404 when navigating between pages, because the URL wasn't being resolved relative to the current project context.

🐛 Automatic chart padding for data labels

Charts now automatically add top padding when data labels are positioned above bars or points, preventing labels from being cut off at the top of the chart.

Projects connected to GitHub now show all repository branches in the branch switcher, not just branches created through Evidence Studio. When a pull request is opened or reopened, Evidence automatically posts a preview link comment on the PR.

🚀 SQL Console Table Grouping

Tables in the SQL console sidebar are now organized by schema/connection in a collapsible tree structure for easier navigation.

✨ Customizable Total Label for Tables

Tables now support a total_label attribute that allows customizing the text displayed in total/subtotal rows and columns, useful when using non-sum aggregations like avg, min, max, or count.

✨ Editor Sidebar

Enhanced editor sidebar, with diff viewer, search, table schema, and page filters.

🚀 Pivot Table Performance

Significant performance improvements for pivoted tables and increased row/column limits.

🐛 Fix dropdowns closing modals

Fixed an issue where clicking on dropdown menus inside a modal would cause the modal to close unexpectedly.

🐛 Stable AI Edit Previews

Prevent AI edits from causing full refresh

✨ Gradient fill for area charts

Area charts now support a gradient fill option that fades from the series color at the top to transparent at the bottom. Enable it with area_options={ gradient=true }.

View Documentation

✨ Clock Component

Display a live clock with running seconds and the current date using {% clock /%}. Supports 12h/24h format, monospace font variant, and left/right alignment.

✨ Branching

Work on multiple versions of your reports at the same time. Create and switch between branches, commit your work, and publish when you're ready.

✨ Heat Grid

Visualize metrics across categories with color-coded cells based on configurable thresholds. Cells are colored red, yellow, or green depending on where values fall relative to your thresholds, with an optional lower_is_better mode.

🚀 Model Engine and Primary Key Settings

The model edit page now includes configurable refresh schedules, table engine selection, and primary key configuration with helpful tooltips explaining each engine type, data locations, and nullable primary key handling.

View Documentation

✨ Progress Bars

Display progress toward goals with horizontal bars showing numerator/denominator ratios. Supports threshold-based coloring and custom color gradients.

✨ PDF Export Options

PDF export now supports custom orientation, margins, and card styling options.

✨ Datadog Connector

Connect your Datadog monitoring and analytics data to Evidence. Sync metrics, dashboards, monitors, hosts, and usage data from your Datadog account.

View Documentation

✨ Custom Title for Table Filter

Customize the Table Filter button text using the new title attribute.

✨ Table Repeat Dimension Values

Tables and dimensions now support a repeat_values attribute that forces dimension values to display on every row instead of being collapsed.

🚀 Improved code editor font

The code editor now uses Geist Mono, a modern monospace font designed for better readability and aesthetics.

✨ Custom AI Instructions

Configure custom instructions for the AI assistant in Settings > AI Agent.

✨ RDS PostgreSQL Connector

Connect your RDS PostgreSQL database to Evidence and sync your data automatically.

View Documentation

🚀 PostgreSQL TLS Requirement Documentation

Added documentation note for PostgreSQL and Azure PostgreSQL connectors specifying that TLS/SSL must be enabled on the database for secure connections.

✨ Collapsible Tables

Tables with subtotals can now be collapsed. Click subtotal rows to expand or collapse their children.

View Documentation

Fixed chevron column styling in tables with row links to match total/subtotal row backgrounds.

✨ Total and Subtotal Position

Control where totals and subtotals appear with total_position and subtotal_position. Set to "top" or "bottom".

View Documentation

🚀 Table Filter Initial Values and Required Selections

Table filters now support initial_values to set default filter values when the page loads, and require_selection to prevent specific filters from being cleared.

🚀 Automatic Unit Formatting for Numbers

BigValue, Value, and Table components now auto-format large numbers with compact units (e.g., $1.2M instead of $1,234,567)

✨ Text Size Option for Big Value

The big_value component now supports a text_size attribute with predefined options (sm, base, lg, xl, 2xl, 3xl, 4xl, 5xl) for reliable text sizing.

🚀 Clear Table Sorting with Third Click

Click a column header a third time to clear sorting and return to the original order.

View Documentation

✨ Azure SQL Database Connector

Sync data from Azure SQL Database directly into Evidence.

View Documentation

✨ Logo Attribute for Table Dimensions

Display company logos in table dimension columns. The new logo attribute accepts a column containing domains to look up logos, and logo_options lets you customize size, grayscale mode, and label visibility.

View Documentation

✨ PDF Export for Viewers

Viewers can now download published pages as PDFs using the page menu or the keyboard shortcut (Cmd/Ctrl+P).

✨ Twilio Connector

Connect your Twilio data to Evidence. Sync calls, messages, accounts, and usage records.

View Documentation

🚀 BigQuery 1 Minute Incremental Syncs

BigQuery data connector now supports 1 minute incremental syncs for faster data freshness.

View Documentation

✨ Column Groups in Tables

Group related columns under shared headers using the new column_group attribute on measures and dimensions. Useful for organizing metrics by category, such as revenue metrics vs volume metrics.

🐛 Dark Mode Empty Circle Markers Fix

Fixed emptyCircle markers in charts to properly use the background color in dark mode instead of white.

✨ Databricks Data Connector

Sync data from Databricks directly into Evidence.

View Documentation

Connect your Google Ads and Facebook Ads data to Evidence. Sync campaigns, ad groups, ads, and performance metrics to build marketing analytics dashboards.

View Documentation

🐛 Horizontal Bar Chart Sorting Fix

Horizontal bar charts now default to sorting by value descending, showing the largest values at the top instead of the bottom.

✨ Logo Component

New logo component to display company logos using logo.dev. Supports light/dark theme switching, configurable sizes, and grayscale mode.

✨ MySQL Data Connector

Sync data from MySQL directly into Evidence.

View Documentation

✨ PostHog Connector

Connect your PostHog product analytics data to Evidence. Sync events, persons, cohorts, feature flags, insights, and more from your PostHog account.

View Documentation

🚀 Snowflake 1 Minute Incremental Syncs

Snowflake data connector now supports 1 minute incremental syncs for faster data freshness.

View Documentation

✨ SQL Server Data Connector

Sync data from SQL Server directly into Evidence.

View Documentation

✨ Dimension Grid

New dimension_grid component for interactive multi-dimensional filtering.

🐛 Fix for frozen columns row shading

Frozen columns in tables now display the correct alternating row shading when row_shading=true is enabled. Previously, frozen columns would not show the shading because they had a solid background that overrode the row-level shading.

✨ Series colors for pie charts

Map specific category values to specific colors in pie charts using the series_colors option in chart_options. This ensures consistent, meaningful coloring regardless of which categories are present in the data.

🐛 Export Data Retains Filters

Table exports now correctly include filtered and sorted data, matching the visual display on screen.

🐛 PDF Export Now Retains Filters

When downloading a PDF, any selected filter values are now preserved in the exported PDF.

🚀 Adjusted Developer Role Privileges

Previously, developers and admins could manage users, groups and customers. This is now restricted to Admins only.

✨ Motherduck Connector Schema Support

You can now use schema with the Motherduck connector

The dropdown component now supports the where attribute for filtering dropdown options with custom SQL WHERE conditions, bringing it to feature parity with other filter components like button_group and input_tabs.

🐛 Horizontal Bar Chart X-Axis Formatting

Fixed issue where the x_fmt parameter was not being applied to axis labels in horizontal bar charts. Formatting now works consistently for both axis labels and tooltips.

Add your organization's logo in settings

✨ Github Data Connector

Sync data about your Github repos directly into Evidence.

✨ Deltalake (S3) Connector

Connect using your S3 with Delta Lake format your data remains at rest in your S3 bucket.

✨ Smooth Line Option

New smooth attribute inside line options lets you create a line with rounded corners

View Documentation

✨ Chart `height` attribute

Control the height of your charts using the height attribute

View Documentation

✨ Customer Groups

Create customers, and invite customer users to view reports that you choose.

View Documentation

✨ Groups

Add team members to groups to simplify permissions on projects and pages

View Documentation

🚀 Improved Excel Export

Excel exports now use component titles to create tab names, and exclude logic and filter components

✨ User Variables

Access the user's name, email and organization using variables in markdown.

View Documentation

✨ Themes

Set color themes at the organization, project, and page level - including background, chart, and card colors

Access theme settings in page settings, project settings, or org settings. You can override theme colors at each level (e.g., project can override org theme, page overrides project and org themes)

View Documentation

🚀 Improved Translation Validation Errors

Incorrect structures for translation maps will provide useful errors

🚀 Translations Editor

Modify translations with a fully featured text editor

🚀 Improved bucket docs

Adds more information about using bucket connectors

View Documentation

✨ Translation Management

Define variables with different translations for multi-language apps.

View Documentation

✨ Standalone Horizontal Bar Chart Component

New dedicated horizontal_bar_chart component makes it easier to create horizontal bar charts

We recommend migrating any existing horizontal bar charts to this new component

View Documentation

✨ Display control for total and subtotals in table

Choose which totals or subtotals to display in your table

View Documentation

✨ Dark Mode Chart Colors

Configure colors for both light and dark mode in your project and org settings

✨ Input tabs full_width and align attributes

Input tabs now allows the same styling configuration as the Tabs component, including full width and right align

View Documentation

✨ Conditional Formatting

Apply conditional logic to choose colors for visualizations

✨ Series Color Mapping

Option to select specific colors for series in your charts

View Documentation

🚀 Assign access to pending users

You can now grant project and page access to users who have not yet accepted invitations to join the Evidence organization.

🚀 Control order of series in combo chart

Combo chart now displays your series in the order you define them in your markdown

✨ Draft Diff Viewer

Review your changes using the diff viewer before you publish

🚀 Icons in Autocomplete

Find components more easily in component autocomplete menus using the mini-icons

🚀 Smoother chart loads on input changes

Improved chart loading behaviour and animation when changing inputs on your page

🐛 Fix for table pivoting issues

Fixed issue where tables were not pivoting in certain situations

✨ `fmt` property for input options

Use dynamic formats in viz components when creating an input to select a metric - e.g., show 'usd' for sales or 'pct1' for growth

View Documentation

✨ Variable `label` property

You can now reference the label property of a variable - useful when adding labels to viz components based on input selection

View Documentation

🐛 Fix for custom date range end dates

Fixes issue where custom end date defined in SQL was not taking effect

🐛 Fix for scale_column

Fixes issue where scale_column in the measure component was not properly assigning colors

🚀 Improved handling of date grains in charts

Automatically handles formatting and positioning of labels on x-axis for date grains including month of year and day of week

✨ Table of Contents

A generated table of contents from the headings in your report. Enable from page settings.

✨ Top padding option for charts

Top padding override option to allow more room for data labels - helps in cases where labels are cut off

✨ x_sort attribute

Choose a specific sort order for your x-axis, including specifying explicit strings

🐛 Histogram support for inline queries

Fix for Histogram issue where it could not accept inline queries

🚀 Toggle `invert` attribute

Invert attribute added to make toggled state = false instead of true

✨ Slider Input

New slider input component to filter on numeric values

View Documentation

✨ Query timing metadata

Queries in the SQL Console, and the pop out component inspector at the bottom of the editor now display how long the query took to run in the Evidence query engine

✨ Zoomable charts

Adds a new "zoom" chart option to enable zooming into the data

✨ Toggle input

New toggle input component which sets a boolean variable you can use in queries and components

View Documentation

✨ Button group and input tabs

New input components as visual alternatives to dropdowns: button_group and input_tabs

Note that this update also deprecates the dropdown_option component in favour of the more general option component. The option component can be used inside dropdown, button_group, or input_tabs

View Documentation

Add links to info text popovers using info_link and info_link_title atttributes.

🚀 User Management Performance

Adding and removing users from reports is now faster

🐛 Fix for custom pivot formatting

Formatting for pivots now works as expected for custom date formats - e.g., fmt="yyyy-mm"

✨ Select all in dropdown

New button to select all options in a dropdown

✨ Text input component

Input component accepting free text input

View Documentation

✨ Feature Requests

Submit and track feature requests directly in your settings menu

From Settings > Feature Requests, you can create requests or bug reports, and set their priority. This integrates directly with the Evidence team's roadmap, with status changes synced into your view

✨ Stacked bar series in combo charts

Bar series in combo charts can now be stacked using the new stack_id attribute. Bars with the same stack_id will be stacked together, allowing for flexible combinations of stacked and grouped bars.

View Documentation

✨ Max label length for x-axis labels

Truncate labels after a certain number of characters using the max_label_length attribute inside x_axis_options

✨ Rotate x-axis labels

Use the new label_rotate option in x_axis_options to rotate the labels on your x-axis

View Documentation

Add custom icons and adjust the sort order of projects and pages in the sidebar

✨ Jump to Code

In the editor preview, Cmd/Ctrl + click on a component to jump to the code for that component

You can jump to code by Cmd/Ctrl + clicking a component in the preview pane, or you can jump to the component preview by Cmd/Ctrl + clicking the code in your editor

🐛 Fixes for table pivoting

Fixed issue where columns were not properly pivoting in tables

🚀 Drag and drop image support

Drag, or paste images into the editor to add them to your page.

✨ Models (Beta)

Join sources together and materialize the results to improve performance

Models can be used to execute joins across sources, centralize type casting, and create clean tables to use when building reports. Models are run and materialized every 8 hours

View Documentation

✨ Set custom end date for date ranges

Use a dynamic end date for date ranges based on your data or a standard offset

By default, date ranges end as of today's date, but this setting allows you to choose a date based on a standard offset (e.g., 1 day ago) or by passing a sql query to calculate the date (e.g., select max(date) from my_table)

✨ Bar chart opacity setting

Customize the opacity of bars in bar chart and combo chart components

🚀 Project Sections

Organize projects into sections for easier navigation during development

Sections will not impact how projects are arranged in the app published to Viewer users

🐛 Version control overflow

Fixes a bug where if you changed lots of files it overflowed the Version History panel

✨ Option to choose first day of week

In project settings, you can now choose whether weeks start on Sunday or Monday

🚀 Better SQL Autocomplete Suggestions

Improved SQL suggestions for columns, and tables after joins

🚀 Variable name shortcuts + use in markdown

Variables no longer require specifying a property - simply use the name, like {{ my_var }}

You can also use variables directly in markdown, including in headers and lists. You still have access to variable properties and can reference them like this: {{ my_var.selected }}

🚀 Performance improvement for table comparisons

Tables containing comparisons should now load much faster

🚀 More source sync info

View the number of rows in a source, and the amount of time it took for the source sync from the Sources page.

✨ Use variables inside components

You can now reference filter variables directly in component attributes

Supports the following attributes: title, subtitle, info, where, date_grain, date_range.range, comparison.compare_vs

✨ Icon support for dropdowns

Include an icon in your dropdown using the icon option

✨ Selector components for date grain and comparisons

Special components for selecting date grain and comparisons

🚀 Dynamic date ranges

Input arbitrary ranges into the date_range attribute in components, like "last 14 weeks" or "2023-01-14 to 2025-11-30"

🐛 Filter scroll fix

Fixed a bug where selecting a filter caused the page to jump back to the top.

✨ Select preset ranges in range calendar

Choose which preset ranges you want your users to see when clicking the range calendar component

🐛 SQL comments in inline queries

You can now add comments to inline queries without breaking them

✨ Option to turn legend off in charts

You can now turn off chart legends with legend=false

🚀 Conditional component render instantly

When previewing or viewing published pages, the initial state of any if/else_if/else conditions will be pre-calculated before the page loads.

🚀 Better label spacing on x-axis

Improvement to the alignment and spacing of labels on the x-axis

🐛 Fix target comparison totals in table

Fixed an issue where target comparisons were hidden in total rows

🐛 Improved date behaviour

Previously, database columns that returned Date type would return DateTime precision, which is confusing in the UI. Now dates will return no additional time component

Values that are Date type will no longer display time component in Tables, Values, and in various input components. Eg a Date previously formatted 2025-09-22T14:05:23Z would now be returned as 2025-09-22.

🐛 Fix Explore table resize and scroll

Fixes an issue where tables on the Explore page would resize and cut off content

🚀 Comparison Tooltip Improvements

Fixed issue with percentage calculations for negative values. Added support for custom formats.

✨ Make Feature Requests in AI Chat

Now you can ask the Evidence chat to submit a feature request to the Evidence team

🐛 Fixed unexpected date offsets

In certain timezones, dates were being transposed by a small number of seconds in Chrome and Safari. This could cause date formats to render incorrectly, for example showing the day before the expected date.

🚀 RLS Enhancements

Added variable support for IN/NOT IN operators, 'Apply All' rule option, new panel interface, and per-user variable editing capabilities.

🚀 Improved Inline SQL Editor

See available variables, inline queries, and a preview of compiled SQL when editing queries in the inline SQL editor

🚀 Improved international character support in SQL queries

You can now include Japanese, Chinese, emoji, and other non-Latin characters directly in SQL passed to components

✨ Page Loading (table)

Tables now load instantly on preview and published pages

This is the first change in a journey to fully enable Server-Side Rendering in Evidence pages. The table is the first component to support this behavior, which enables the following features:- Tables load instantly on preview and published pages (no more loading spinner when the page loads)- Chat can now debug SQL query errors in Table componentsThis change lays the groundwork for other components to opt into this new Server-Side Rendering system.

✨ Add optional dark_url prop to image component

Image components can now display different images in light and dark modes using the new dark_url prop.

✨ Themes

Define a custom color palette to apply to all charts in a project

🚀 Improved Default Funnel Chart Styling

Funnel Charts are more intuitive to read, with a squared off style

View Documentation

🐛 Fix Comparison Issues

Fixed bug for target comparisons which resulted in undefined error

✨ Inline SQL Editor

A new SQL editor for running and modifying inline queries on your page

✨ Icon Component

Add icons inline into markdown, with configuration for color and size

View Documentation

✨ Row Level Security

Add rules to restrict which rows of are visible to users from sources

Add RLS rules to data source columns, and add user variables to determine which values in these columns allow access.

View Documentation

🚀 Custom Color Palettes

All charts now support custom color palettes via the "chart_options" attribute

Pass an array of hex codes to the color_palette option e.g. color_palette=["#ff0000","#00ff00"]

View Documentation

🐛 Fix Editor Overwriting Bug

Fixed bug where switching pages and then hitting Ctrl+Z would overwrite your page with the content of the previous page.

Adds hover text to sidebar items that are truncated due to length

🐛 Table Filter Option Overflow

Fixed a bug where long string values in the table filter overlapped each other

🚀 Charting Library Upgrade

Upgraded to ECharts 6, fixed some issues where labels got cut off

🐛 Expose SQL Errors

Exposes some SQL errors that were not being shown

🐛 Fix High Precision Decimals in Postgres

Resolves issue where tables containing decimal columns with more that 9 digits of precision were failing to publish

🚀 Editor Loading Speed

We've significantly improved the load speeds when switching between pages in the editor.

Use the link button to link to another page in Evidence or an external location

View Documentation

Add page breaks, print groups, and hide elements from PDF downloads

✨ PDF Download

Download your page as a PDF

🐛 If / Else Behaviour Fix

Fixed some issues with the if /else components which sometimes caused them to not display information when they should

✨ Accordian components

Organize content into collapsible accordian sections

✨ Axis Label Interval Control

More control over the intervals between labels on charts

🐛 Long Page Name Overflow

Long page and directory names now truncate in the sidebar to prevent the action button being hidden

✨ Range Calendar Input

New range calendar component for date filtering.

✨ Tabs

New Tabs, and Tab components for tabbed layouts.

✨ Variables

Define variables in frontmatter and use them in markdown, SQL and components

View Documentation

✨ Column-level control for tables

Control formatting for each column in a table

✨ Conditional formatting in tables

Use color scale to conditionallyformat values in a table

✨ Image support in tables

Add images to columns in a table

🚀 Improved Explore page

Supports more date grain options and improved share experience

🚀 Improved pivot table

Table now supports more complex pivot table scenarios

Add links to columns in a table, or set up row links

🚀 New date grain options

Inclues special grains like 'day of week' and 'month of year', with built-in labels

✨ New table visualizations

Add bar charts, sparklines, and deltas to your columns

✨ Period over period comparisons

Automatically compare values vs. prior year, prior period, or target. Available in table and big value.

🐛 Delete Connections Fix

Fixed a bug which only allowed you to delete the most recently added connection

✨ Hubspot Connector

Import data from Hubspot directly into Evidence

View Documentation

✨ Modals

New modal component that can contain content in a dialogue or drawer.

View Documentation

✨ Motherduck Connector

Add data sources from your Motherduck DB

View Documentation

✨ Page linking

Link to other Evidence pages using markdown links []() with Intellisense support

View Documentation

🐛 Respect columns option in table filter

Fix bug which ignored columns selection in table filter

🐛 Table filter responsiveness

Fix bug which prevented table filter inputs from taking effect immediately after adding the table filter to the page.

✨ Filter interpolation

Reference filter values inside of inlined queries, and view the state of your filters in the new filters pane of the devtools sidebar.

View Documentation

🚀 Agent Keyboard Shortcut

Ctrl+Alt+I (Mac: Cmd+Shift+I) to open a chat with the Evidence agent from anywhere in the Editor

✨ If, Else If, Else

Use conditional blocks to choose what to render based on data.

View Documentation

✨ Reference Components

Use reference_line, reference_area, and reference_point to add reference annotations to your charts

View Documentation

🚀 Postgres Schema Support

Use tables in any Postgres schema (not just the default "public" schema)

✨ Import Views as Sources

All supported DBs now allow importing views as sources

🚀 Public Documentation

We've published full documentation at https://docs.evidence.studio

✨ Card Option for Row and Stack Components

Added card option to row and stack components to display their contents as a single card.

✨ Data Point Labels

Label each data point in your chart with the data_labels option

✨ Downloadable Data

Right click any chart to download its data, or use the kebab menu in the top left of the published page to download a whole page's data.

✨ Chart, Axis, and Series Options

New chart_options, x_axis_options, y_axis_options, y2_axis_options, and series options for customizing your charts.

✨ Partials

Define sections of markdown for re-use across pages.

✨ Polar Chart

Added a new polar chart component.

Search bar for the Table component.

🐛 Inline Query Date Validation

Fixes issue creating visualizations using inline queries with dates

✨ Histogram

Added a new histogram chart component.

✨ Markdown Comments

Adds support for mardown comments with &lt;!-- --&gt;. Mac: Cmd + / Windows: Ctrl + /

✨ Calendar Heatmap

Added a new calendar heatmap chart.

✨ Combo Chart

Added a combo_chart component that allows you to combine area, bar, bubble, line, and scatter series on one chart.

✨ Accept and Reject Changes Panel in Diff View

Added accept and reject buttons to the top of the diff view.

🚀 Connection Documentation

Added generaldocumentation for data connections.

🐛 Fix to give AI agent knowledge of inline queries

Fixed the issue where the AI agent did not know about inline queries on your page.

🐛 Fix to Maintain Chart Height

Fixed the issue where the chart height was shrinking when title and legend were added.

✨ Heatmap Chart

Added a new heatmap chart component.

Added a link to all docs in the docs tab of the editor.

✨ Custom X and Y Chart Titles

Added the ability to customize x_title and y_title for charts.

✨ Funnel Chart

Added a new funnel chart component.

✨ Sankey Chart

Added a new sankey chart component.

✨ Changelog

We're shipping features and fixes very quickly. Keep an eye out here for updates.

🐛 Fix Slash Commands When Inside Parent Component

Fixed the issue where slash commands were not working when inside a parent component.

🚀 Helpful Warning for Aggregating Columns

Added a warning to consider aggregating a column for a chart.

✨ Open Chat Automatically for Fix in Chat

When the fix in chat button is pressed, the chat window will open automatically.

✨ Pie and Donut Charts

Added a new pie chart component.

🚀 Collapse the Sidebar

Added the ability to collapse and expand the sidebar on all screen sizes.

🚀 Faster Sources Page

Significantly improved loading performance on the sources page.

🚀 Fix in Chat Now Available on All Error Messages

Error messages throughout the platform now include the fix in chat feature.

🚀 More Readable SQL Errors

SQL error messages have been redesigned to be clearer and more actionable.

🐛 Row and Stack Components

Fixed issues with Row and Stack components rendering and layout behavior.

✨ European Number Formatting

Support for European number format using comma as the decimal separator (e.g., 1.234,56 instead of 1,234.56).

✨ Azure Postgres Connector

Connect your Azure Database for PostgreSQL to Evidence and sync your data automatically.

View Documentation

✨ SQL Files

Create reusable SQL queries as standalone files. SQL files can be referenced from components using data="path/to/query" and from inline queries using {{path/to/query}} syntax.


Docs.Json (`docs/docs.json`)

{
"$schema": "https://mintlify.com/docs.json",
"theme": "maple",
"thumbnails": {
"fonts": {
"family": "Geist"
}
},
"icons": {
"library": "lucide"
},
"name": "Evidence Docs",
"colors": {
"primary": "#2c5282",
"light": "#2c5282",
"dark": "#15803D"
},
"integrations": {
"posthog": {
"apiKey": "phc_5gRFl1Rp6a01CZM9CX3qDvFwyxp7YzdWvdGAgi8a1fq"
}
},
"favicon": "/favicon.svg",
"redirects": [
{
"source": "/features/embedded",
"destination": "/features/embedded-analytics"
},
{
"source": "/features/code-managed-access",
"destination": "/features/page-level-access-control"
},
{
"source": "/features/page-frontmatter",
"destination": "/features/page-settings"
},
{
"source": "/features/access-control",
"destination": "/features/row-level-security"
},
{
"source": "/features/access-rules",
"destination": "/features/row-level-security"
},
{
"source": "/features/project-configuration",
"destination": "/features/project-settings"
},
{
"source": "/features/mcp-server",
"destination": "/mcp/docs"
},
{
"source": "/features/evidence-mcp",
"destination": "/mcp/studio"
},
{
"source": "/install-evidence",
"destination": "/quickstart"
},
{
"source": "/getting-started/install-evidence",
"destination": "/quickstart"
},
{
"source": "/build-your-first-app",
"destination": "/quickstart"
},
{
"source": "/core-concepts/queries",
"destination": "/evidence-warehouse"
},
{
"source": "/core-concepts/formatting",
"destination": "/core-concepts/value-formatting"
},
{
"source": "/core-concepts/filters",
"destination": "/components/filter_bar"
},
{
"source": "/core-concepts/themes",
"destination": "/features/themes"
},
{
"source": "/core-concepts/templated-pages",
"destination": "/features/page-settings"
},
{
"source": "/core-concepts/exports",
"destination": "/components/download"
},
{
"source": "/core-concepts/syntax",
"destination": "/core-concepts/markdown"
},
{
"source": "/core-concepts/pages",
"destination": "/features/page-settings"
},
{
"source": "/core-concepts/query-functions",
"destination": "/core-concepts/models"
},
{
"source": "/core-concepts/if-else",
"destination": "/components/if"
},
{
"source": "/core-concepts/loops",
"destination": "/components/repeat"
},
{
"source": "/core-concepts/data-sources/duckdb",
"destination": "/evidence-warehouse"
},
{
"source": "/core-concepts/data-sources/bigquery",
"destination": "/direct-connectors/bigquery"
},
{
"source": "/core-concepts/data-sources/postgres",
"destination": "/direct-connectors/postgres"
},
{
"source": "/core-concepts/data-sources/javascript",
"destination": "/evidence-warehouse"
},
{
"source": "/core-concepts/data-sources/csv",
"destination": "/evidence-warehouse"
},
{
"source": "/core-concepts/data-sources/snowflake",
"destination": "/direct-connectors/snowflake"
},
{
"source": "/core-concepts/data-sources/google-sheets",
"destination": "/evidence-warehouse"
},
{
"source": "/core-concepts/data-sources/databricks",
"destination": "/direct-connectors/databricks"
},
{
"source": "/core-concepts/data-sources/trino",
"destination": "/evidence-warehouse"
},
{
"source": "/core-concepts/data-sources/mssql",
"destination": "/evidence-warehouse"
},
{
"source": "/core-concepts/data-sources/motherduck",
"destination": "/direct-connectors/motherduck"
},
{
"source": "/components/charts/echarts-options",
"destination": "/components/custom_echart"
},
{
"source": "/components/charts/custom-echarts",
"destination": "/components/custom_echart"
},
{
"source": "/components/charts/bar-chart",
"destination": "/components/bar_chart"
},
{
"source": "/components/charts/line-chart",
"destination": "/components/line_chart"
},
{
"source": "/components/charts/sankey-diagram",
"destination": "/components/sankey_chart"
},
{
"source": "/components/charts/heatmap",
"destination": "/components/heatmap"
},
{
"source": "/components/charts/calendar-heatmap",
"destination": "/components/calendar_heatmap"
},
{
"source": "/components/charts/mixed-type-charts",
"destination": "/components/combo_chart"
},
{
"source": "/components/charts/funnel-chart",
"destination": "/components/funnel_chart"
},
{
"source": "/components/charts/annotations",
"destination": "/components/reference_line"
},
{
"source": "/components/charts/scatter-plot",
"destination": "/components/scatter_chart"
},
{
"source": "/components/charts/area-chart",
"destination": "/components/area_chart"
},
{
"source": "/components/charts/histogram",
"destination": "/components/histogram"
},
{
"source": "/components/charts/sparkline",
"destination": "/components/sparkline"
},
{
"source": "/components/charts/bubble-chart",
"destination": "/components/bubble_chart"
},
{
"source": "/components/data/data-table",
"destination": "/components/table"
},
{
"source": "/components/data/big-value",
"destination": "/components/big_value"
},
{
"source": "/components/data/value",
"destination": "/components/value"
},
{
"source": "/components/data/delta",
"destination": "/components/delta"
},
{
"source": "/components/inputs/dropdown",
"destination": "/components/dropdown"
},
{
"source": "/components/inputs/date-range",
"destination": "/components/range_calendar"
},
{
"source": "/components/inputs/date-input",
"destination": "/components/range_calendar"
},
{
"source": "/components/inputs/dimension-grid",
"destination": "/components/dimension_grid"
},
{
"source": "/components/inputs/button-group",
"destination": "/components/button_group"
},
{
"source": "/components/inputs/slider",
"destination": "/components/slider"
},
{
"source": "/components/inputs/text-input",
"destination": "/components/text_input"
},
{
"source": "/components/inputs/checkbox",
"destination": "/components/toggle"
},
{
"source": "/components/inputs",
"destination": "/components/dropdown"
},
{
"source": "/components/maps/area-map",
"destination": "/components/area_layer"
},
{
"source": "/components/maps/point-map",
"destination": "/components/point_layer"
},
{
"source": "/components/maps/bubble-map",
"destination": "/components/point_layer"
},
{
"source": "/components/maps/us-map",
"destination": "/components/map"
},
{
"source": "/components/maps/base-map",
"destination": "/components/map"
},
{
"source": "/components/ui/embed",
"destination": "/components/iframe"
},
{
"source": "/components/ui/link",
"destination": "/components/link"
},
{
"source": "/components/ui/grid",
"destination": "/components/row"
},
{
"source": "/components/ui/tabs",
"destination": "/components/tabs"
},
{
"source": "/components/ui/big-link",
"destination": "/components/link_button"
},
{
"source": "/components/ui/link-button",
"destination": "/components/link_button"
},
{
"source": "/components/ui/image",
"destination": "/components/image"
},
{
"source": "/components/ui/info",
"destination": "/components/info"
},
{
"source": "/components/ui/alert",
"destination": "/components/callout"
},
{
"source": "/components/ui/download-data",
"destination": "/components/download"
},
{
"source": "/components/ui/details",
"destination": "/components/details"
},
{
"source": "/components/ui/print-format-components",
"destination": "/components/print_group"
},
{
"source": "/components/ui/accordion",
"destination": "/components/accordion"
},
{
"source": "/components/ui/modal",
"destination": "/components/modal"
},
{
"source": "/components/ui/note",
"destination": "/components/note"
},
{
"source": "/components/custom/custom-component",
"destination": "/core-concepts/custom-components"
},
{
"source": "/components/custom/component-queries",
"destination": "/core-concepts/custom-components"
},
{
"source": "/components/all-components",
"destination": "/core-concepts/components"
},
{
"source": "/reference/layouts",
"destination": "/features/layouts"
},
{
"source": "/reference/markdown",
"destination": "/core-concepts/markdown"
},
{
"source": "/reference/cli",
"destination": "/cli/commands"
},
{
"source": "/deployment/overview",
"destination": "/publishing"
},
{
"source": "/deployment",
"destination": "/publishing"
},
{
"source": "/deployment/self-host",
"destination": "/self-host"
},
{
"source": "/deployment/self-host/vercel",
"destination": "/self-host/vercel"
},
{
"source": "/deployment/self-host/github-pages",
"destination": "/self-host"
},
{
"source": "/deployment/self-host/netlify",
"destination": "/self-host"
},
{
"source": "/deployment/self-host/gitlab-pages",
"destination": "/self-host"
},
{
"source": "/deployment/self-host/hugging-face-spaces",
"destination": "/self-host"
},
{
"source": "/deployment/self-host/azure-static-apps",
"destination": "/self-host"
},
{
"source": "/deployment/self-host/firebase",
"destination": "/self-host"
},
{
"source": "/deployment/self-host/aws-amplify",
"destination": "/self-host"
},
{
"source": "/deployment/configuration/rendering-modes",
"destination": "/features/project-settings"
},
{
"source": "/deployment/configuration/environments",
"destination": "/features/project-settings"
},
{
"source": "/deployment/configuration/base-paths",
"destination": "/self-host"
},
{
"source": "/guides/system-requirements",
"destination": "/self-host"
},
{
"source": "/guides/updating-your-app",
"destination": "/migration-guide"
},
{
"source": "/guides",
"destination": "/quickstart"
},
{
"source": "/plugins/source-plugins",
"destination": "/evidence-warehouse"
},
{
"source": "/plugins/component-plugins",
"destination": "/core-concepts/custom-components"
},
{
"source": "/plugins/create-component-plugin",
"destination": "/core-concepts/custom-components"
},
{
"source": "/plugins/create-source-plugin",
"destination": "/evidence-warehouse"
},
{
"source": "/plugins",
"destination": "/core-concepts/custom-components"
},
{
"source": "/components/charts/box-plot",
"destination": "/components/custom_echart"
},
{
"source": "/components/ui/last-refreshed",
"destination": "/components/html"
},
{
"source": "/deployment/cloud/evidence-cloud",
"destination": "/publishing"
},
{
"source": "/guides/troubleshooting",
"destination": "/"
},
{
"source": "/guides/best-practices",
"destination": "/"
},
{
"source": "/deployment/self-host/cloudflare-pages",
"destination": "/self-host"
},
{
"source": "/getting-started/what-is-evidence",
"destination": "/"
},
{
"source": "/markdown",
"destination": "/core-concepts/markdown"
},
{
"source": "/themes-and-layouts",
"destination": "/features/layouts"
},
{
"source": "/plugins/creating-a-plugin",
"destination": "/core-concepts/custom-components"
},
{
"source": "/guides/updating-your-project",
"destination": "/migration-guide"
},
{
"source": "/components/area-map",
"destination": "/components/area_layer"
},
{
"source": "/components/us-map",
"destination": "/components/map"
},
{
"source": "/components/bubble-map",
"destination": "/components/point_layer"
},
{
"source": "/components/point-map",
"destination": "/components/point_layer"
},
{
"source": "/components/base-map",
"destination": "/components/map"
},
{
"source": "/components/download-data",
"destination": "/components/download"
},
{
"source": "/components/last-refreshed",
"destination": "/components/html"
},
{
"source": "/components/alert",
"destination": "/components/callout"
},
{
"source": "/components/big-link",
"destination": "/components/link_button"
},
{
"source": "/components/link-button",
"destination": "/components/link_button"
},
{
"source": "/components/print-format-components",
"destination": "/components/print_group"
},
{
"source": "/components/grid",
"destination": "/components/row"
},
{
"source": "/components/bubble-chart",
"destination": "/components/bubble_chart"
},
{
"source": "/components/mixed-type-charts",
"destination": "/components/combo_chart"
},
{
"source": "/components/funnel-chart",
"destination": "/components/funnel_chart"
},
{
"source": "/components/bar-chart",
"destination": "/components/bar_chart"
},
{
"source": "/components/custom-echarts",
"destination": "/components/custom_echart"
},
{
"source": "/components/box-plot",
"destination": "/components/custom_echart"
},
{
"source": "/components/annotations",
"destination": "/components/reference_line"
},
{
"source": "/components/calendar-heatmap",
"destination": "/components/calendar_heatmap"
},
{
"source": "/components/area-chart",
"destination": "/components/area_chart"
},
{
"source": "/components/line-chart",
"destination": "/components/line_chart"
},
{
"source": "/components/sankey-diagram",
"destination": "/components/sankey_chart"
},
{
"source": "/components/echarts-options",
"destination": "/components/custom_echart"
},
{
"source": "/components/scatter-plot",
"destination": "/components/scatter_chart"
},
{
"source": "/components/custom-components",
"destination": "/core-concepts/custom-components"
},
{
"source": "/components/component-queries",
"destination": "/core-concepts/custom-components"
},
{
"source": "/components/big-value",
"destination": "/components/big_value"
},
{
"source": "/components/data-table",
"destination": "/components/table"
},
{
"source": "/components/dimension-grid",
"destination": "/components/dimension_grid"
},
{
"source": "/components/checkbox",
"destination": "/components/toggle"
},
{
"source": "/components/date-range",
"destination": "/components/range_calendar"
},
{
"source": "/components/text-input",
"destination": "/components/text_input"
},
{
"source": "/components/button-group",
"destination": "/components/button_group"
},
{
"source": "/deployment/github-pages",
"destination": "/self-host"
},
{
"source": "/deployment/aws-amplify",
"destination": "/self-host"
},
{
"source": "/deployment/azure-static-apps",
"destination": "/self-host"
},
{
"source": "/deployment/cloudflare-pages",
"destination": "/self-host"
},
{
"source": "/deployment/firebase",
"destination": "/self-host"
},
{
"source": "/deployment/gitlab-pages",
"destination": "/self-host"
},
{
"source": "/deployment/hugging-face-spaces",
"destination": "/self-host"
},
{
"source": "/deployment/netlify",
"destination": "/self-host"
},
{
"source": "/deployment/vercel",
"destination": "/self-host/vercel"
},
{
"source": "/deployment/rendering-modes",
"destination": "/features/project-settings"
},
{
"source": "/deployment/base-paths",
"destination": "/self-host"
},
{
"source": "/deployment/environments",
"destination": "/features/project-settings"
},
{
"source": "/core-concepts/data-sources",
"destination": "/evidence-warehouse"
},
{
"source": "/data-sources",
"destination": "/evidence-warehouse"
},
{
"source": "/warehouses/evidence-warehouse",
"destination": "/evidence-warehouse"
}
],
"navigation": {
"global": {
"anchors": [
{
"anchor": "Evidence Studio",
"href": "https://evidence.studio",
"icon": "app-window"
},
{
"anchor": "Community",
"href": "https://slack.evidence.dev",
"icon": "slack"
},
{
"anchor": "Legacy Docs",
"href": "https://legacy-docs.evidence.dev",
"icon": "book"
}
]
},
"tabs": [
{
"tab": "Docs",
"groups": [
{
"group": "Get Started",
"pages": [
"index",
"quickstart",
"migration-guide",
"editing",
"publishing"
]
},
{
"group": "Core Concepts",
"pages": [
"core-concepts/markdown",
"core-concepts/components",
"core-concepts/models",
"core-concepts/metrics",
"core-concepts/value-formatting",
"core-concepts/variables",
"core-concepts/partials",
"core-concepts/custom-components"
]
},
{
"group": "Features",
"pages": [
"features/version-control",
"features/project-settings",
"features/page-settings",
"features/themes",
"features/layouts",
"features/sql-files",
"features/page-level-access-control",
"features/row-level-security",
"features/evidence-agent",
"features/translations",
"features/embedded-analytics",
"features/scheduled-reports"
]
},
{
"group": "MCP",
"pages": [
"mcp/overview",
"mcp/studio",
"mcp/docs"
]
},
{
"group": "CLI",
"pages": [
"cli/index",
"cli/connections",
"cli/commands"
]
},
{
"group": "Self Host",
"pages": [
"self-host/index",
"self-host/authentication",
"self-host/vercel",
"self-host/render",
"self-host/fly",
"self-host/railway"
]
},
{
"group": "Direct Connectors",
"pages": [
"direct-connectors/snowflake",
"direct-connectors/fabric",
"direct-connectors/clickhouse",
"direct-connectors/bigquery",
"direct-connectors/databricks",
"direct-connectors/postgres",
"direct-connectors/cube",
"direct-connectors/motherduck"
]
},
{
"group": "Evidence Warehouse",
"pages": [
"evidence-warehouse",
{
"group": "Databases",
"expanded": false,
"icon": "database",
"pages": [
"data-sources/athena",
"data-sources/motherduck",
"data-sources/redshift"
]
},
{
"group": "Object Storage",
"expanded": false,
"icon": "hard-drive",
"pages": [
"data-sources/abs",
"data-sources/backblaze",
"data-sources/custom",
"data-sources/gcs",
"data-sources/r2",
"data-sources/s3"
]
},
{
"group": "Data Lakes",
"expanded": false,
"icon": "layers",
"pages": [
"data-sources/deltalake_s3",
"data-sources/iceberg"
]
},
{
"group": "Flat Files",
"expanded": false,
"icon": "file",
"pages": [
"data-sources/file"
]
}
]
},
{
"group": "Components",
"pages": [
{
"group": "Values",
"expanded": false,
"icon": "shapes",
"pages": [
"components/value",
"components/big_value",
"components/delta",
"components/heat_grid",
"components/progress_bars"
]
},
{
"group": "Tables",
"expanded": false,
"icon": "table-2",
"pages": [
"components/table",
"components/dimension",
"components/measure",
"components/pivot"
]
},
{
"group": "Charts",
"expanded": false,
"icon": "chart-column-increasing",
"pages": [
"components/area_chart",
"components/bar_chart",
"components/bubble_chart",
"components/calendar_heatmap",
"components/candlestick",
"components/chord_chart",
"components/combo_chart",
"components/custom_echart",
"components/funnel_chart",
"components/heatmap",
"components/histogram",
"components/horizontal_bar_chart",
"components/line_chart",
"components/pie_chart",
"components/polar_chart",
"components/radar_chart",
"components/sankey_chart",
"components/scatter_chart",
"components/treemap",
"components/waterfall_chart",
"components/area",
"components/bar",
"components/bubble",
"components/line",
"components/reference_area",
"components/reference_line",
"components/reference_point",
"components/scatter",
"components/sparkline"
]
},
{
"group": "Maps",
"expanded": false,
"icon": "map",
"pages": [
"components/custom_map",
"components/map",
"components/area_layer",
"components/heatmap_layer",
"components/point_layer"
]
},
{
"group": "Inputs",
"expanded": false,
"icon": "text-cursor-input",
"pages": [
"components/button_group",
"components/comparison_selector",
"components/benchmark_comparison",
"components/target_comparison",
"components/date_grain_selector",
"components/dropdown",
"components/filter_bar",
"components/input_tabs",
"components/option",
"components/range_calendar",
"components/slider",
"components/table_filter",
"components/text_input",
"components/toggle",
"components/dimension_grid",
"components/period_selector"
]
},
{
"group": "Custom",
"expanded": false,
"icon": "code-xml",
"pages": [
"components/html"
]
},
{
"group": "UI",
"expanded": false,
"icon": "layout-template",
"pages": [
"components/accordion",
"components/accordion_item",
"components/accordion_title",
"components/audio",
"components/callout",
"components/clock",
"components/commentary",
"components/details",
"components/download",
"components/fence",
"components/file",
"components/hidden_in_print",
"components/icon",
"components/iframe",
"components/image",
"components/info",
"components/line_break",
"components/link",
"components/link_button",
"components/logo",
"components/modal",
"components/note",
"components/only_in_print",
"components/page_break",
"components/partial",
"components/print_group",
"components/row",
"components/stack",
"components/tab",
"components/tabs"
]
},
{
"group": "Logic",
"expanded": false,
"icon": "trending-up-down",
"pages": [
"components/if",
"components/else_if",
"components/else",
"components/repeat"
]
}
]
}
]
},
{
"tab": "Changelog",
"groups": [
{
"group": "Changelog",
"pages": [
"changelog"
]
}
]
}
]
},
"logo": {
"light": "/logo/wordmark-light.png",
"dark": "/logo/wordmark-dark.png"
},
"footer": {
"socials": {
"x": "https://x.com/evidence_dev",
"github": "https://github.com/evidence-dev",
"linkedin": "https://linkedin.com/company/evidence-dev",
"slack": "https://slack.evidence.dev",
"bluesky": "https://bsky.app/profile/evidence.dev"
}
}
}


Editing (`docs/editing.mdx`)


title: 'Editing'

import StudioOnly from '/snippets/studio-only.mdx';

Code Editor

On the left hand side of your screen, you have a code editor. This is where you define your report in markdown.

The code editor is enriched for data development with:

  • Slash commands: Type a / to list components, accept suggestions with tab.
  • Autocompletion: For components and SQL fences, accept suggestions with tab.
  • Syntax highlighting: For markdown, SQL, and components.
  • Validation: Invalid code is underlined in red, hover to see errors, and click "Fix" for AI assistance.

Preview

As you modify the code in the editor, the preview will update in real time, including rerunning SQL queries and rerendering charts when you make changes.

Nothing is published until you click the "Publish" button. See Publishing for details.

Evidence Agent

The right sidebar contains a chat interface with the Evidence Agent.

  • The agent is trained to generate valid Evidence markdown
  • It knows the schema of any data sources you have added

The agent can generate reports, fix errors, and answer general questions about Evidence Studio.

Agent Capabilities

The agent can help you across most of what you do in Studio, including:

  • Read and edit pages: Generate new reports or make targeted edits to existing markdown, SQL, and components.
  • Run SQL queries: Execute SQL against your connected data sources to explore data and validate results before writing it into a report.
  • Inspect your data: Read the schema and metadata of tables, sources, and models, and list available connections to see what data is available.
  • Read existing visualizations: Pull the data behind a chart, table, or value already on the page to reason about and extend it.
  • Update settings: Adjust project and page settings (theme, layout, table of contents, default date range, and more) and edit project config files like theme.yaml and evidence.config.yaml.
  • Diagnose errors: Identify and fix invalid SQL, broken components, and other issues in your reports.
  • Search the docs: Answer questions about Evidence Studio, components, and SQL using the documentation.

The Evidence Agent suggests changes in a "diff view", which you can accept, reject, or refine with another message.


Evidence Warehouse (`docs/evidence-warehouse.mdx`)


title: 'Evidence Warehouse'
sidebarTitle: 'Overview'
keywords:

  • data warehouse
  • managed warehouse
  • data integration
  • cloud warehouse
  • direct connectors
  • data lake
  • etl data integration
  • zero etl

import StudioOnly from '/snippets/studio-only.mdx';

The Evidence Warehouse is Evidence's built-in, fully managed cloud warehouse. You connect a data source once, Evidence extracts the data into the warehouse, and every report queries it from there — fast, with no infrastructure for you to run. You choose which region the data is stored in (see Storage Regions). When you use the managed warehouse, Evidence handles etl data integration for you — extracting, loading, and making data available for reporting on a schedule.

Connectors are how you get data into the Evidence Warehouse. You connect to your data source once, then use that data across all your reports. With this data integration workflow, your reports always query the same extracted data, regardless of which source it came from.

Evidence supports different types of connectors: Databases, Object Storage, Data Lakes, Flat Files, and Applications.

If you'd rather have Evidence query a warehouse you own directly — without extracting data into the Evidence Warehouse — use a native connector instead.


Databases

Database connectors connect to your existing data warehouse or database. Evidence extracts the data, and you can define a schedule for sync.

How it works:

  1. You provide connection credentials to your database
  2. Evidence runs queries against your database to extract data
  3. Data is cached in Evidence's query engine in your chosen region
  4. Reports query the cached data for fast performance

You choose where your extracted data is stored. See available regions.

Best for:

  • Existing data warehouses (Snowflake, BigQuery, Redshift, etc.)
  • Data that's already modeled and ready to report on
  • Teams who want Evidence to manage the data pipeline

Supported databases:

We are continuously adding support for new databases. Request one here.


Direct Connectors

Prefer to keep your data in your own warehouse? Native connectors are the alternative to the Evidence Warehouse: instead of extracting data, Evidence runs queries live against a warehouse you own. Each request from a viewer issues queries against your warehouse and returns the rows directly. This is a zero etl approach — since the warehouse is queried directly, there's no extraction, loading, or sync pipeline to maintain.

How it works:

  1. You provide credentials with read access to your warehouse
  2. Evidence issues queries directly to your warehouse when viewers load reports

Key characteristics:

  • Always live: viewers see the current state of your warehouse on every load — no sync schedule.
  • Data stays in your warehouse: Evidence holds credentials but doesn't store data.

Best for:

  • Use cases where data freshness is important
  • Strict data residency requirements
  • Teams that already maintain RLS policies in their warehouse and want Evidence to honour them

Native connectors live in the Warehouses section:


Object Storage

Object storage connectors read Parquet files directly from cloud storage buckets that you control. Evidence queries the data in place using ClickHouse's S3 table engine. In addition to the below named providers, any S3 compatible storage is supported (via the "custom S3" connector).

How it works:

  1. You store Parquet files in your own bucket (S3, GCS, Azure, etc.)
  2. You provide bucket credentials to Evidence
  3. Evidence queries the Parquet files directly — no data is copied

Key characteristics:

  • Instant data availability: When you update a Parquet file in your bucket, the new data is immediately available in Evidence—no sync or publish required
  • Schema changes require publish: Adding or removing columns requires clicking Publish or setting up a refresh schedule
  • Data stays in your infrastructure: Your data never leaves your bucket, Evidence queries it in place
  • S3-compatible: Any storage provider with an S3-compatible API works (AWS S3, GCS, Azure Blob, Cloudflare R2, MinIO, Backblaze B2, etc.)

Best for:

  • Data residency or sovereignty requirements
  • Teams who manage their own data pipelines and produce Parquet files
  • High-frequency data updates where you control the source files
  • Keeping data within your own infrastructure

Supported providers:


Data Lakes

Data lake connectors connect to open table formats that provide ACID transactions, schema evolution, and time travel capabilities on top of object storage.

How it works:

  1. You provide credentials to your data lake catalog or storage
  2. Evidence reads the table metadata and data files
  3. Data is queried with full support for the table format's features

Best for:

  • Teams using modern lakehouse architectures
  • Large-scale data with complex partitioning
  • Scenarios requiring time travel or schema evolution

Supported data lakes:


Applications

Application connectors sync data from SaaS applications and APIs. Evidence uses Fivetran to extract and normalize data from these sources.

How it works:

  1. You authenticate with the application (OAuth or API key)
  2. Evidence syncs data on a configurable schedule
  3. Data is normalized and stored in Evidence's query engine

Best for:

  • Product analytics and operational reporting
  • Combining SaaS data with your data warehouse
  • Teams who want turnkey integrations without building pipelines

Supported applications:

We are continuously adding support for new applications. Request one here.


Flat Files

Upload flat files directly to Evidence for quick data analysis without setting up external connections.

How it works:

  1. Upload a file directly through the Evidence interface
  2. Evidence processes and stores the data
  3. Query the data immediately in your reports

Supported formats:

  • CSV
  • Parquet
  • JSONL
  • Excel

Best for:

  • Quick prototyping and ad-hoc analysis
  • Small datasets that don't require a database
  • Getting started with Evidence before connecting external sources

See Flat Files for details.


Comparison

Databases Object Storage Data Lakes Flat Files Applications
Data location Data is extracted Stays in your bucket Stays in your storage Uploaded to Evidence Data is extracted
Data updates Scheduled sync Instant (for row changes) Scheduled sync Re-upload file Scheduled sync
Schema changes Requires re-publish Requires re-publish Requires re-publish Re-upload file Requires re-publish
Data residency Choose Evidence region Your bucket location Your storage location Choose Evidence region Choose Evidence region

Storage Regions

Evidence supports the following storage regions for extracted data.

Region Location
us-central1 Iowa, USA
us-east1 South Carolina, USA
us-east4 Virginia, USA
us-east5 Ohio, USA
us-west1 Oregon, USA
us-west2 Los Angeles, USA
us-west3 Salt Lake City, USA
us-west4 Las Vegas, USA
northamerica-northeast1 Montreal, Canada
northamerica-northeast2 Toronto, Canada
europe-west2 London, UK
europe-west3 Frankfurt, Germany
europe-west4 Eemshaven, Netherlands
europe-west6 Zurich, Switzerland
europe-west8 Milan, Italy
europe-west9 Paris, France
europe-west10 Berlin, Germany
asia-south1 Mumbai, India
asia-southeast1 Singapore
asia-northeast1 Tokyo, Japan
australia-southeast1 Sydney, Australia

Create a connection

(For databases only)

  1. On the sources page, click New Connection
  2. Enter the connection details for your database. Note that you require one connection per schema at this time.
  3. Click Test to verify the connection is configured correctly.
  4. Click Save.

IP Whitelisting

If your database requires IP whitelisting, add the Evidence Studio IP addresses:

text
3.21.143.81
3.209.193.182
3.215.195.233
18.189.109.43
34.56.211.45
35.192.240.48
35.192.240.49
35.192.240.50
35.192.240.51
35.192.240.52
35.192.240.53
35.192.240.54
35.192.240.55
35.234.176.144
35.234.176.145
35.234.176.146
35.234.176.147
35.234.176.148
35.234.176.149
35.234.176.150
35.234.176.151
104.197.50.84
*.us-east4.gcp.proxy.prod.fivetran.com
*.us-central1.gcp.proxy.prod.fivetran.com

Import a data source

  1. On the sources page, click New Source.
  2. Select the connection you just created.
  3. Choose from the tables in the connection.
  4. (Optional) Rename the source - this is used to reference the source in your reports.
  5. Click Save.

Import a file

  1. On the sources page, click Upload File.
    • You can upload CSV, Parquet, and JSONL files.
  2. Your file will be automatically imported, and named using a snake_case version of the filename.

Updating data

You can only update uploaded files by reuploading them.

Manual refresh

  1. On the sources page, click the ... menu on the right of the source and select Publish.

Scheduled refresh

  1. In the sources page, click the ... menu on the right of the source and select Schedule.
  2. Choose a refresh interval.
    • Current refresh intervals are: 5 mins, 15 mins, 1 hour, 1 day, 1 week. Contact Evidence for custom intervals.
  3. Click Save.

Migration Guide (`docs/migration-guide.mdx`)


title: Migration Guide

Legacy Evidence is a static website generator: Markdown and DuckDB SQL which queries data you package up in a build step. Evidence Studio has a live connection to a database, and an updated set of components that can generate SQL.

How to migrate

The CLI has a evidence migrate command. It converts everything it can mechanically — component syntax, attribute names, input references, connections, source SQL - and prints a warning for items it cannot migrate.

The fastest path is to let a coding agent support your migration.

  1. Install the Evidence CLI (version ≥ 0.9.0)
  2. Add the migration skill to your project: Save the file below into your legacy project as .claude/skills/evidence-migrate/SKILL.md, or the equivalent path for your assistant.
  3. Ask your assistant to migrate the project: "Migrate this Evidence project to Studio syntax." The skill tells it which commands to run and how to work through the warnings.

To run it yourself: evidence migrate --dry-run to preview, evidence migrate to convert in place, then evidence validate for syntax and SQL errors and evidence dev to inspect the result.

The migration skill

text
/* Detailed source-code truncated for AI context efficiency. */

What works differently

Legacy Evidence Evidence Studio
Component syntax Svelte: <LineChart data={orders} x=date y=sales /> Markdoc: {% line_chart data="orders" x="date" y="sum(sales)" /%}
Component data Renders a query you wrote Writes its own SQL — aggregations, date_grain, comparisons, filters, where
SQL DuckDB, in-browser (WASM) Server-side: ClickHouse, or your warehouse's dialect via a direct connector
Data prep sources/*.sql queries run at build Sync data to Evidence on a schedule, or update your data warehouse
SQL files queries/*.sql, interpolated with ${inputs.x.value} /queries/*.sql inlined verbatim — {{ }} variables do not resolve; move input-driven SQL into a SQL block on the page
Variables ${inputs.category.value} {{category}}, or filters=["category"] — see Variables
Logic Svelte/JS in pages: {#each}, {#if}, {@const} {% repeat %}, {% if %}
Builds Build required for every data or content change No build, Queries re-run on page load
Deployment Configure hosting and a build pipeline Publish in seconds, from Evidence Studio or linked GitHub repo
Scale ~2M rows Hundreds of millions of rows
Access control Build it yourself SSO, page permissions, row-level access rules, user groups
Self-service Reports Reports + Insights + AI Chat

Not supported

Legacy feature Instead
Templated pages ([param].md) One page driven by an input — a dropdown wired to every component via filters
Source SQL queries (sources/) Sync the table, or a view in your database, then use Models
Svelte files and custom Svelte components Custom components, or {% custom_echart %} / {% html %}
JS expressions and Svelte blocks in pages {% repeat %}, {% if %}, or compute it in SQL
Box plots, Venn diagrams No equivalent
Drill-through links on maps No equivalent — maps support tooltips only
Secondary y-axis (y2=) Rebuild as {% combo_chart %} with axis="y2" on the secondary series
<ECharts> config objects Move the config into the {% custom_echart %} body
Horizontal 100% stacked bars Regular stacked {% horizontal_bar_chart %}

Individual attributes without an equivalent are dropped with a warning by evidence migrate; run it with --dry-run to see the full list for your project.

Getting help

Ask in the Slack community, or book a migration call.


Publishing (`docs/publishing.mdx`)


title: 'Publishing'

Evidence Studio

How to publish

There are three ways to publish:

  • From the editor. Open the Publish menu in the top right of the editor and click Publish. The menu shows pending changes, any open pull request, and the current publish state.
  • From local dev. Push to the project's published branch using git or the Evidence CLI. The push triggers a publish automatically.
  • From GitHub. Merge a pull request into the published branch on GitHub.

You can use any combination of these — Studio, your local environment, and GitHub stay in sync through the project's repo.

Pull requests

When you open a pull request against the published branch, Evidence runs checks and posts a preview:

  • Markdown validation check: Catches invalid syntax and broken components before merge.
  • access.yaml validation check: Validates page level access rules so a bad config can't take down viewer access.
  • Preview link: A comment on the PR linking to a deployed preview of the branch, so reviewers can see the report before merging.

The checks appear as status checks on the PR — you can configure branch protection in GitHub to block merges until they pass.

Publish history and rollback

Every project has a publish history page that lists every publish attempt (publishes, CLI/local pushes, and PR merges), with who triggered it, the commit, the result, and a detail view for failures.

From the history page you can:

  • Roll back to any previous successful publish.
  • Retry a failed publish.

Reliable publishes

  • Failed publishes never affect viewers. If a publish fails, the previous successful version stays live. Viewers don't see broken reports while you fix the issue.
  • Email alerts on failure. Org admins get an email when a publish fails.
  • Project banner on failure. When the latest publish failed, every project page in Studio shows a banner linking to the failure in history.

Connecting GitHub

By default, every project is backed by an Evidence-managed git repo — you don't need to do anything to get the publish flow above. If you want the repo to live in your own GitHub organization so you can edit it locally, review changes through your existing PR process, or hook it into your own CI, connect the Evidence GitHub App:

  1. Install the Evidence GitHub App. From Organization Settings, connect Evidence to your GitHub account or organization. You can grant access to all repos or just the ones you choose, and update that selection later.
  2. Link a repo to a project. Open the project, then Project Settings → Version Control, and select Connect to GitHub repository. Pick the repo, the branch to use as the published branch, and the project root path.
  3. First publish. Click Publish in the editor to push the current state to GitHub. From then on, all three publish flows (editor, local dev, GitHub PR merge) work against your repo.

See Version Control for branching strategies and the list of files that are version controlled.

GitHub Enterprise Cloud

Enterprise organizations can connect a GitHub Enterprise Cloud account hosted on a dedicated *.ghe.com domain:

  1. In Organization Settings, select Connect GitHub Enterprise.
  2. Enter the enterprise hostname (for example, arkaan.ghe.com) and the GitHub organization that owns your repositories.
  3. Continue to GitHub to create and install the private, organization-owned Evidence Studio GitHub App.
  4. Return to a project's Version Control settings and select one of the repositories available to the App.

Evidence supports GitHub Enterprise Cloud with data residency on *.ghe.com. Self-hosted GitHub Enterprise Server domains are not supported. An Evidence organization can connect to either GitHub.com or one GHE.com host at a time. Disconnect all projects from the current host before replacing the organization connection.

Sharing access

Once a report is published, control who can view it with access.yaml. See Page Level Access Control for the full schema and patterns for sharing with teammates, groups, and external customers.

Roles are managed from the Team Settings page:

  • Viewer: Can view published reports they've been granted access to.
  • Org Viewer: Can view all published reports in the org.
  • Developer: Can edit reports and configure data sources.
  • Admin: Developer permissions plus organization settings.

Self Host

Alternatively, run your project as a self-hosted site — no Evidence Studio account required. See Self Host for the Docker image, project setup, and platform guides for Vercel, Render, Fly.io, and Railway, plus a feature comparison with Evidence Studio.


Cli Commands (`docs/cli/commands.mdx`)


title: 'Commands'

Development

`evidence init`

Scaffold a new Evidence project.

bash
evidence init my-project
evidence init my-project --warehouse snowflake
Option Description
--warehouse Scaffold a connection.yaml for a direct warehouse connection: snowflake or bigquery. See Connecting a Warehouse.

Without --warehouse, the project uses the managed Evidence Warehouse. With it, the CLI writes a connection.yaml (gitignored) so queries run directly against your own warehouse.

`evidence dev`

Start the local development server.

bash
evidence dev
evidence dev --port 8080
Option Description
--port, -p Port to run on (default: 3000)

Deploy

`evidence launch`

Connect this project to Evidence Studio and GitHub, then deploy by pushing to your repo. Interactive by default — it walks you through installing the GitHub App and creating (or linking) the Studio project.

bash
evidence launch
evidence launch --name "My Project" --upload-credentials
Option Description
--name Name for the Studio project to create.
--branch Branch to publish from (default: auto-detected).
--root-directory Project root within the repo (default: auto-detected).
--upload-credentials Upload warehouse credentials from connection.yaml to your org. Prompted for interactively; required to opt in when running non-interactively.

evidence launch recognizes GitHub.com and GitHub Enterprise Cloud (*.ghe.com) remotes over HTTPS and SSH. If the detected GHE.com host is not connected yet, the CLI opens Organization Settings to guide an Evidence admin through creating and installing the private Enterprise GitHub App. GHE.com connections require Evidence Studio on the Enterprise plan.

Attach this repo to an existing Studio project. The project's content becomes git-managed — the next git push overwrites it with the repo's contents.

bash
evidence link my-project
evidence link --project my-project
Option Description
--project Studio project to attach, by slug or id. Also accepted as a positional argument.
--branch Branch to publish from (default: auto-detected).
--root-directory Project root within the repo (default: auto-detected).

The repository host must match the GitHub host connected to the Evidence organization.

Disconnect this repo from its Studio project. The org's GitHub App install and the project itself are left intact.

bash
evidence unlink
evidence unlink --project my-project
Option Description
--project Studio project to unlink, by slug or id. Inferred from the repo's binding when omitted. Also accepted as a positional argument.

Data

`evidence query`

Run a SQL query against connected data sources.

bash
evidence query "SELECT * FROM orders LIMIT 10"
evidence query --file query.sql
cat query.sql | evidence query -
Option Description
--format Output format: json (default), jsonl, table, csv
--limit, -l Limit number of rows
--quiet, -q Suppress status messages
--columns Output only column names and types
--file Read SQL from a file
--output, -o Write results to a file

`evidence tables`

List available data tables.

bash
evidence tables

`evidence describe`

Show schema for a table.

bash
evidence describe demo_daily_orders

`evidence schema`

Show all tables with their columns.

bash
evidence schema

`evidence connectors`

List all connectors with health status.

bash
evidence connectors
evidence connectors --json

Shows connector name, type, status, last sync, schedule, table count, and reference count for all connector types.

`evidence models`

List all models with refresh status.

bash
evidence models
evidence models --json

Shows model name, status, last refresh time, and schedule.

`evidence lineage`

Show where connections and tables are used across projects, pages, models, and queries.

bash
evidence lineage
evidence lineage table orders
evidence lineage --branch dev/alex
evidence lineage --json
Option Description
table <name> Show where a specific table is referenced
--branch Query a specific branch (default: main)
--json Output JSON for tooling

Project

`evidence validate`

Validate all markdown files in the current project.

bash
evidence validate
evidence validate --json

`evidence docs`

Browse and search component documentation.

bash
evidence docs                         # Overview
evidence docs search "chart"          # Search docs
evidence docs component bar_chart     # Component details

Authentication

`evidence signup`

Create an account and workspace. Opens Evidence in your browser; once done, run evidence login to connect the CLI.

bash
evidence signup

`evidence login`

Authenticate with Evidence Studio using your browser.

bash
evidence login

`evidence logout`

Clear stored credentials.

bash
evidence logout

`evidence whoami`

Show the currently authenticated user.

bash
evidence whoami

`evidence orgs`

List available organizations.

bash
evidence orgs

`evidence switch`

Switch to a different organization.

bash
evidence switch "My Organization"

`evidence token`

Generate a token for headless/CI use. Prints an EVIDENCE_AUTH_TOKEN value you can set as an environment variable to authenticate without an interactive login. Requires an active login and a selected organization.

bash
evidence token

The generated token contains a long-lived access token. Treat it as a secret.

Utility

`evidence version`

Print the current CLI version.

bash
evidence version

`evidence upgrade`

Upgrade to the latest CLI version.

bash
evidence upgrade

`evidence help`

Show help and available commands.

bash
evidence help

`evidence telemetry`

Show or change anonymous usage reporting. See Telemetry for what is sent.

bash
evidence telemetry            # same as status
evidence telemetry status
evidence telemetry disable
evidence telemetry enable

Self-hosting

`evidence serve`

Serve the project as a self-hosted site. Runs the built-in production server — no Evidence Studio account or session required.

bash
evidence serve
evidence serve --port 8080
evidence serve --host 0.0.0.0
Option Description
--port, -p Port to run on (default: 3000)
--host Bind address (default: 127.0.0.1)
--open Open the browser after starting (default: off)

Requires a direct connector configured in connection.yaml — the managed query engine is not supported for self-hosting.

To serve beyond localhost, set EVIDENCE_BASIC_USER and EVIDENCE_BASIC_PASSWORD to protect the site with HTTP Basic Auth. The server refuses to start on a non-localhost --host without these set.

On a trusted private network (VPN, Tailscale, internal VPC), EVIDENCE_AUTH_DISABLED=true skips authentication entirely.


Cli Connections (`docs/cli/connections.mdx`)


title: 'Connect your CLI to your data' sidebarTitle: 'Connections'

How the CLI gets data depends on how your project is set up.

Evidence Warehouse

If you use the Evidence Warehouse, run evidence login. No further setup is needed.

Other warehouses

If you use a direct connection to a warehouse you own, add a connection.yaml file to the root of your project. When this file is present, the CLI queries your warehouse directly from your machine — no login required.

Scaffold with `evidence init`

The quickest way to create a connection.yaml is to pass --warehouse to evidence init:

bash
evidence init my-project --warehouse snowflake
# or
evidence init my-project --warehouse bigquery

This writes a connection.yaml in the project root pre-filled with placeholder values, and adds it to .gitignore (the file holds credentials — keep it out of version control).

`connection.yaml` and any files it references — the Snowflake private-key `.pem` or the BigQuery service-account JSON — contain credentials. Never commit them. `evidence init --warehouse` gitignores `connection.yaml` for you, but **not** the referenced key files: add those to `.gitignore` yourself, or use the inline `private_key` / `keyfile_json` fields so there's no separate file to leak.

Fill in the placeholders with your own connection details. If --warehouse is omitted, no connection.yaml is written and the project uses the Evidence Warehouse.

Configuration

```yaml type: snowflake account: xy12345.us-east-1 user: evidence_user private_key_path: ./snowflake-key.pem warehouse: COMPUTE_WH database: ANALYTICS # role: EVIDENCE_READER # schema: { production: ANALYTICS, devSchemas: [DEV_ALICE] } ```
text
Provide exactly one of `password`, `private_key`, or `private_key_path`. Paths (`private_key_path`) are resolved relative to `connection.yaml`.

See the [Snowflake direct connector](/direct-connectors/snowflake) for the full field reference and how to create a read-only Snowflake user.
```yaml type: bigquery project: my-gcp-project keyfile: ./evidence-bq-primary.json datasets: - analytics - reporting # dataset: analytics # location: US ```
text
Provide exactly one of `keyfile` or `keyfile_json`. The `keyfile` path is resolved relative to `connection.yaml`.

See the [BigQuery direct connector](/direct-connectors/bigquery) for the full field reference and the service-account setup steps.

Components Accordion (`docs/components/accordion.mdx`)


title: Accordion keywords: ["collapsible","expandable","disclosure"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% accordion %}
  ...
{% /accordion %}

Attributes

Whether only one item can be open at a time Visual style variant of the accordion

Allowed values:

  • default
  • well
  • card
Set the width of this component (in percent) relative to the page width

Allowed Children


Components Accordion Item (`docs/components/accordion_item.mdx`)


title: Accordion Item

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% accordion %}
    {% accordion_item title="Section 1" open=true %}
        Content for section 1.
    {% /accordion_item %}
    {% accordion_item title="Section 2" %}
        Content for section 2.
    {% /accordion_item %}
    {% accordion_item title="Section 3" icon="settings" %}
        Content for section 3 with an icon.
    {% /accordion_item %}
{% /accordion %}

Examples

Accordion with Items

liquid
{% accordion %}
    {% accordion_item title="Section 1" open=true %}
        Content for section 1.
    {% /accordion_item %}
    {% accordion_item title="Section 2" %}
        Content for section 2.
    {% /accordion_item %}
    {% accordion_item title="Section 3" icon="settings" %}
        Content for section 3 with an icon.
    {% /accordion_item %}
{% /accordion %}

Attributes

Title displayed in the accordion item header. For rich titles (e.g. containing another component), nest an `accordion_title` tag instead. When both are provided, the nested `accordion_title` takes precedence and this attribute is ignored. Icon to display in the accordion item header

Allowed values:

  • trending-up
  • trending-down
  • clock
  • calendar
  • check
  • x
  • info
  • alert-circle
  • help-circle
  • eye
  • eye-off
  • user
  • users
  • settings
  • cog
  • plus
  • minus
  • up
  • down
  • right
  • left
  • star
  • heart
  • search
  • file
  • file-text
  • home
  • mail
  • filter
  • share
  • bell
  • trash
  • credit-card
  • globe
  • key
  • croissant
  • map
  • rotate
  • rewind
  • bank
  • receipt
  • activity
  • chart-column
  • chart-pie
  • chart-no-axes-combined
  • goal
  • rocket
  • trophy
  • apple
  • cookie
  • donut
  • beef
  • cake
  • soup
  • utensils
  • milk
  • nut
  • pyramid
  • triangle
  • arrow-down
  • arrow-left
  • arrow-right
  • arrow-up
  • chevron-down
  • chevron-left
  • chevron-right
  • chevron-up
  • chevrons-down
  • chevrons-left
  • chevrons-right
  • chevrons-up
  • menu
  • external-link
  • check-circle
  • x-circle
  • edit
  • trash-2
  • copy
  • save
  • download
  • upload
  • send
  • refresh
  • redo
  • undo
  • folder
  • folder-open
  • image
  • file-image
  • user-plus
  • user-minus
  • user-check
  • lock
  • unlock
  • log-in
  • log-out
  • message-square
  • message-circle
  • phone
  • phone-call
  • bell-off
  • video
  • video-off
  • play
  • pause
  • stop
  • skip-back
  • skip-forward
  • volume
  • volume-1
  • volume-2
  • volume-off
  • volume-x
  • bookmark
  • tag
  • link
  • unlink
  • share-2
  • alert-triangle
  • loader
  • more-vertical
  • more-horizontal
  • grid
  • list
  • maximize
  • minimize
  • zoom-in
  • zoom-out
  • thumbs-up
  • thumbs-down
  • shopping-cart
  • dollar-sign
  • camera
  • printer
  • monitor
  • smartphone
  • laptop
  • calculator
  • cloud-sun-rain
  • sun-snow
  • thermometer-sun
  • thermometer-snowflake
  • cloudy
  • cloud-rain-wind
  • cloud-rain
  • wind
  • sun
  • cloud-snow
  • thermometer
  • cloud-drizzle
  • cloud-sun
  • cloud
  • cloud-lightning
  • snowflake
  • flame
  • atom
  • fuel
  • magnet
  • factory
  • tree-deciduous
  • waypoints
  • plug
  • dam
  • battery
Whether the accordion item is initially open

Allowed Parents


Components Accordion Title (`docs/components/accordion_title.mdx`)


title: Accordion Title

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

Examples

Accordion item with a big_value in the title

liquid
{% accordion %}
    {% accordion_item %}
        {% accordion_title padding_top=8 padding_bottom=8 %}
            {% big_value data="orders" value="sum(sales)" fmt="usd" /%}
        {% /accordion_title %}
        Body content for this section.
    {% /accordion_item %}
{% /accordion %}

Attributes

Top padding of the accordion trigger, in pixels. Lower this when the slotted content already provides its own top padding. Bottom padding of the accordion trigger, in pixels. Lower this when the slotted content already provides its own bottom padding.

Allowed Parents


Components Area (`docs/components/area.mdx`)


title: Area

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" /%}
{% /combo_chart %}

Examples

Basic Area Series

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" /%}
{% /combo_chart %}

Unstacked Areas

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" series="category" stacked=false /%}
{% /combo_chart %}

Area with Gradient Fill

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" stacked=false options={
        gradient=true
    } /%}
{% /combo_chart %}

Attributes

Column name for y-axis. Aggregated at the parent combo_chart's `x=`. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Column name for series grouping The axis to render the series on

Allowed values:

  • y1
  • y2
Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Label each point in the series with its value

Example:

text
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}

Attributes:

  • position: string - Position the label relative to its data point
    • Allowed values:
      • above
      • below
      • left
      • right
      • middle
  • fmt: string - Format the label value. Defaults to series or axis fmt.
  • size: number - Font size in px
  • distance: number - How far the label is from the data point
  • rotate: number - Rotate each label (degrees)
  • color: string - Change the text color of the labels
  • border_color: string - Change the border color surrounding text labels, defaults to chart background
  • show_overlap: boolean - Show labels for every point even when they overlap

Example:

text
options={
  step = "start"
  smooth = true
  gradient = true
}

Attributes:

  • step: string - Show a stepped line rather than a smooth line between points and control where the step happens (start, middle, or end)
    • Allowed values:
      • start
      • middle
      • end
  • smooth: boolean
  • gradient: boolean - Apply a color-to-transparent gradient fill to the area, fading from the series color at the top to transparent at the bottom
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into this series only. For overrides that apply to every series on the chart, set `echarts_series_options` on the parent chart instead.

Example:

text
echarts_options={
    endLabel={ show=true }
    markPoint={ data=[{ type="max" }, { type="min" }] }
}
Whether to stack areas with the same series value. Set to "100%" for percentage stacking. Stack identifier - areas with the same stack_id value will be stacked together. Overrides the stacked prop.

Allowed Parents


Components Area Chart (`docs/components/area_chart.mdx`)


title: Area Chart keywords: ["area graph","area plot","stacked area"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% area_chart
	data="demo.daily_orders"
	x="date"
	y="sum(total_sales)"
	date_grain="month"
/%}

Examples

Basic Usage

liquid
{% area_chart
	data="demo.daily_orders"
	x="date"
	y="sum(total_sales)"
	date_grain="month"
/%}

Area Chart with Series

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    series="category"
    date_grain="month"
/%}

Area Chart with Formatting

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    title="Sales Over Time"
    subtitle="Monthly sales performance"
    date_grain="month"
/%}

100% Stacked Area Chart

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    series="category"
    stacked="100%"
    date_grain="month"
    title="Sales Distribution by Category"
/%}

Revenue by Day of Week

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of week"
    title="Revenue by Day of Week"
    subtitle="Weekday vs weekend sales patterns"
/%}

Seasonality Analysis (Month of Year)

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month of year"
    title="Seasonality Analysis"
    subtitle="Sales patterns across months"
/%}
liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="quarter of year"
    title="Quarterly Performance"
    subtitle="Q1 through Q4 comparison"
/%}

Monthly Billing Cycle Patterns

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of month"
    title="Daily Revenue by Day of Month"
    subtitle="Identify billing cycle patterns"
/%}

Week Number Analysis

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="week of year"
    title="Revenue by Week of Year"
    subtitle="Weekly performance across the year"
/%}

Day of Year Analysis

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of year"
    title="Revenue by Day of Year"
    subtitle="Identify patterns across 365 days"
/%}

Area Chart with Gradient Fill

liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month"
    stacked=false
    area_options={
        gradient=true
    }
/%}

Attributes

Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

Allowed values:

  • connect
  • gaps
  • zero
Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column. Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Column name for series grouping (applies to all series) Column name for individual point labels displayed at the top of the tooltip Title to display above the component Subtitle to display below the title Information tooltip text (can only be used with title). Displays an info icon next to the title. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

Allowed values:

  • asc
  • desc
  • data
Configure the y-axis

Example:

text
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the secondary y-axis

Example:

text
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the x-axis

Example:

text
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}

Attributes:

  • title: string
  • show_title: boolean - When true, renders the auto-derived axis title (the x column name) below the chart. Ignored when title is set explicitly. Defaults to false — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
  • label_wrap: boolean
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
  • min_interval: string - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • max_interval: string - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
  • label_rotate: number - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
  • title_arrow: boolean - Show/hide the arrow (→) on the axis title
  • max_label_length: number - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.
Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead. Position of the legend (top or bottom)

Allowed values:

  • top
  • bottom
Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones. Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

Example:

text
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}

Attributes:

  • color_palette: array of strings - Array of hex color codes to use for series colors
  • series_colors: map of key-value pairs - Map of series names to hex color codes for custom series coloring
  • zoom: boolean - Enables zoom by dragging on the chart area
  • top_padding: number - Additional padding (in px) above the chart area to prevent labels from being cut off
Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

Example:

text
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
Column name for y-axis Semantic metric name(s) to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Pass an array for multiple series (e.g. `metric=["revenue", "orders"]`). Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Label each point in the series with its value

Example:

text
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}

Attributes:

  • position: string - Position the label relative to its data point
    • Allowed values:
      • above
      • below
      • left
      • right
      • middle
  • fmt: string - Format the label value. Defaults to series or axis fmt.
  • size: number - Font size in px
  • distance: number - How far the label is from the data point
  • rotate: number - Rotate each label (degrees)
  • color: string - Change the text color of the labels
  • border_color: string - Change the border color surrounding text labels, defaults to chart background
  • show_overlap: boolean - Show labels for every point even when they overlap

Example:

text
options={
  step = "start"
  smooth = true
  gradient = true
}

Attributes:

  • step: string - Show a stepped line rather than a smooth line between points and control where the step happens (start, middle, or end)
    • Allowed values:
      • start
      • middle
      • end
  • smooth: boolean
  • gradient: boolean - Apply a color-to-transparent gradient fill to the area, fading from the series color at the top to transparent at the bottom
Whether to stack the areas. Set to "100%" for percentage stacking where each area shows its proportion of the total. Column name for secondary y-axis

Example:

text
area_options={
  step = "start"
  smooth = true
  gradient = true
}

Attributes:

  • step: string - Show a stepped line rather than a smooth line between points and control where the step happens (start, middle, or end)
    • Allowed values:
      • start
      • middle
      • end
  • smooth: boolean
  • gradient: boolean - Apply a color-to-transparent gradient fill to the area, fading from the series color at the top to transparent at the bottom

Allowed Children


Components Area Layer (`docs/components/area_layer.mdx`)


title: Area Layer

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="name"
        data="state_sales"
        area_id="state"
        value="sum(sales)"
    /%}
{% /map %}

Examples

US States by Name

liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="name"
        data="state_sales"
        area_id="state"
        value="sum(sales)"
    /%}
{% /map %}

US States by Abbreviation

liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="abbr"
        data="state_sales"
        area_id="state_abbr"
        value="sum(sales)"
    /%}
{% /map %}

US Counties by State + County

liquid
{% map %}
    {% area_layer
        geography="us_counties"
        match_by="state-county"
        data="county_sales"
        area_id="state || '-' || county"
        value="sum(sales)"
    /%}
{% /map %}

US Counties by FIPS

liquid
{% map %}
    {% area_layer
        geography="us_counties"
        match_by="fips"
        data="county_sales"
        area_id="state_fips || county_fips"
        value="sum(sales)"
    /%}
{% /map %}

Custom GeoJSON

liquid
{% area_layer
    geojson_url="https://example.com/custom.geojson"
    geojson_id="id"
    data="my_data"
    area_id="region_id"
    value="sum(sales)"
/%}

Diverging Scale Centered at 0

liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="abbr"
        data="state_growth"
        area_id="state_abbr"
        value="growth_pct"
        color_scale=["#d73027", "#ffffbf", "#1a9850"]
        min=-100
        max=100
        midpoint=0
    /%}
{% /map %}

Custom Breakpoints

liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="abbr"
        data="state_sales"
        area_id="state_abbr"
        value="sum(sales)"
        color_stops=[
            { value=0 color="#ffffff" },
            { value=10000 color="#f59e0b" },
            { value=50000 color="#1a9850" }
        ]
    /%}
{% /map %}

Attributes

Name of the table to query Array of filter IDs to apply Pre-provided geography (use this OR geojson_url + geojson_id)

Allowed values:

  • us_states
  • us_counties
How to match areas. For us_states: "name", "abbr", or "fips". For us_counties: "state-county" or "fips". URL to custom GeoJSON file (use with geojson_id for custom maps) GeoJSON property to join on. Use a string for single property (e.g., "NAME") or array for composite key (e.g., ["STATE", "COUNTY"]). Column name in data that matches geo_id (e.g., "state_id") Column or expression for coloring the choropleth (e.g., "sum(sales)") Array of colors for the choropleth gradient. A single-color array auto-expands to [background, color]. Deprecated. Use `color_scale`. Lower bound for the color scale. Values below this clamp to the first color in the scale. Defaults to the minimum value in the data. Upper bound for the color scale. Values above this clamp to the last color in the scale. Defaults to the maximum value in the data. Anchor a specific value (typically 0) at the middle of a diverging color scale. Requires a color_scale with 3 or more colors. Pin specific data values to specific colors, interpolating between them. Provide an array of value and color pairs. Values beyond the first and last breakpoint are clamped to the end colors. Takes precedence over color_scale, min, max, and midpoint. Whether to show areas that do not have matching data Show tooltips on hover Array of SQL expressions for additional fields to show in tooltip (e.g., ["category", "emissions"]) GeoJSON property to use for area name in tooltip (defaults to "NAME") Format for values in tooltip. See [Value Formatting](/core-concepts/value-formatting) for available formats. Zoom range [min, max] where this layer is visible (e.g., [0, 8] shows layer from zoom 0 to 8) Show legend for this layer Custom label for the legend (defaults to table name) Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results

Allowed Parents


Components Audio (`docs/components/audio.mdx`)


title: Audio keywords: ["sound","music","podcast","mp3","wav","media","player"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% audio url="https://files.example.com/podcast/episode-01.mp3" /%}

Examples

Basic Audio Player

liquid
{% audio url="https://files.example.com/podcast/episode-01.mp3" /%}

WAV File with Title

liquid
{% audio url="https://files.example.com/recordings/call.wav" type="wav" title="Call Recording" /%}

Attributes

URL of the audio file (may include query parameters such as SAS tokens) MIME subtype of the audio file (e.g. mpeg, wav, ogg, mp4). Mapped to audio/[type] for the browser. Accessible label for the audio player

Components Bar (`docs/components/bar.mdx`)


title: Bar

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" /%}
{% /combo_chart %}

Examples

Basic Bar Series

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" /%}
{% /combo_chart %}

Unstacked Bars

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" series="category" stacked=false /%}
{% /combo_chart %}

Multiple Stacks

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" stack_id="sales" /%}
    {% bar y="sum(total_sales)+1000000" stack_id="sales" /%}
    {% bar y="sum(quantity)" stack_id="quantity" /%}
{% /combo_chart %}

Extra tooltip fields

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar
        y="sum(total_sales)"
        fmt="usd"
        tooltip_fields=[
            { value="count(distinct order_id)" label="Orders" },
            { value="sum(total_sales) - lag(sum(total_sales)) over (order by date_trunc('month', date))" label="MoM Δ" fmt="usd" color_by_sign=true }
        ]
    /%}
{% /combo_chart %}

Attributes

Column name for y-axis. Aggregated at the parent combo_chart's `x=`. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Column name for series grouping The axis to render the series on

Allowed values:

  • y1
  • y2
Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Label each point in the series with its value

Example:

text
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}

Attributes:

  • position: string - Position the label relative to its data point
    • Allowed values:
      • above
      • below
      • left
      • right
      • middle
  • fmt: string - Format the label value. Defaults to series or axis fmt.
  • size: number - Font size in px
  • distance: number - How far the label is from the data point
  • rotate: number - Rotate each label (degrees)
  • color: string - Change the text color of the labels
  • border_color: string - Change the border color surrounding text labels, defaults to chart background
  • show_overlap: boolean - Show labels for every point even when they overlap

Attributes:

  • color: string
  • opacity: number - Between 0 and 1
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into this series only. For overrides that apply to every series on the chart, set `echarts_series_options` on the parent chart instead.

Example:

text
echarts_options={
    endLabel={ show=true }
    markPoint={ data=[{ type="max" }, { type="min" }] }
}
Whether to stack bars with the same series value. Set to "100%" for percentage stacking. Stack identifier - bars with the same stack_id value will be stacked together. Overrides the stacked prop.

Allowed Parents


Components Bar Chart (`docs/components/bar_chart.mdx`)


title: Bar Chart keywords: ["column chart","bar graph","bar plot"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% bar_chart
	data="demo.daily_orders"
	x="category"
	y="sum(total_sales)"
/%}

Examples

Basic Usage

liquid
{% bar_chart
	data="demo.daily_orders"
	x="category"
	y="sum(total_sales)"
/%}

Bar Chart with Date Grain

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    date_grain="month"
/%}

Sorting by Value

liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    order="sum(total_sales) desc"
/%}

Custom Category Order

liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    x_sort=["Clothing", "Home", "Sports", "Electronics"]
/%}

Bar Chart with Series Colors

liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    series="case when sum(total_sales) > 7000 then '>$7k' when sum(total_sales) > 3500 then '>$3.5k' else '<$3.5k' end"
    title="Sales by Category and Performance"
    chart_options={
        series_colors={
            ">$7k"="#22c55e"
            ">$3.5k"="#f59e0b"
            "<$3.5k"="#ef4444"
        }
    }
/%}

100% Stacked Bar Chart

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    series="category"
    stacked="100%"
    date_grain="month"
    title="Sales Distribution by Category"
/%}

Revenue by Day of Week

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of week"
    title="Revenue by Day of Week"
    subtitle="Weekday vs weekend sales patterns"
/%}

Seasonality Analysis (Month of Year)

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month of year"
    title="Seasonality Analysis"
    subtitle="Sales patterns across months"
/%}
liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="quarter of year"
    title="Quarterly Performance"
    subtitle="Q1 through Q4 comparison"
/%}

Monthly Billing Cycle Patterns

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of month"
    title="Daily Revenue by Day of Month"
    subtitle="Identify billing cycle patterns"
/%}

Week Number Analysis

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="week of year"
    title="Revenue by Week of Year"
    subtitle="Weekly performance across the year"
/%}

Day of Year Analysis

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of year"
    title="Revenue by Day of Year"
    subtitle="Identify patterns across 365 days"
/%}

Extra tooltip fields

liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month"
    tooltip_fields=[
        { value="count(distinct order_id)" label="Orders" },
        { value="sum(total_sales) / nullif(count(distinct order_id), 0)" label="Avg order" fmt="usd" }
    ]
/%}

Raw ECharts overrides (rounded bars, background track)

liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    echarts_series_options={
        itemStyle={ borderRadius=[6, 6, 0, 0] }
        showBackground=true
        backgroundStyle={ color="rgba(0,0,0,0.04)" }
    }
/%}

Attributes

Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

Allowed values:

  • connect
  • gaps
  • zero
Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column. Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Column name for series grouping (applies to all series) Column name for individual point labels displayed at the top of the tooltip Title to display above the component Subtitle to display below the title Information tooltip text (can only be used with title). Displays an info icon next to the title. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

Allowed values:

  • asc
  • desc
  • data
Configure the y-axis

Example:

text
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the secondary y-axis

Example:

text
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the x-axis

Example:

text
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}

Attributes:

  • title: string
  • show_title: boolean - When true, renders the auto-derived axis title (the x column name) below the chart. Ignored when title is set explicitly. Defaults to false — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
  • label_wrap: boolean
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
  • min_interval: string - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • max_interval: string - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
  • label_rotate: number - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
  • title_arrow: boolean - Show/hide the arrow (→) on the axis title
  • max_label_length: number - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.
Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead. Position of the legend (top or bottom)

Allowed values:

  • top
  • bottom
Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones. Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

Example:

text
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}

Attributes:

  • color_palette: array of strings - Array of hex color codes to use for series colors
  • series_colors: map of key-value pairs - Map of series names to hex color codes for custom series coloring
  • zoom: boolean - Enables zoom by dragging on the chart area
  • top_padding: number - Additional padding (in px) above the chart area to prevent labels from being cut off
Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

Example:

text
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
Column name for y-axis Semantic metric name(s) to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Pass an array for multiple series (e.g. `metric=["revenue", "orders"]`). Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Label each point in the series with its value

Example:

text
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}

Attributes:

  • position: string - Position the label relative to its data point
    • Allowed values:
      • above
      • below
      • left
      • right
      • middle
  • fmt: string - Format the label value. Defaults to series or axis fmt.
  • size: number - Font size in px
  • distance: number - How far the label is from the data point
  • rotate: number - Rotate each label (degrees)
  • color: string - Change the text color of the labels
  • border_color: string - Change the border color surrounding text labels, defaults to chart background
  • show_overlap: boolean - Show labels for every point even when they overlap

Attributes:

  • color: string
  • opacity: number - Between 0 and 1
Whether to stack the bars. Set to "100%" for percentage stacking where each bar shows its proportion of the total. Column name for secondary y-axis

Attributes:

  • color: string
  • opacity: number - Between 0 and 1

Allowed Children


Components Benchmark Comparison (`docs/components/benchmark_comparison.mdx`)


title: Benchmark Comparison

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% benchmark_comparison 
    name="vs Franchisees" 
    agg="avg" 
    subject="store_id"
    where="ownership_type = 'franchise'"
/%}

Examples

Compare vs Franchisees

liquid
{% benchmark_comparison 
    name="vs Franchisees" 
    agg="avg" 
    subject="store_id"
    where="ownership_type = 'franchise'"
/%}

Compare vs Full Network

liquid
{% benchmark_comparison 
    name="vs Full Network" 
    agg="avg" 
    subject="store_id"
/%}

Compare vs Region Average

liquid
{% benchmark_comparison 
    name="vs Region Avg" 
    agg="avg" 
    subject="store_id"
    within=["region"]
/%}

Attributes

Display name shown in the dropdown (e.g., "vs Franchisees") Aggregation function to apply across benchmark entities. Options: avg, median, min, max, sum, count, count_distinct

Allowed values:

  • avg
  • median
  • min
  • max
  • sum
  • count
  • count_distinct
Column that defines individual entities (e.g., "store_id", "customer_id"). Required for benchmark calculations. Optional column or expression to use for benchmark calculation. If not specified, uses the main value column. Useful if you have a pre-aggregated benchmark table for RLS reasons. SQL WHERE clause to filter which entities are included in the benchmark (e.g., "ownership_type = 'franchise'") Dimension columns to group the benchmark by (e.g., ["region"]). Leave empty for dataset-wide benchmark. Exclude the current row from its own benchmark calculation (table context only). Default: false Default display type for this comparison. Options: pct (percentage change), abs (absolute change), compared_value (benchmark value)

Allowed values:

  • pct
  • abs
  • compared_value
Custom comparison label text (overrides default "vs {name}") Format code for percentage values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format code for absolute values. See [Value Formatting](/core-concepts/value-formatting) for available formats. If true, negative changes are shown as positive (green). Defaults to the page's `down_is_good` setting.

Allowed Parents


Components Big Value (`docs/components/big_value.mdx`)


title: Big Value keywords: ["KPI","metric","big number","scorecard","headline number"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% big_value
  data="demo.daily_orders"
  value="sum(total_sales)"
  fmt="usd1m"
/%}

Examples

Basic Usage

liquid
{% big_value
  data="demo.daily_orders"
  value="sum(total_sales)"
  fmt="usd1m"
/%}

Comparison

liquid
{% big_value
	data="demo.daily_orders"
	value="sum(total_sales)"
	fmt="usd1m"
	date_range={
		date="date"
		range="last 12 months"
	}
	comparison={
		compare_vs="prior year"
	}
/%}

Sparkline

liquid
{% big_value
	data="demo.daily_orders"
	value="sum(total_sales)"
	fmt="usd1m"
	sparkline={
		type="line"
		x="date"
	}
/%}

Text Size

liquid
{% big_value
	data="demo.daily_orders"
	value="sum(total_sales)"
	fmt="usd1m"
	text_size="4xl"
/%}

Attributes

Table or view to query. Omit when using `metric`. Semantic metric to display (the whole reference — a metric is a single number). Use instead of `data` + `value`. The SQL aggregation to display (with `data`). Omit when using `metric`. Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Comparison configuration object

Example:

text
comparison={
  compare_vs = "prior year"
  display_type = "compared_value"
  target = "string"
  benchmark = {
    agg = "avg"
    subject = "store_name"
    within = ["region"]
  }
  hide_pct = true
  pct_fmt = "string"
  abs_fmt = "string"
  text = "string"
  delta = true
  down_is_good = true
  neutral_range = []
}

Attributes:

  • compare_vs: string - Type of comparison to perform. Options: prior year (same period last year), prior period (previous period of same duration), target (compare against a target value), benchmark (compare against group average/aggregate)
    • Allowed values:
      • prior year
      • prior period
      • target
      • benchmark
  • display_type: string - What to display for comparison. Options: compared_value (comparison period value), abs (absolute change), pct (percentage change). Default: pct
    • Allowed values:
      • compared_value
      • abs
      • pct
  • target: string - Target value for target comparison. Can be a column name, aggregation (e.g., "sum(target_sales)"), or literal value.
  • benchmark: options group
    • Options:
      • agg: string - Aggregation function to apply across benchmark group. Options: avg (average), median, min, max, sum, count, count_distinct
        • Allowed values:
          • avg
          • median
          • min
          • max
          • sum
          • count
          • count_distinct
      • subject: string - Column or expression that defines individual entities in the benchmark (e.g., "store_name", "customer_id"). Required for single-value components.
      • value: string - Optional column or expression to use for benchmark calculation. If not specified, uses the main value column. Useful if you have a pre-aggregated benchmark table for RLS reasons.
      • within: array of strings - Dimension columns to group the benchmark by (e.g., ["region"]). Leave empty for dataset-wide benchmark.
      • where: string - SQL WHERE clause to filter which entities are included in the benchmark
      • exclude_self: boolean - Exclude the current row from its own benchmark calculation (table context only). Default: false
  • hide_pct: boolean - Hide the percentage change line in comparison tooltips
  • pct_fmt: string - Format code for percentage values in comparison tooltips
  • abs_fmt: string - Format code for absolute values in comparison tooltips
  • text: string - Text displayed after the comparison value
  • delta: boolean - Whether to display the comparison as a delta
  • down_is_good: boolean - Whether a decrease is considered positive. Defaults to the page's down_is_good setting.
  • neutral_range: array - Range [min, max] for neutral values. Use null for infinity (e.g., [null, 0] means anything ≤ 0 is neutral)
Sparkline configuration object

Example:

text
sparkline={
  type = "line"
  color = "string"
  x = "string"
  y_fmt = "string"
  x_fmt = "string"
  fit_to_data = true
  connect_group = "string"
  date_grain = "year"
  date_range = {
    range = "today"
    date = "string"
  }
}

Attributes:

  • type: string - The type of sparkline to display
    • Allowed values:
      • line
      • area
      • bar
  • color: string - Color for the sparkline
  • x: string - X column for the sparkline
  • y_fmt: string - Value format for the sparkline tooltips
  • x_fmt: string - Date format for the sparkline tooltips
  • fit_to_data: boolean - Whether to fit the Y axis scale to the data range
  • connect_group: string - Connect group for the sparkline
  • date_grain: string - Time grain for the sparkline data points
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
      • minute
  • date_range: options group
    • Options:
      • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
        • Allowed values:
          • today
          • yesterday
          • last 7 days
          • last 30 days
          • last 3 months
          • last 6 months
          • last 12 months
          • previous week
          • previous month
          • previous quarter
          • previous year
          • this week
          • this month
          • this quarter
          • this year
          • next week
          • next month
          • next quarter
          • next year
          • week to date
          • month to date
          • quarter to date
          • year to date
          • all time
      • date: string - Date column to filter on. Required when the data has multiple date columns.
Format for the main value. See [Value Formatting](/core-concepts/value-formatting) for available formats. Title for the main value Maximum width of the component Minimum width of the component Text size for the value. Options: sm, base, lg, xl (default), 2xl, 3xl, 4xl, 5xl

Allowed values:

  • sm
  • base
  • lg
  • xl
  • 2xl
  • 3xl
  • 4xl
  • 5xl
Additional CSS classes for the title Additional CSS classes for the value URL to link the title to Information tooltip text URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) IDs of filters to apply to the query Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Additional CSS classes for the component Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Set the width of this component (in percent) relative to the page width

Components Bubble (`docs/components/bubble.mdx`)


title: Bubble

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bubble
        y="avg(avg_transaction_value)"
        size="sum(transactions)"
    /%}
{% /combo_chart %}

Examples

Basic Bubble Series

liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bubble
        y="avg(avg_transaction_value)"
        size="sum(transactions)"
    /%}
{% /combo_chart %}

Attributes

Column name for y-axis. Aggregated at the parent combo_chart's `x=`. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Column name for series grouping The axis to render the series on

Allowed values:

  • y1
  • y2
Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Label each point in the series with its value

Example:

text
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}

Attributes:

  • position: string - Position the label relative to its data point
    • Allowed values:
      • above
      • below
      • left
      • right
      • middle
  • fmt: string - Format the label value. Defaults to series or axis fmt.
  • size: number - Font size in px
  • distance: number - How far the label is from the data point
  • rotate: number - Rotate each label (degrees)
  • color: string - Change the text color of the labels
  • border_color: string - Change the border color surrounding text labels, defaults to chart background
  • show_overlap: boolean - Show labels for every point even when they overlap
The opacity of the series Column to use for the size of the bubbles Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into this series only. For overrides that apply to every series on the chart, set `echarts_series_options` on the parent chart instead.

Example:

text
echarts_options={
    endLabel={ show=true }
    markPoint={ data=[{ type="max" }, { type="min" }] }
}

Allowed Parents


Components Bubble Chart (`docs/components/bubble_chart.mdx`)


title: Bubble Chart keywords: ["bubble plot","bubble graph"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    series="category"
/%}

Examples

Basic Usage

liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    series="category"
/%}

Bubble Chart with Formatting

liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    x_fmt="usd"
    y_fmt="usd"
    title="Sales Performance Analysis"
    subtitle="Bubble size represents transaction count"
    series="category"
/%}

Bubble Chart with Point Titles

liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    point_title="category"
    x_fmt="usd"
    y_fmt="usd"
/%}

Attributes

Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

Allowed values:

  • connect
  • gaps
  • zero
Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column. Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Column name for series grouping (applies to all series) Column name for individual point labels displayed at the top of the tooltip Title to display above the component Subtitle to display below the title Information tooltip text (can only be used with title). Displays an info icon next to the title. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

Allowed values:

  • asc
  • desc
  • data
Configure the y-axis

Example:

text
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the secondary y-axis

Example:

text
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the x-axis

Example:

text
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}

Attributes:

  • title: string
  • show_title: boolean - When true, renders the auto-derived axis title (the x column name) below the chart. Ignored when title is set explicitly. Defaults to false — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
  • label_wrap: boolean
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
  • min_interval: string - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • max_interval: string - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
  • label_rotate: number - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
  • title_arrow: boolean - Show/hide the arrow (→) on the axis title
  • max_label_length: number - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.
Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead. Position of the legend (top or bottom)

Allowed values:

  • top
  • bottom
Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones. Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

Example:

text
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}

Attributes:

  • color_palette: array of strings - Array of hex color codes to use for series colors
  • series_colors: map of key-value pairs - Map of series names to hex color codes for custom series coloring
  • zoom: boolean - Enables zoom by dragging on the chart area
  • top_padding: number - Additional padding (in px) above the chart area to prevent labels from being cut off
Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

Example:

text
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
Column name for y-axis Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Label each point in the series with its value

Example:

text
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}

Attributes:

  • position: string - Position the label relative to its data point
    • Allowed values:
      • above
      • below
      • left
      • right
      • middle
  • fmt: string - Format the label value. Defaults to series or axis fmt.
  • size: number - Font size in px
  • distance: number - How far the label is from the data point
  • rotate: number - Rotate each label (degrees)
  • color: string - Change the text color of the labels
  • border_color: string - Change the border color surrounding text labels, defaults to chart background
  • show_overlap: boolean - Show labels for every point even when they overlap
The opacity of the series Column to use for the size of the bubbles Column name for secondary y-axis Format for size values in tooltips. See [Value Formatting](/core-concepts/value-formatting) for available formats.

Allowed Children


Components Button Group (`docs/components/button_group.mdx`)


title: Button Group keywords: ["radio buttons","segmented control","chip selector"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}

Examples

Using `filters`

liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}

Using `where`

liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    where="category = {{category_filter}}"
    date_grain="month"
/%}

Using Inline SQL

liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

```sql filtered_orders
select * from demo.daily_orders
where category = {{category_filter}}
```

{% table data="filtered_orders" /%}

Vertical orientation inside a row

liquid
{% row %}

{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
    orientation="vertical"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}

{% /row %}

Attributes

The id of the button group to be used in a `filters` prop Name of the table to query Array of filter IDs to apply when querying for options Column name to use as the value for each option, and the column to filter by when this button group's `id` is used in the `filters` prop of a chart Column name to use as the label for each option Text displayed above the button group Information tooltip text Initial selected value(s) Allows multiple selections Automatically select the first option when the component loads Layout direction of the button group. Use "vertical" to stack buttons in a column. Best paired with a sibling element inside a `row` so the stack sits alongside its target content.

Allowed values:

  • horizontal
  • vertical
Maximum height in pixels for the button stack when `orientation="vertical"`. Buttons scroll if the list overflows. Ignored when horizontal. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.

Using the Filter Variable

Reference this filter using {{filter_id}}. The value returned depends on where you use it.

The examples below show values for three scenarios:

  • No selection
  • Single select: "Electronics" selected
  • Multi select: "Sports" and "Home" selected (when multiple=true)
Context Default Property No Selection Single Select Multi Select
Inline SQL query .selected '' 'Electronics' ('Sports', 'Home')
where attribute .selected '' 'Electronics' ('Sports', 'Home')
Text / Markdown .literal Electronics Sports, Home

Available Properties

You can also access specific properties using {{filter_id.property}}:

.filter

Returns a complete SQL filter expression ready to use in WHERE clauses. Returns true when no value is selected.

liquid
{% button_group id="category_filter" data="products" value_column="category" /%}

```sql filtered_products
select * from products
where {{category_filter.filter}}
```
No Selection Single Select Multi Select
true category = 'Electronics' category IN ('Sports', 'Home')

.selected

Returns the selected value(s) wrapped in quotes, suitable for SQL comparisons. Returns an empty string when no value is selected.

liquid
{% button_group id="category_filter" data="products" value_column="category" /%}

```sql products_by_category
select * from products
where category = {{category_filter.selected}}
```
No Selection Single Select Multi Select
'' 'Electronics' ('Sports', 'Home')

.literal

Returns the raw unescaped selected value(s), useful for display in text or dynamic column selection.

liquid
{% button_group id="sort_column" data="products" value_column="column_name" /%}

```sql dynamic_sort
select * from products
order by {{sort_column.literal}}
```
No Selection Single Select Multi Select
`` Electronics Sports, Home

.label

Returns the display label for the selected option(s). Falls back to the value if no label is defined.

liquid
{% button_group id="category_filter" %}
    {% option value="Electronics" label="Electronics" /%}
    {% option value="Sports" label="Sports" /%}
    {% option value="Home" label="Home" /%}
{% /button_group %}

Selected: {{category_filter.label}}
No Selection Single Select Multi Select
`` Electronics Sports, Home

.fmt

Returns the format string associated with the selected option. For multiple selections, returns the first format.

liquid
{% button_group id="metric_selector" %}
    {% option value="revenue" label="Revenue" fmt="usd" /%}
    {% option value="growth_rate" label="Growth Rate" fmt="pct1" /%}
{% /button_group %}

{% big_value data={metrics} value=value fmt={{metric_selector.fmt}} /%}
No Selection Single Select Multi Select
`` usd usd

Allowed Children


Components Calendar Heatmap (`docs/components/calendar_heatmap.mdx`)


title: Calendar Heatmap keywords: ["calendar chart","activity chart","contribution graph"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
/%}

Examples

Basic Usage

liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
/%}

Calendar Heatmap with Custom Colors

liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
    title="Daily Sales Heatmap"
    chart_options={
        color_scale = ["#0d0887", "#6300a7", "#a62098", "#d5546e", "#f68d45", "#fcd225", "#f0f921"]
    }
/%}

Calendar Heatmap with Conditional Colors

liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
    title="Sales Performance Heatmap"
    chart_options={
        conditional_colors = "case when sum(total_sales) > 65000 then '#22c55e' when sum(total_sales) > 40000 then '#f59e0b' else '#ef4444' end"
    }
/%}

Calendar Heatmap with Conditional Colors and Legend

liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
    title="Sales Performance Heatmap"
    chart_options={
        conditional_colors="case when sum(total_sales) > 65000 then '#22c55e' when sum(total_sales) > 40000 then '#f59e0b' else '#ef4444' end"
        color_map={
            "#22c55e"="High Sales"
            "#f59e0b"="Medium Sales"
            "#ef4444"="Low Sales"
        }
    }
/%}

Attributes

Name of the table to query. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Column name for dates Column name for cell values. Omit when using `metric`. Title to display above the chart Subtitle to display below the title Information tooltip text (can only be used with title) URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Format for values (defaults to `num`, or the metric format in metric mode). See [Value Formatting](/core-concepts/value-formatting) for available formats. Show color scale legend Show borders between calendar cells Color and styling options for the heatmap

Example:

text
chart_options={
  color_scale = ["value1", "value2"]
  color_palette = ["value1", "value2"]
  conditional_colors = "string"
  color_map = {
    "key1" = "value1"
    "key2" = "value2"
  }
}

Attributes:

  • color_scale: array of strings - Array of hex colors for the heatmap gradient. A single-color array auto-expands to [background, color].
  • color_palette: array of strings - Deprecated. Use color_scale.
  • conditional_colors: string - SQL CASE expression returning hex colors based on value
  • color_map: map of key-value pairs - Maps hex colors to legend labels when using conditional_colors
Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

Example:

text
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
}

Components Callout (`docs/components/callout.mdx`)


title: Callout keywords: ["alert","banner","notice","admonition"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% callout type="info" title="Report Info"%}
This is an info callout
{% /callout %}

Examples

Basic Usage

liquid
{% callout type="info" title="Report Info"%}
This is an info callout
{% /callout %}

Attributes

Allowed values:

  • info
  • success
  • warning
  • error
Set the width of this component (in percent) relative to the page width

Components Candlestick (`docs/components/candlestick.mdx`)


title: Candlestick keywords: ["ohlc","stock chart","financial chart"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    y_axis_options={
        min=90
        max=115
    }
/%}

Examples

Basic Usage

liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    y_axis_options={
        min=90
        max=115
    }
/%}

With Volume

liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close, 1500000 as volume
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0, 2100000
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0, 1800000
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0, 2500000
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0, 3200000
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    volume="volume"
    y2_fmt="num0"
    title="Stock Price with Volume"
    y_axis_options={
        min=90
        max=115
    }
/%}

With Custom Colors

liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    chart_options={
        up_color="#22c55e"
        down_color="#ef4444"
    }
    y_axis_options={
        min=90
        max=115
    }
/%}

Attributes

Name of the table or view to query IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
Column for x-axis (typically date/time) Column for opening price Column for high price Column for low price Column for closing price Column for trading volume (displayed as bars on secondary y-axis) Format for x-axis values and labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y-axis values and labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for secondary y-axis (volume) values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Title to display above the component Subtitle to display below the title Information tooltip text (can only be used with title). Displays an info icon next to the title. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Configure the y-axis

Example:

text
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the x-axis

Example:

text
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}

Attributes:

  • title: string
  • show_title: boolean - When true, renders the auto-derived axis title (the x column name) below the chart. Ignored when title is set explicitly. Defaults to false — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
  • label_wrap: boolean
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
  • min_interval: string - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • max_interval: string - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
  • label_rotate: number - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
  • title_arrow: boolean - Show/hide the arrow (→) on the axis title
  • max_label_length: number - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.
Candlestick chart configuration options

Attributes:

  • up_color: string - Color for bullish (up) candles
  • down_color: string - Color for bearish (down) candles
  • zoom: boolean - Enables zoom by dragging on the chart area
Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

Example:

text
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}

Components Chord Chart (`docs/components/chord_chart.mdx`)


title: Chord Chart keywords: ["chord diagram","circular flow","relationship diagram"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
/%}

Examples

Basic Usage

liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
/%}

Chord Chart with Custom Colors

liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
    title="Category to Item Flow"
    chart_options={
        color_palette = ["#0d0887", "#6300a7", "#a62098", "#d5546e", "#f68d45", "#fcd225", "#f0f921"]
    }
/%}

Chord Chart with Raw ECharts Overrides

liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
    echarts_options={
        series=[{ startAngle=0 padAngle=6 }]
    }
    echarts_series_options={
        itemStyle={ borderRadius=6 }
    }
/%}

Attributes

Name of the table or view to query. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Column name for source nodes Column name for target nodes Column name for flow values (chord thickness). Omit when using `metric`. Title to display above the component Subtitle to display below the title Information tooltip text (can only be used with title). Displays an info icon next to the title. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Format for values (defaults to `num`, or the metric format in metric mode). See [Value Formatting](/core-concepts/value-formatting) for available formats. Show node labels around the circle Chart configuration options

Example:

text
chart_options={
  color_palette = ["value1", "value2"]
  series_colors = {
    "key1" = "value1"
    "key2" = "value2"
  }
}

Attributes:

  • color_palette: array of strings
  • series_colors: map of key-value pairs
Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

Example:

text
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
}
Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.

Components Clock (`docs/components/clock.mdx`)


title: Clock

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% clock /%}

Examples

Default Clock (12h)

liquid
{% clock /%}

24-Hour Clock

liquid
{% clock format="24h" /%}

Attributes

Time format: 12-hour or 24-hour

Allowed values:

  • 12h
  • 24h
Font variant: sans-serif or monospace

Allowed values:

  • sans
  • mono
Text alignment

Allowed values:

  • left
  • right

Components Combo Chart (`docs/components/combo_chart.mdx`)


title: Combo Chart keywords: ["mixed chart","combination chart","dual axis"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
%}
    {% line
        y="sum(total_sales)"
    /%}
    {% bar
        y="sum(transactions)"
        axis="y2"
    /%}
{% /combo_chart %}

Examples

Basic Usage

liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
%}
    {% line
        y="sum(total_sales)"
    /%}
    {% bar
        y="sum(transactions)"
        axis="y2"
    /%}
{% /combo_chart %}

Combo Chart with Area and Line

liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
%}
    {% area
        y="sum(total_sales)"
    /%}
    {% line
        y="avg(avg_transaction_value)"
        axis="y2"
    /%}
{% /combo_chart %}

Combo Chart with Formatting

liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    y_fmt="usd"
    y2_fmt="num0"
    title="Sales and Transactions Overview"
    subtitle="Combined view of sales and transaction volume"
    date_grain="month"
%}
    {% line
        y="sum(total_sales)"
    /%}
    {% bar
        y="sum(transactions)"
        axis="y2"
    /%}
{% /combo_chart %}

Raw ECharts overrides

liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
    echarts_options={
        dataZoom=[{ type="slider" }]
        tooltip={ position="top" }
    }
    echarts_series_options={
        itemStyle={ borderRadius=4 }
    }
%}
    {% bar y="sum(total_sales)" /%}
{% /combo_chart %}

Attributes

Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

Allowed values:

  • connect
  • gaps
  • zero
Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column. Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Column name for series Column name for individual point labels displayed at the top of the tooltip Title to display above the component Subtitle to display below the title Information tooltip text (can only be used with title). Displays an info icon next to the title. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

Allowed values:

  • asc
  • desc
  • data
Configure the y-axis

Example:

text
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the secondary y-axis

Example:

text
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the x-axis

Example:

text
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}

Attributes:

  • title: string
  • show_title: boolean - When true, renders the auto-derived axis title (the x column name) below the chart. Ignored when title is set explicitly. Defaults to false — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
  • label_wrap: boolean
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
  • min_interval: string - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • max_interval: string - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
    • Allowed values:
      • year
      • quarter
      • month
      • week
      • day
      • hour
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
  • label_rotate: number - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
  • title_arrow: boolean - Show/hide the arrow (→) on the axis title
  • max_label_length: number - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.
Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead. Position of the legend (top or bottom)

Allowed values:

  • top
  • bottom
Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones. Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

Example:

text
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}

Attributes:

  • color_palette: array of strings - Array of hex color codes to use for series colors
  • series_colors: map of key-value pairs - Map of series names to hex color codes for custom series coloring
  • zoom: boolean - Enables zoom by dragging on the chart area
  • top_padding: number - Additional padding (in px) above the chart area to prevent labels from being cut off
Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

Example:

text
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}

Allowed Children


Components Commentary (`docs/components/commentary.mdx`)


title: Commentary

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% commentary id="overview" /%}

Examples

Page-wide commentary

liquid
{% commentary id="overview" /%}

Reporting-period commentary

liquid
{% commentary id="monthly-review" scope="period" /%}

Commentary per period and input

liquid
{% dropdown id="category" data="demo.daily_orders" value_column="category" select_first=true /%}

{% commentary id="category-review" scope=["period", "category"] /%}

Attributes

Unique identifier for the commentary component What the commentary is kept for: `page` (one for the whole page), `period` (one per reporting period; requires `workflow.period` in the frontmatter), an input id, or a list such as `["period", "fund"]` (one per combination of selected values). Inputs must be single-select: dropdown, button_group, input_tabs, toggle or period_selector. Placeholder text to show when the commentary is empty Additional CSS classes to apply to the component Emails of allowed commentary editors Title to display above the commentary When to hide the edit metadata

Allowed values:

  • always
  • never
  • print
Style of the commentary

Allowed values:

  • quote
  • normal
Set the width of this component (in percent) relative to the page width

Components Comparison Selector (`docs/components/comparison_selector.mdx`)


title: Comparison Selector keywords: ["period over period","year over year","prior period","prior year","comparison","time comparison","date comparison","compare periods"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% comparison_selector
    id="comp"
    default_value="prior year"
/%}

{% big_value
    data="demo.daily_orders"
    value="sum(total_sales)"
    fmt="usd1m"
    date_range={
        date="date"
        range="last 12 months"
    }
    comparison={
        compare_vs={{comp}}
    }
/%}

Examples

Using `comparison`

liquid
{% comparison_selector
    id="comp"
    default_value="prior year"
/%}

{% big_value
    data="demo.daily_orders"
    value="sum(total_sales)"
    fmt="usd1m"
    date_range={
        date="date"
        range="last 12 months"
    }
    comparison={
        compare_vs={{comp}}
    }
/%}

Attributes

The id of the comparison selector to be used in SQL query templates Optional array of preset comparison values to show. If not provided, all comparison options will be available. Default comparison to select on load

Allowed values:

  • prior year
  • prior period
  • target
  • benchmark
Text displayed above the selector Information tooltip text URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Placeholder text displayed when no value is selected Icon to display Set the width of this component (in percent) relative to the page width

Using the Filter Variable

Reference this filter using {{filter_id}}. The value returned depends on where you use it.

Context Default Property No Selection Result
Inline SQL query .comparison {"compare_vs": "prior year"}
where attribute .comparison {"compare_vs": "prior year"}
Text / Markdown .comparison {"compare_vs": "prior year"}

Available Properties

You can also access specific properties using {{filter_id.property}}:

.selected

Returns the selected comparison value with quotes. Returns an empty string when no value is selected.

liquid
{% comparison_selector id="comparison" preset_values=["prior year", "prior period"] /%}

```sql sales_comparison
select 
  date,
  sum(sales) as total_sales,
  '{{comparison.selected}}' as comparison_type
from orders
group by date
```

Example value: 'prior year'

.literal

Returns the raw unescaped selected value.

liquid
{% comparison_selector id="comparison" preset_values=["prior year", "prior period"] /%}

```sql sales_comparison
select 
  date,
  sum(sales) as total_sales,
  {{comparison.literal}} as comparison_type
from orders
group by date
```

Example value: prior year

.compare_vs

Returns the comparison type.

Example value: prior year

.comparison

Returns the full comparison configuration as JSON. Use {{comp}} directly with compare_vs to dynamically configure comparisons.

liquid
{% comparison_selector id="comp" /%}

{% big_value 
    data="demo.daily_orders"
    value="sum(total_sales)"
    comparison={ compare_vs={{comp}} }
/%}

Example value: {"compare_vs": "prior year"}

.agg

For benchmark comparisons: returns the aggregation function.

Example value: avg

.subject

For benchmark comparisons: returns the subject column that defines entities.

Example value: region

.target

For target comparisons: returns the target value or expression.

Example value: 100000

Allowed Children


Components Custom Echart (`docs/components/custom_echart.mdx`)


title: Custom Echart keywords: ["echarts","custom chart","advanced chart","escape hatch","config","waterfall","bridge"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% custom_echart data="demo.daily_orders" %}
{
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}

Examples

Basic Usage

liquid
{% custom_echart data="demo.daily_orders" %}
{
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}

Multiple Series with Tooltip

liquid
{% custom_echart data="demo.daily_orders" %}
{
  tooltip: { trigger: 'axis' },
  legend: { show: true },
  xAxis: { type: 'category' },
  yAxis: {},
  series: [
    { type: 'bar', name: 'Sales', encode: { x: 'category', y: 'total_sales' } },
    { type: 'line', name: 'Transactions', encode: { x: 'category', y: 'transactions' } }
  ]
}
{% /custom_echart %}

Dataset Transform

liquid
{% custom_echart data="demo.daily_orders" %}
{
  dataset: [
    {},
    { transform: { type: 'sort', config: { dimension: 'total_sales', order: 'desc' } } }
  ],
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', datasetIndex: 1, encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}

Waterfall (EBITDA Bridge)

liquid
```sql ebitda_bridge
select 'Prior EBITDA' as step, 1 as ord, 0 as placeholder, null as inc, null as dec, 32000000 as tot
union all select 'Home', 2, 32000000, 6200000, null, null
union all select 'Sports', 3, 38200000, 4100000, null, null
union all select 'Groceries', 4, 40000000, null, 2300000, null
union all select 'Current EBITDA', 5, 0, null, null, 40000000
order by ord
```

{% custom_echart data="ebitda_bridge" title="EBITDA Bridge" %}
{
  tooltip: { trigger: 'axis', valueFormatter: 'fmt:usd1m' },
  xAxis: { type: 'category', axisLabel: { interval: 0 } },
  yAxis: { axisLabel: { formatter: 'fmt:usd0m' } },
  series: [
    { type: 'bar', stack: 'bridge', silent: true,
      itemStyle: { color: 'transparent' },
      encode: { x: 'step', y: 'placeholder' } },
    { type: 'bar', stack: 'bridge', name: 'Increase',
      itemStyle: { color: '#22A39F' },
      label: { show: true, position: 'top', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'inc' } },
    { type: 'bar', stack: 'bridge', name: 'Decrease',
      itemStyle: { color: '#E2483D' },
      label: { show: true, position: 'bottom', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'dec' } },
    { type: 'bar', stack: 'bridge', name: 'Total',
      itemStyle: { color: '#475569' },
      label: { show: true, position: 'top', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'tot' } }
  ]
}
{% /custom_echart %}

JavaScript mode (functions, gradients)

liquid
{% custom_echart data="demo.daily_orders" %}
{
  tooltip: { trigger: 'axis', valueFormatter: (value) => fmt(value, 'usd0') },
  xAxis: { type: 'category' },
  yAxis: { axisLabel: { formatter: (value) => fmt(value, 'usd0m') } },
  series: [
    {
      type: 'bar',
      encode: { x: 'category', y: 'total_sales' },
      itemStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: theme.colorPalettes.default[0] },
          { offset: 1, color: theme.colorPalettes.default[1] }
        ])
      },
      label: { show: true, formatter: (params) => fmt(params.value.total_sales, 'usd0') }
    }
  ]
}
{% /custom_echart %}

Attributes

Name of the table to query IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Title to display above the chart Subtitle to display below the title Information tooltip text (can only be used with title) URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) ECharts rendering engine

Allowed values:

  • canvas
  • svg
Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom

Components Custom Map (`docs/components/custom_map.mdx`)


title: Custom Map keywords: ["map","mapbox","maplibre","custom map","geospatial","gl"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% custom_map height=400 %}
// mapgl is Mapbox GL when a token is available, else MapLibre GL.
// container and the access token are provided for you.
const map = new mapgl.Map({
  container,
  center: [-71.06, 42.36],
  zoom: 9
});
// Tiles load asynchronously — signal readiness once painted so PDF/PNG
// export captures a finished map rather than a blank frame.
map.on('idle', () => evidence.ready());
{% /custom_map %}

Examples

Basic map

liquid
{% custom_map height=400 %}
// mapgl is Mapbox GL when a token is available, else MapLibre GL.
// container and the access token are provided for you.
const map = new mapgl.Map({
  container,
  center: [-71.06, 42.36],
  zoom: 9
});
// Tiles load asynchronously — signal readiness once painted so PDF/PNG
// export captures a finished map rather than a blank frame.
map.on('idle', () => evidence.ready());
{% /custom_map %}

Plot Evidence data as points

liquid
```sql locations
select 'New York'    as name, -74.01  as lng, 40.71 as lat
union all select 'Los Angeles', -118.24, 34.05
union all select 'Chicago',      -87.63, 41.88
union all select 'Houston',      -95.37, 29.76
union all select 'Denver',      -104.99, 39.74
union all select 'Seattle',     -122.33, 47.61
union all select 'Miami',        -80.19, 25.76
```

{% custom_map height=500 %}
const map = new mapgl.Map({ container, center: [-98, 39], zoom: 3 });
map.on('load', async () => {
  const rows = await evidence.query('locations');
  map.addSource('pts', {
    type: 'geojson',
    data: {
      type: 'FeatureCollection',
      features: rows.map((r) => ({
        type: 'Feature',
        geometry: { type: 'Point', coordinates: [r.lng, r.lat] },
        properties: r
      }))
    }
  });
  map.addLayer({ id: 'pts', type: 'circle', source: 'pts', paint: { 'circle-radius': 5 } });
});
{% /custom_map %}

Import a plugin (lasso / draw)

liquid
{% custom_map height=500 %}
// The draw control's buttons are CSS sprites — load its stylesheet or they render blank.
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/dist/mapbox-gl-draw.css';
document.head.appendChild(link);

const { default: MapboxDraw } = await import('https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/+esm');
const map = new mapgl.Map({ container, center: [-98, 39], zoom: 3 });
map.on('load', () => {
  map.addControl(new MapboxDraw({ displayControlsDefault: false, controls: { polygon: true, trash: true } }));
});
{% /custom_map %}

How it works

The body of the tag is JavaScript that draws a map. It runs in a sandboxed iframe with three things already in scope:

  • container — the element to render the map into.
  • mapgl — the map library (Mapbox GL, or MapLibre GL when there is no Mapbox token). Write standard Mapbox / MapLibre code against it.
  • evidence — your page's data and state: run queries, read and write filters, and follow the report theme.

A minimal map:

js
const map = new mapgl.Map({ container, center: [-71.06, 42.36], zoom: 9 });
map.on('idle', () => evidence.ready());

From there you write the same code you would anywhere else with Mapbox GL or MapLibre GL: load data with evidence.query, add sources and layers, and import any map plugin from a CDN. Because the code runs in an isolated iframe it cannot reach the rest of the page — it interacts with the report only through evidence. The full list of what is in scope is below.

Globals available to your code

The tag body runs as JavaScript inside an isolated iframe with these globals already in scope:

Global What it is
container The element to mount your map into.
mapgl The active map library — Mapbox GL when a token is available, otherwise MapLibre GL. Use new mapgl.Map({ container, ... }) for provider-agnostic code.
maplibregl MapLibre GL, always available.
mapboxgl Mapbox GL, with the access token already set. undefined when there is no token.
provider / token The resolved provider and Mapbox token.
evidence.query(name) Rows for a named query or sql block on the page. Returns a promise; page filters are already applied.
evidence.variables Values passed via variables={…}. Always current; onVariablesChange fires on change.
evidence.onVariablesChange(cb) Fires when any variables value changes. Returns an unsubscribe fn.
evidence.filters get(), set(id, value), create(id, value, { column }), subscribe(cb) — read and write page filters.
evidence.subscribe(cb) Fires on any state change (variables, filters, or theme). Returns unsubscribe.
evidence.theme { mode, palette } — resolved light/dark mode and categorical palette.
evidence.onThemeChange(cb) Fires on theme/mode change — swap the basemap style here for dark mode.
evidence.onResize(cb) Fires when the block resizes. Call map.resize() in the callback.
evidence.onTeardown(cb) Register cleanup (e.g. () => map.remove()) run before the map re-renders on an edit.
evidence.ready() Signal the first render is done, so PDF/PNG export captures a finished frame.

Basemaps and keys

You don't need a Mapbox key in Studio. Maps render with a Mapbox basemap and the token is applied for you, so new mapboxgl.Map({ container }) works with no accessToken.

Where no token is configured — such as the open-source CLI or local development — maps use MapLibre GL with a free OpenFreeMap basemap instead. mapgl points at whichever library is active, so new mapgl.Map({ container }) works either way.

  • provider="maplibre" always uses the keyless MapLibre basemap.
  • token="..." uses your own Mapbox account.

Choose a basemap style for the current theme with evidence.theme.mode:

  • Mapbox — mapbox://styles/mapbox/light-v11, mapbox://styles/mapbox/dark-v11
  • MapLibre — https://tiles.openfreemap.org/styles/positron (light), https://tiles.openfreemap.org/styles/dark

Switch the style when the report toggles light/dark:

js
evidence.onThemeChange((t) => map.setStyle(styleFor(t.mode)));

Theming panels and overlays

Custom panels, legends, and controls you add to the map match the report theme with these CSS variables — set for you and updated on light/dark toggle (a sandboxed iframe has no host CSS otherwise, so use these rather than assuming a background):

  • var(--evidence-background) — surface background
  • var(--evidence-foreground) — text
  • var(--evidence-muted-foreground) — secondary text
  • var(--evidence-border) — borders / dividers

evidence.theme.mode (light / dark) plus evidence.onThemeChange(cb) let you swap the basemap style to match dark mode.

Reacting to page filters and variables

A map and the rest of the page interact in three separate ways. Pick the one that matches what you need:

1. Filter the map's data by a page input (dropdown, date range). A filter takes effect where a query references it — passing it via variables= does not filter anything. Reference it in the SQL of the query the map runs, then evidence.query() that query:

sql
-- city_sales (the query the map consumes)
select * from city_sales_all where {{ region_filter.filter }}
js
const rows = await evidence.query('city_sales'); // re-runs with a region predicate when the dropdown changes

Selecting the dropdown re-runs city_sales; call evidence.query again from evidence.subscribe / evidence.filters.subscribe to redraw with the filtered rows.

2. Read a filter/variable value in map JS (labels, client-side logic — not filtering). Pass it via variables= as a quoted {{ }} expression — use .literal for the raw value or .selected for a SQL-quoted value. This gives you the value in evidence.variables; it does not filter any query.

text
{% custom_map height=400 variables={ region="{{ region_filter.literal }}" } %}
const label = evidence.variables.region; // e.g. show the selected region in a badge
evidence.onVariablesChange((v) => { /* re-label */ });
{% /custom_map %}

3. Write a filter back from the map (lasso/click → filter other components or a server re-query). Use evidence.filters and reference the filter in your query's SQL — the large-dataset pattern where you can't ship every row to the browser. A viewport-driven re-query on pan/zoom:

js
const map = new mapgl.Map({ container, center: [-98, 39], zoom: 4 });
async function load() {
  const rows = await evidence.query('points_in_view'); // SQL references {{ min_lng.literal }} etc.
  // ...update your source with rows...
}
map.on('load', load);
map.on('moveend', () => {
  const b = map.getBounds();
  evidence.filters.set('min_lng', b.getWest());
  evidence.filters.set('max_lng', b.getEast());
  evidence.filters.set('min_lat', b.getSouth());
  evidence.filters.set('max_lat', b.getNorth());
});
evidence.filters.subscribe(load); // re-query when the bbox filters change

Call evidence.filters.create('min_lng', -130) once at startup for any filter the page's SQL references before the user interacts.

When you write a selection back as a list of ids, an empty list is ambiguous — it can mean "nothing selected yet" or "selected, matched nothing." Track selection state explicitly rather than checking the array length. And because id IN () is invalid SQL, write a value that matches no rows (e.g. ['__none__']) rather than an empty array when a selection matches nothing.

PDF and PNG export

Map tiles load after your setup code returns, so signal completion once the map has painted or export captures a blank frame:

js
map.on('idle', () => evidence.ready());

PNG export (image download) reads the WebGL canvas, which requires preserveDrawingBuffer — custom_map turns it on for you, so image export works by default. (PDF export uses a page screenshot and needs nothing extra.) On a very heavy map you can trade image export for a small perf win by opting out:

js
const map = new mapgl.Map({ container, preserveDrawingBuffer: false }); // opt out: PNG blank, PDF still works

Adding plugins

Import any map-ecosystem library from a CDN — mapbox-gl-draw (lasso / box select), deck.gl, turf, h3-js, and so on. They load as normal dynamic imports. A plugin with its own UI (buttons, icons) also needs its stylesheet loaded, or its controls render blank:

js
// load the plugin's CSS too — icons are CSS sprites
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/dist/mapbox-gl-draw.css';
document.head.appendChild(link);

const { default: MapboxDraw } = await import('https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/+esm');
map.addControl(new MapboxDraw());

mapbox-gl-draw's controls appear only on the Mapbox provider; on MapLibre use @maplibre/maplibre-gl-draw.

Common issues

Blank map. If you passed a token, check it is valid — an invalid token still loads Mapbox but then fails to fetch tiles. Remove the token to fall back to the keyless MapLibre basemap.

Export shows a blank map. Tiles load after your setup code returns, so call evidence.ready() once the map has painted: map.on('idle', () => evidence.ready()).

Different basemap locally than when published. Local development and the CLI often have no Mapbox token, so they use MapLibre while Studio uses Mapbox. Set PUBLIC_MAPBOX_TOKEN locally to match, or set provider to pin one everywhere. If you rely on a Mapbox-only plugin, pin provider="mapbox".

Attributes

Title shown above the map Subtitle shown below the title Information tooltip text (can only be used with title) URL to link the info text to (can only be used with info) Custom text for the info link Mapbox access token. Not required in Studio — a token is provided for you. Pass one to use your own Mapbox account. With no token, maps use keyless MapLibre. Force a basemap provider. Defaults to Mapbox when a token is available, otherwise MapLibre.

Allowed values:

  • mapbox
  • maplibre
Page values to expose to the map as `evidence.variables` — e.g. `variables={ region=$region label="static" }` (Markdoc object syntax: whitespace-separated `key=value`, no commas). Changing a value fires `evidence.onVariablesChange(cb)` / `evidence.subscribe(cb)`. Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels

Components Date Grain Selector (`docs/components/date_grain_selector.mdx`)


title: Date Grain Selector keywords: ["date grain","time grain","date bucket","date interval","date truncate","date grouping","time period","day week month year","date aggregation"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% date_grain_selector
    id="time_grain"
    default_value="month"
/%}

{% line_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    date_grain={{time_grain}}
/%}

Examples

Using `date_grain`

liquid
{% date_grain_selector
    id="time_grain"
    default_value="month"
/%}

{% line_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    date_grain={{time_grain}}
/%}

Using Inline SQL

liquid
{% date_grain_selector
    id="time_grain"
    default_value="month"
/%}

```sql sales_by_period
select 
    date_trunc({{time_grain}}, date) as period,
    sum(total_sales) as total_sales
from demo.daily_orders
group by 1
order by 1
```

{% line_chart
    data="sales_by_period"
    x="period"
    y="total_sales"
/%}

Attributes

The id of the date grain selector to be used in SQL query templates Optional array of preset date grain values to show. If not provided, all date grain options will be available. Default date grain to select on load

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
Text displayed above the selector Information tooltip text URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Placeholder text displayed when no value is selected Icon to display Set the width of this component (in percent) relative to the page width

Using the Filter Variable

Reference this filter using {{filter_id}}. The value returned depends on where you use it.

Context Default Property No Selection Result
Inline SQL query .selected '' 'month'
where attribute .selected '' 'month'
Text / Markdown .literal month

Available Properties

You can also access specific properties using {{filter_id.property}}:

.selected

Returns the selected date grain value with quotes. Returns an empty string when no value is selected.

liquid
{% date_grain_selector id="grain" preset_values=["day", "week", "month"] /%}

```sql sales_by_grain
select 
  toStartOf{{grain.selected}}(date) as period,
  sum(sales) as total_sales
from orders
group by period
```

Example value: 'month'

.literal

Returns the raw unescaped selected value. Use this with the date_grain attribute.

liquid
{% date_grain_selector id="grain" preset_values=["day", "week", "month"] /%}

```sql sales_by_grain
select 
  {{grain.literal}} as period,
  sum(sales) as total_sales
from orders
group by period
```

Example value: month


Components Delta (`docs/components/delta.mdx`)


title: Delta keywords: ["change","difference","variance","comparison"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% delta
	data="demo.daily_orders"
	value="sum(total_sales)"
	comparison={
		compare_vs="target"
		target="120000000"
	}
/%}

Examples

Basic Usage

liquid
{% delta
	data="demo.daily_orders"
	value="sum(total_sales)"
	comparison={
		compare_vs="target"
		target="120000000"
	}
/%}

Semantic metric

liquid
{% delta metric="revenue" comparison={ compare_vs="prior year" } /%}

Attributes

Table or view to query. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. SQL expression to insert into the SELECT part of the query (e.g., "COUNT(*)", "SUM(sales)"). Omit when using `metric`. Format code for the value (e.g., "num", "usd", "pct"). See formatValue documentation for available formats. See [Value Formatting](/core-concepts/value-formatting) for available formats. Text appearing after the delta (e.g., vs. prev month) Whether to display as a chip Comparison configuration object

Example:

text
comparison={
  compare_vs = "prior year"
  display_type = "compared_value"
  target = "string"
  benchmark = {
    agg = "avg"
    subject = "store_name"
    within = ["region"]
  }
  hide_pct = true
  pct_fmt = "string"
  abs_fmt = "string"
  down_is_good = true
}

Attributes:

  • compare_vs: string - Type of comparison to perform. Options: prior year (same period last year), prior period (previous period of same duration), target (compare against a target value), benchmark (compare against group average/aggregate)
    • Allowed values:
      • prior year
      • prior period
      • target
      • benchmark
  • display_type: string - What to display for comparison. Options: compared_value (comparison period value), abs (absolute change), pct (percentage change). Default: pct
    • Allowed values:
      • compared_value
      • abs
      • pct
  • target: string - Target value for target comparison. Can be a column name, aggregation (e.g., "sum(target_sales)"), or literal value.
  • benchmark: options group
    • Options:
      • agg: string - Aggregation function to apply across benchmark group. Options: avg (average), median, min, max, sum, count, count_distinct
        • Allowed values:
          • avg
          • median
          • min
          • max
          • sum
          • count
          • count_distinct
      • subject: string - Column or expression that defines individual entities in the benchmark (e.g., "store_name", "customer_id"). Required for single-value components.
      • value: string - Optional column or expression to use for benchmark calculation. If not specified, uses the main value column. Useful if you have a pre-aggregated benchmark table for RLS reasons.
      • within: array of strings - Dimension columns to group the benchmark by (e.g., ["region"]). Leave empty for dataset-wide benchmark.
      • where: string - SQL WHERE clause to filter which entities are included in the benchmark
      • exclude_self: boolean - Exclude the current row from its own benchmark calculation (table context only). Default: false
  • hide_pct: boolean - Hide the percentage change line in comparison tooltips
  • pct_fmt: string - Format code for percentage values in comparison tooltips
  • abs_fmt: string - Format code for absolute values in comparison tooltips
  • down_is_good: boolean - Whether a downward trend is considered positive. Defaults to the page's down_is_good setting.
Whether to show the value Whether to show the delta symbol Position of the delta symbol relative to the value

Allowed values:

  • left
  • right
Range [min, max] for neutral values. Use null for infinity (e.g., [null, 0] means anything ≤ 0 is neutral) IDs of filters to apply to the query Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Set the width of this component (in percent) relative to the page width

Components Details (`docs/components/details.mdx`)


title: Details keywords: ["expandable","collapsible section","show more"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% details
    title="Metric Definitions"
%}

**Sales:** includes sales of all core products in all regions

**Sales Growth:** YoY growth in sales

{% /details %}

Examples

Basic Usage

liquid
{% details
    title="Metric Definitions"
%}

**Sales:** includes sales of all core products in all regions

**Sales Growth:** YoY growth in sales

{% /details %}

Open on Desktop, Collapsed on Mobile

liquid
{% details
    title="Metric Definitions"
    open=true
    open_mobile=false
%}

**Sales:** includes sales of all core products in all regions

**Sales Growth:** YoY growth in sales

{% /details %}

Attributes

Title of the details section Whether the details section starts open Whether the details section starts open on mobile screens. Defaults to the value of `open` Set the width of this component (in percent) relative to the page width

Components Dimension (`docs/components/dimension.mdx`)


title: Dimension

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" /%}
    {% dimension value="date" date_grain="month" title="Month" /%}
{% /table %}

Examples

Table with Dimensions

liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" /%}
    {% dimension value="date" date_grain="month" title="Month" /%}
{% /table %}

With Image

liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" image="image_url" /%}
    {% measure value="sum(total_sales)" /%}
{% /table %}
liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" link="concat('https://www.google.com/search?q=', category)" /%}
    {% measure value="sum(total_sales)" /%}
{% /table %}
liquid
{% table data="sales" %}
    {% dimension value="vendor" logo="domain" /%}
    {% measure value="sum(amount)" /%}
{% /table %}

Conditional Colors

liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" conditional_colors="case when sum(total_sales) > 20000000 then '#22c55e' when sum(total_sales) > 10000000 then '#f59e0b' else '#ef4444' end" /%}
    {% measure value="sum(total_sales)" fmt="usd1m" /%}
{% /table %}

Attributes

Allowed values:

  • left
  • center
  • right
Whether to allow content in this dimension column to wrap across multiple lines URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Whether to hide this column from the table display. Hidden columns are still included in queries and can be referenced by other columns. Whether to render the dimension value as HTML Image display options (used when image prop is set)

Attributes:

  • height: number - Height of the image in pixels
  • width: number - Width of the image in pixels
  • alt: string - Alt text for the image
  • hide_label: boolean - Whether to hide the text label and show only the image
Column name or SQL expression containing the image URL for this dimension Column name or SQL expression containing the domain to look up a company logo for this dimension Logo display options (used when logo prop is set)

Example:

text
logo_options={
  size = "sm"
  grayscale = true
  hide_label = true
}

Attributes:

  • size: string - Logo size: sm, base, lg, xl
    • Allowed values:
      • sm
      • base
      • lg
      • xl
  • grayscale: boolean - Display logo in grayscale
  • hide_label: boolean - Whether to hide the text label and show only the logo
Column name or SQL expression containing the URL for linking this dimension Static text to use as the link label instead of the cell content Whether to open the link in a new tab Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
Format code for displaying dimension values (e.g., "yyyy" for years, "mmm" for months) Sort direction for this dimension column. When specified, the table will be sorted by this column.

Allowed values:

  • asc
  • desc
Group name for this column. Columns with matching group names will be visually grouped under a shared header. Whether to repeat this dimension value on every row. When true, the value is displayed on every row even when it is the same as the row above. Overrides the table-level repeat_values setting for this dimension. SQL expression that returns color values for each row. Used to conditionally color dimension cells based on data (e.g., "case when count(*) > 0 then '#22c55e' else null end").

Allowed Parents


Components Dimension Grid (`docs/components/dimension_grid.mdx`)


title: Dimension Grid keywords: ["facet filter","dimension filter","multi-select grid"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% dimension_grid
    id="product_filter"
    data="demo.daily_orders"
/%}

Examples

Basic Usage

liquid
{% dimension_grid
    id="product_filter"
    data="demo.daily_orders"
/%}

With Explicit Dimensions and Metric

liquid
{% dimension_grid
    id="sales_filter"
    data="orders"
    dimensions=["category", "region"]
    metric="sum(sales)"
    fmt="usd"
    limit=5
/%}

Using Filter in Query

liquid
{% dimension_grid id="order_filter" data="orders" /%}

```sql filtered_orders
select * from orders
where {{order_filter.filter}}
```

Attributes

The id of the dimension grid to use in a `filters` prop Name of the table to query Array of column names to display as dimensions. If not provided, auto-detects string columns. SQL aggregation expression (default: count(*)) Label displayed above the metric values Format code for the metric values (e.g., "num0", "usd", "pct1"). See [Value Formatting](/core-concepts/value-formatting) for available formats. Maximum number of values to show per dimension (default: 10) Allow multiple selections per dimension (default: true) Array of filter IDs to apply when querying dimension values SQL WHERE clause to filter data Title displayed above the dimension grid Subtitle displayed below the title Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Set the width of this component (in percent) relative to the page width

Using the Filter Variable

Reference this filter using {{filter_id}}. The value returned depends on where you use it.

Context Default Property No Selection Result

Available Properties

You can also access specific properties using {{filter_id.property}}:

.filter

Returns a complete SQL filter expression combining all dimension selections. Returns true when no values are selected.

liquid
{% dimension_grid id="dim_filter" data="orders" /%}

```sql filtered_orders
select * from orders
where {{dim_filter.filter}}
```

.selected

Returns an object with dimension names as keys and selected values as arrays. Useful for accessing individual dimension selections.

liquid
{% dimension_grid id="dim_filter" data="orders" dimensions=["category", "region"] /%}

Selected categories: {{dim_filter.category}}
Selected regions: {{dim_filter.region}}

.literal

Returns a human-readable summary of all selections.

liquid
{% dimension_grid id="dim_filter" data="orders" /%}

Active filters: {{dim_filter.literal}}

Components Download (`docs/components/download.mdx`)


title: Download

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% download data="demo.daily_orders" /%}

Examples

Basic Usage

liquid
{% download data="demo.daily_orders" /%}

Custom Label and Filename

liquid
{% download
  data="demo.daily_orders"
  label="Export Orders"
  filename="daily_orders_export"
/%}

With Variant

liquid
{% download
  data="demo.daily_orders"
  label="Export Data"
  variant="primary"
/%}

With Large Limit

liquid
{% download
  data="demo.daily_orders"
  label="Download Recent Orders"
  limit=50000
/%}

Attributes

Table or view to download Text displayed on the download button Name of the downloaded file (without extension) Button style variant

Allowed values:

  • default
  • primary
  • destructive
  • secondary
  • ghost
  • link
IDs of filters to apply to the query Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results

Components Dropdown (`docs/components/dropdown.mdx`)


title: Dropdown keywords: ["cascading","linked","dependent","hierarchical","filter","select","relevant values"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}

Examples

Using `filters`

liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}

Using `where`

liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    where="category = {{category_filter}}"
    date_grain="month"
/%}

Using Inline SQL

liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

```sql filtered_orders
select * from demo.daily_orders
where category = {{category_filter}}
```

{% table data="filtered_orders" /%}

Using `date_range`

liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
    date_range={
        date="date"
        range="last 12 months"
    }
/%}

Cascading Dropdowns (Linked Filters)

liquid
{% dropdown
    id="category"
    data="demo.order_details"
    value_column="category"
    title="Category"
/%}

{% dropdown
    id="item"
    data="demo.order_details"
    value_column="item_name"
    title="Item"
    filters=["category"]
/%}

{% table
    data="demo.order_details"
    filters=["category", "item"]
/%}

Attributes

The id of the dropdown to be used in a `filters` prop Name of the table to query Array of filter IDs to apply when querying for dropdown options. Use this to create cascading/linked dropdowns where selecting a value in one dropdown narrows the available options in this dropdown. Column name to use as the value for each option, and the column to filter by when this dropdown's `id` is used in the `filters` prop of a chart Column name to use as the label for each option List of options to display in the dropdown Text displayed above the dropdown Information tooltip text URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Icon to display in the dropdown trigger

Allowed values:

  • trending-up
  • trending-down
  • clock
  • calendar
  • check
  • x
  • info
  • alert-circle
  • help-circle
  • eye
  • eye-off
  • user
  • users
  • settings
  • cog
  • plus
  • minus
  • up
  • down
  • right
  • left
  • star
  • heart
  • search
  • file
  • file-text
  • home
  • mail
  • filter
  • share
  • bell
  • trash
  • credit-card
  • globe
  • key
  • croissant
  • map
  • rotate
  • rewind
  • bank
  • receipt
  • activity
  • chart-column
  • chart-pie
  • chart-no-axes-combined
  • goal
  • rocket
  • trophy
  • apple
  • cookie
  • donut
  • beef
  • cake
  • soup
  • utensils
  • milk
  • nut
  • pyramid
  • triangle
  • arrow-down
  • arrow-left
  • arrow-right
  • arrow-up
  • chevron-down
  • chevron-left
  • chevron-right
  • chevron-up
  • chevrons-down
  • chevrons-left
  • chevrons-right
  • chevrons-up
  • menu
  • external-link
  • check-circle
  • x-circle
  • edit
  • trash-2
  • copy
  • save
  • download
  • upload
  • send
  • refresh
  • redo
  • undo
  • folder
  • folder-open
  • image
  • file-image
  • user-plus
  • user-minus
  • user-check
  • lock
  • unlock
  • log-in
  • log-out
  • message-square
  • message-circle
  • phone
  • phone-call
  • bell-off
  • video
  • video-off
  • play
  • pause
  • stop
  • skip-back
  • skip-forward
  • volume
  • volume-1
  • volume-2
  • volume-off
  • volume-x
  • bookmark
  • tag
  • link
  • unlink
  • share-2
  • alert-triangle
  • loader
  • more-vertical
  • more-horizontal
  • grid
  • list
  • maximize
  • minimize
  • zoom-in
  • zoom-out
  • thumbs-up
  • thumbs-down
  • shopping-cart
  • dollar-sign
  • camera
  • printer
  • monitor
  • smartphone
  • laptop
  • calculator
  • cloud-sun-rain
  • sun-snow
  • thermometer-sun
  • thermometer-snowflake
  • cloudy
  • cloud-rain-wind
  • cloud-rain
  • wind
  • sun
  • cloud-snow
  • thermometer
  • cloud-drizzle
  • cloud-sun
  • cloud
  • cloud-lightning
  • snowflake
  • flame
  • atom
  • fuel
  • magnet
  • factory
  • tree-deciduous
  • waypoints
  • plug
  • dam
  • battery
Initial selected value(s) Automatically select the first option when the component loads For a multi-select dropdown, pre-selects the first N options (after `order` is applied) when the component loads. Generalizes `select_first`. Does not limit the option list and has no effect when `multiple=false`. Placeholder text displayed when no value is selected Includes a search input within the dropdown menu Allows multiple selections Includes a clear button to unselect the selected value(s) Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Set the width of this component (in percent) relative to the page width

Using the Filter Variable

Reference this filter using {{filter_id}}. The value returned depends on where you use it.

The examples below show values for three scenarios:

  • No selection
  • Single select: "Electronics" selected
  • Multi select: "Sports" and "Home" selected (when multiple=true)
Context Default Property No Selection Single Select Multi Select
Inline SQL query .selected '' 'Electronics' ('Sports', 'Home')
where attribute .selected '' 'Electronics' ('Sports', 'Home')
Text / Markdown .literal Electronics Sports, Home

Available Properties

You can also access specific properties using {{filter_id.property}}:

.filter

Returns a complete SQL filter expression ready to use in WHERE clauses. Returns true when no value is selected.

liquid
{% dropdown id="category_filter" data="products" value_column="category" /%}

```sql filtered_products
select * from products
where {{category_filter.filter}}
```
No Selection Single Select Multi Select
true category = 'Electronics' category IN ('Sports', 'Home')

.selected

Returns the selected value(s) wrapped in quotes, suitable for SQL comparisons. Returns an empty string when no value is selected.

liquid
{% dropdown id="category_filter" data="products" value_column="category" /%}

```sql products_by_category
select * from products
where category = {{category_filter.selected}}
```
No Selection Single Select Multi Select
'' 'Electronics' ('Sports', 'Home')

.literal

Returns the raw unescaped selected value(s), useful for display in text or dynamic column selection.

liquid
{% dropdown id="sort_column" data="products" value_column="column_name" /%}

```sql dynamic_sort
select * from products
order by {{sort_column.literal}}
```
No Selection Single Select Multi Select
`` Electronics Sports, Home

.label

Returns the display label for the selected option(s). Falls back to the value if no label is defined.

liquid
{% dropdown id="category_filter" %}
    {% option value="Electronics" label="Electronics" /%}
    {% option value="Sports" label="Sports" /%}
    {% option value="Home" label="Home" /%}
{% /dropdown %}

Selected: {{category_filter.label}}
No Selection Single Select Multi Select
`` Electronics Sports, Home

.fmt

Returns the format string associated with the selected option. For multiple selections, returns the first format.

liquid
{% dropdown id="metric_selector" %}
    {% option value="revenue" label="Revenue" fmt="usd" /%}
    {% option value="growth_rate" label="Growth Rate" fmt="pct1" /%}
{% /dropdown %}

{% big_value data={metrics} value=value fmt={{metric_selector.fmt}} /%}
No Selection Single Select Multi Select
`` usd usd

Allowed Children


Components Else (`docs/components/else.mdx`)


title: Else

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% if data="demo.daily_orders" %}
	If Content
{% /if %}
{% else %}
	Else Content
{% /else %}

Examples

Basic Usage

liquid
{% if data="demo.daily_orders" %}
	If Content
{% /if %}
{% else %}
	Else Content
{% /else %}

Attributes

This component has no attributes.


Components Else If (`docs/components/else_if.mdx`)


title: Else If

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% if data="demo.daily_orders" condition="no_rows" %}
	If Content
{% /if %}
{% else_if data="demo.daily_orders" %}
	Else If Content
{% /else_if %}

Examples

Basic Usage

liquid
{% if data="demo.daily_orders" condition="no_rows" %}
	If Content
{% /if %}
{% else_if data="demo.daily_orders" %}
	Else If Content
{% /else_if %}

Attributes

Table or view to query IDs of filters to apply to the query Set to "no_rows" to render children only if the query returns no rows. Set to "has_rows" (or omit) to render if query returns rows.

Allowed values:

  • no_rows
  • has_rows
Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results

Components Fence (`docs/components/fence.mdx`)


title: Fence

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
```language query_name
  content
```

Examples

Basic Usage

liquid
```language query_name
  content
```

Define a SQL query

liquid
```sql electronics_orders
  SELECT * FROM demo.daily_orders WHERE category = 'Electronics'
```


{% table data="electronics_orders" /%}

Attributes

The language of the code block The content of the code block Optional name for the code block. If provided and language is "sql", this will register the query as an inline query that can be used by other components. Inline queries must be defined at the top level of the page, not inside other components (e.g. tabs, accordion, details). Set the width of this component (in percent) relative to the page width

Components File (`docs/components/file.mdx`)


title: File keywords: ["attachment","download","document","pdf","excel","csv","upload","asset"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% file
    url="https://files.example.com/reports/q3-board-deck.pdf"
    name="Q3 Board Deck.pdf"
    date="2026-09-29"
/%}

Examples

Basic Usage

liquid
{% file
    url="https://files.example.com/reports/q3-board-deck.pdf"
    name="Q3 Board Deck.pdf"
    date="2026-09-29"
/%}

Uploaded File

liquid
{% file
    url="evd_org_01ABC/k7Xq2mB9.xlsx"
    name="Regional Sales Model.xlsx"
    date="2026-09-29"
/%}

Attributes

The upload alias returned when a file is dropped into the editor (evd_...), or an external URL to link to. Display name for the file. Defaults to the filename from the URL. File type label shown on the card (e.g. PDF, Excel). Inferred from the file extension when omitted. Date shown on the card, e.g. the upload date. Accepts YYYY-MM-DD, an ISO timestamp, or free text. Set the width of this component (in percent) relative to the page width

Components Filter Bar (`docs/components/filter_bar.mdx`)


title: Filter Bar

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% filter_bar %}
  ...
{% /filter_bar %}

Attributes

This component has no attributes.

Allowed Children


Components Funnel Chart (`docs/components/funnel_chart.mdx`)


title: Funnel Chart keywords: ["funnel","conversion funnel","pipeline"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
/%}

Examples

Basic Usage

liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
/%}

Funnel Chart with Custom Styling

liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
    align="left"
    label_position="outside"
    gap=5
    title="Styled Funnel"
/%}

Funnel Chart with Custom Colors

liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
    chart_options={
        color_palette = ["#0d0887", "#6300a7", "#a62098", "#d5546e", "#f68d45", "#fcd225", "#f0f921"]
    }
/%}

Attributes

Name of the table to query. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Column name for funnel stages/categories Column name for values. Omit when using `metric`. Title to display above the chart Subtitle to display below the title Information tooltip text (can only be used with title) URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Format for values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Show a legend above the chart (stages are labeled directly on the funnel by default) Position of the legend (top or bottom)

Allowed values:

  • top
  • bottom
Label position: auto places labels inside each stage, moving them beside stages that are too narrow; outside places all labels in a rail beside the chart (left of the chart unless the funnel is right-aligned)

Allowed values:

  • auto
  • inside
  • outside
  • center
Chart configuration options

Example:

text
chart_options={
  color_palette = ["value1", "value2"]
}

Attributes:

  • color_palette: array of strings
Funnel alignment

Allowed values:

  • center
  • left
  • right
Show percentages relative to first stage Minimum size of funnel stages Maximum size of funnel stages Gap between funnel stages in pixels Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

Example:

text
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
}

Components Heat Grid (`docs/components/heat_grid.mdx`)


title: Heat Grid keywords: ["metric grid","color grid","conditional formatting"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% heat_grid
  data="appointments"
  dimension="province"
  value="avg(wait_time)"
  thresholds=[60, 90]
  units="MIN"
  lower_is_better=true
/%}

Examples

Basic Usage

liquid
{% heat_grid
  data="appointments"
  dimension="province"
  value="avg(wait_time)"
  thresholds=[60, 90]
  units="MIN"
  lower_is_better=true
/%}

Attributes

Table or view to query. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Column for cell labels (e.g., province) SQL aggregation expression for the metric (e.g., avg(wait_time)). Omit when using `metric`. Two numeric thresholds creating 3 color zones: [low, high]. Values below low are zone 1, between low and high are zone 2, at or above high are zone 3. Units label shown below the value in each cell (e.g., "MIN") Format code for the metric value. See [Value Formatting](/core-concepts/value-formatting) for available formats. Component title If true, low values are green and high values are red. Default (false) means high values are green. If true, removes gaps and borders between cells and applies a single border radius to the outer grid. IDs of filters to apply to the query Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width

Components Heatmap (`docs/components/heatmap.mdx`)


title: Heatmap keywords: ["heat map","matrix chart","color matrix"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% heatmap
    data="demo.daily_orders"
    x="date"
    x_date_grain="year"
    y="category"
    value="sum(total_sales)"
/%}

Examples

Basic Usage

liquid
{% heatmap
    data="demo.daily_orders"
    x="date"
    x_date_grain="year"
    y="category"
    value="sum(total_sales)"
/%}

With Custom Colors

liquid
{% heatmap
    data="demo.daily_orders"
    x="date"
    x_date_grain="year"
    y="category"
    value="sum(total_sales)"
    title="Sales Intensity by Year and Category"
    chart_options={
        color_scale = ["#f7fafc", "#e2e8f0", "#cbd5e0", "#a0aec0", "#718096", "#4a5568", "#2d3748"]
    }
/%}

Attributes

Name of the table to query. Omit when using `metric`. Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
Column name for x-axis categories Column name for y-axis categories Title to display for the x-axis Title to display for the y-axis Column name for cell values. Omit when using `metric`. Title to display above the chart Subtitle to display below the title Info text to display in a tooltip next to the title. Can only be used with the title prop. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Format for values (defaults to `num`, or the metric format in metric mode). See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for x axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Sort order for x axis categories (asc or desc)

Allowed values:

  • asc
  • desc
Sort order for y axis categories (asc or desc)

Allowed values:

  • asc
  • desc
Sort categories by total value (asc or desc). Applies to the first axis without explicit sort.

Allowed values:

  • asc
  • desc
Show color scale legend Show borders around heatmap cells Chart configuration options

Example:

text
chart_options={
  color_scale = ["value1", "value2"]
  color_palette = ["value1", "value2"]
}

Attributes:

  • color_scale: array of strings - Array of hex colors for the heatmap gradient. A single-color array auto-expands to [background, color].
  • color_palette: array of strings - Deprecated. Use color_scale.
Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples. Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

Example:

text
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
}

Components Heatmap Layer (`docs/components/heatmap_layer.mdx`)


title: Heatmap Layer

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% map %}
    {% heatmap_layer
        data="events"
        lat="latitude"
        lng="longitude"
    /%}
{% /map %}

Examples

Basic Heatmap

liquid
{% map %}
    {% heatmap_layer
        data="events"
        lat="latitude"
        lng="longitude"
    /%}
{% /map %}

Weighted Heatmap

liquid
{% map %}
    {% heatmap_layer
        data="sales"
        lat="latitude"
        lng="longitude"
        weight="sum(revenue)"
    /%}
{% /map %}

Custom Color Palette

liquid
{% map %}
    {% heatmap_layer
        data="incidents"
        lat="latitude"
        lng="longitude"
        color_scale=["#ffffb2", "#fecc5c", "#fd8d3c", "#f03b20", "#bd0026"]
    /%}
{% /map %}

Adjusted Radius and Intensity

liquid
{% map %}
    {% heatmap_layer
        data="visits"
        lat="latitude"
        lng="longitude"
        weight="visit_count"
        radius=50
        intensity=2
    /%}
{% /map %}

Attributes

Name of the table to query Array of filter IDs to apply Column name for latitude values Column name for longitude values Column or expression for weighting points in the heatmap (e.g., "sum(sales)"). Higher values create more intense heat Base radius of influence for each point in pixels (adjusts with zoom) Intensity multiplier for the heatmap. Higher values create more pronounced heat Opacity of the heatmap layer (0-1) Array of colors for the heatmap gradient, from lowest to highest density. A single-color array auto-expands to [background, color]. Defaults to the theme color scale. Deprecated. Use `color_scale`. Zoom range [min, max] where this layer is visible (e.g., [0, 8] shows layer from zoom 0 to 8) Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results

Allowed Parents


Components Hidden In Print (`docs/components/hidden_in_print.mdx`)


title: Hidden In Print

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

Examples

Hidden in Print

liquid
{% hidden_in_print %}
This content is hidden when printed.
{% /hidden_in_print %}

Attributes

This component has no attributes.


Components Histogram (`docs/components/histogram.mdx`)


title: Histogram keywords: ["distribution","frequency chart","frequency distribution"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% histogram
    data="demo.daily_orders"
    value="transactions"
    bin_count=30
/%}

Examples

Basic Usage

liquid
{% histogram
    data="demo.daily_orders"
    value="transactions"
    bin_count=30
/%}

Attributes

Name of the table to query SQL expression for the values to create histogram for Column name to group data by series Chart configuration options

Example:

text
chart_options={
  color_palette = ["value1", "value2"]
}

Attributes:

  • color_palette: array of strings
Number of bins for the histogram (takes precedence over bin_width) Width of each bin (ignored if bin_count is specified) Format for the column values displayed in bin ranges. See [Value Formatting](/core-concepts/value-formatting) for available formats. IDs of filters to apply to the query Title to display above the histogram Subtitle to display below the title Info text to display in a tooltip next to the title. Can only be used with the title prop. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Show legend Position of the legend (top or bottom)

Allowed values:

  • top
  • bottom
Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

Example:

text
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

Example:

text
echarts_series_options={
    itemStyle={ borderRadius=8 }
}

Components Horizontal Bar Chart (`docs/components/horizontal_bar_chart.mdx`)


title: Horizontal Bar Chart keywords: ["horizontal bar graph","row chart"]

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

liquid
{% horizontal_bar_chart
	data="demo.daily_orders"
	y="category"
	x="sum(total_sales)"
/%}

Examples

Basic Usage

liquid
{% horizontal_bar_chart
	data="demo.daily_orders"
	y="category"
	x="sum(total_sales)"
/%}

Attributes

Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view. IDs of filters to apply to the query Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

Example:

text
date_range={
  range = "today"
  date = "string"
}

Attributes:

  • range: string - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    • Allowed values:
      • today
      • yesterday
      • last 7 days
      • last 30 days
      • last 3 months
      • last 6 months
      • last 12 months
      • previous week
      • previous month
      • previous quarter
      • previous year
      • this week
      • this month
      • this quarter
      • this year
      • next week
      • next month
      • next quarter
      • next year
      • week to date
      • month to date
      • quarter to date
      • year to date
      • all time
  • date: string - Date column to filter on. Required when the data has multiple date columns.
Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

Allowed values:

  • day
  • week
  • month
  • quarter
  • year
  • hour
  • day of week
  • day of month
  • day of year
  • week of year
  • month of year
  • quarter of year
How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

Allowed values:

  • connect
  • gaps
  • zero
Column name for x-axis (value, extends horizontally) Format for x values. See [Value Formatting](/core-concepts/value-formatting) for available formats. Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats. Column name for series Column name for individual point labels displayed at the top of the tooltip Title to display above the component Subtitle to display below the title Information tooltip text (can only be used with title). Displays an info icon next to the title. URL to link the info text to (can only be used with info) Create a custom link title for the info link, placed after the info text (can only be used with info_link) Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component. Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead. Custom SQL HAVING condition to apply to the query after GROUP BY Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows. Column name(s) with optional direction (e.g. "column_name", "column_name desc") Custom SQL QUALIFY condition to filter windowed results Set the width of this component (in percent) relative to the page width Set a fixed height for the chart in pixels Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom Configure the y-axis

Example:

text
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}

Attributes:

  • title: string
  • title_position: string - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
    • Allowed values:
      • top
      • side
  • ticks: boolean
  • baseline: boolean
  • labels: boolean - Show/hide axis labels
  • gridlines: boolean - Show/hide gridlines
  • min: number - Minimum value for this axis (number for numeric axes, date string for date axes)
  • max: number - Maximum value for this axis (number for numeric axes, date string for date axes)
  • fit_to_data: boolean - Fit the axis to the data instead of including 0
  • interval: number - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
Configure the x-axis

Example:

text
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}

Attributes:

  • title: string
  • show_title: boolean - When true, renders the auto-derived axis title (the x column name) below the chart. Ignored when title is set explici