Skip to content

dft render

Render a dashboard to SVG, HTML, PNG, PDF, JSON, YAML, or terminal output.

dft render [OPTIONS] FACE

Use "-" as the FACE argument to read YAML from stdin — useful for AI agents and shell pipelines that don't want to write a temp file.

Arguments

Argument Description
FACE Path to face YAML file, or "-" to read YAML from stdin. (required)

Options

Flag Description
--output PATH Output file path. Default: face name with extension. Use "-" to write to stdout.
--format TEXT Output format: svg, html, png, pdf, terminal, json, text, yaml, data. Default: svg.
--project-dir PATH Project directory for resolving relative paths.
--var KEY=VALUE Variable value (repeatable).
--no-cache Bypass all query caches and re-run from scratch.
--cache PATH Persist the query cache to this DuckDB file (created if absent). Default: in-memory, discarded when the process exits. Also settable via DFT_CACHE_PATH. Mutually exclusive with --no-cache.
--json-errors Emit errors as JSON to stdout instead of Rich panels. Success-path output is still controlled by --format.
--allow-chart-errors Allow per-chart runtime errors (missing columns, query failures) without exiting non-zero. Default: fail — see Warnings & CI behavior.
--fail-fast Stop immediately on the first render failure. Default: continue rendering remaining faces, exit 1 at the end.
--max-workers INT Maximum parallel query workers (default: 8, from config). Also settable via DFT_MAX_WORKERS. Effective only for external warehouse executors — DuckDB serializes access internally regardless of this setting.
--no-warnings Suppress warning output to stderr. Warnings still appear in --format json output so agents and consumers always see them.
--ignore-warning CODE Suppress a specific render-time warning code (repeatable). Suppressed warnings move to suppressed_warnings in --format json output. A code that isn't a registered WARN-* code exits 1.
--print0, -0 Delimit produced output paths with NUL (\0) instead of newline, for safe piping to xargs -0 when paths contain spaces.

Warnings & CI behavior

By default, dft render exits 1 if any chart has a runtime error — a missing column, a failed query, an unresolvable reference. This is the CI-safe contract: a broken chart fails the build instead of shipping a silently-partial dashboard.

For live previews and agent iteration, where a partial render is useful feedback rather than a failure, pass --allow-chart-errors to keep exit code 0 and render whatever charts succeeded.

dft render faces/sales.yml --allow-chart-errors

Render-time warnings (as opposed to chart errors) print to stderr by default and don't affect the exit code. Use --no-warnings to silence them, or --ignore-warning CODE to suppress one specific code (repeatable):

dft render faces/sales.yml --ignore-warning WARN-REDUNDANT-ENCODING

dft docs warnings lists every registered warning code; dft docs warnings <CODE> explains one.

Output formats

Format Purpose
svg (default) Scalable vector graphics — embedding, presentations
html Interactive HTML page with embedded charts
png Raster image — screenshots, thumbnails
pdf PDF document — reports, printing
terminal ASCII/Unicode charts printed to stdout
json Post-execution resolved layout + data
text Plain text rendering
yaml Compiled face YAML
data Flat JSON: queries keyed by name, charts keyed by slug

Examples

Static export

dft render faces/sales.yml                         # → faces/sales.svg
dft render faces/sales.yml --format html
dft render faces/sales.yml --format png
dft render faces/sales.yml --format pdf
dft render faces/sales.yml --output sales.svg

Variables

dft render faces/sales.yml \
  --var region=West \
  --var category=Electronics

Terminal preview

dft render faces/sales.yml --format terminal
================================================================================
 Sales Dashboard
================================================================================

Daily Revenue Trend
      ┌────────────────────────────────────────────────────────────┐
2400.0┤    ▗                ▟                                 ▗    │
2141.7┤   ▄▀▖              ▞ ▚               ▞▖              ▄▀▖   │
...

Terminal format writes directly to stdout. Use shell redirection to save:

dft render faces/sales.yml --format terminal > dashboard.txt

Reading YAML from stdin

dft render - --format terminal --project-dir . <<'EOF'
charts:
  revenue:
    query:
      source: ./data/sales.csv
      sql: SELECT * FROM sales
    type: bar
    x: region
    y: revenue
rows:
  - revenue
EOF

There's no type: csv / file: query shape — a file is referenced with source: pointing at the path, and the table name is the file's stem (sales.csvsales). See Inline File Sources.

echo 'charts: {revenue: {query: {source: ./data/sales.csv, sql: "SELECT * FROM sales"}, type: bar, x: region, y: revenue}}
rows: [revenue]' | dft render - --format terminal
cat generated_dashboard.yml | dft render - --output - > output.svg

--project-dir controls where relative file paths (CSVs, etc.) are resolved from when reading stdin. Defaults to cwd.

CI artifact generation

for face in faces/*.yml; do
  dft render "$face" \
    --format html \
    --output "dist/$(basename "$face" .yml).html"
done

Inspect resolved layout for debugging

dft render faces/sales.yml --format json > sales_resolved.json

Extract the underlying data

--format data drops the layout and returns two flat maps: queries keyed by query name, and charts keyed by slug. Each query carries its SQL and exactly one copy of its rows; charts reference their query by name rather than embedding the rows, so charts sharing a query do not repeat the result set.

dft render faces/sales.yml --format data > sales_data.json
{
  "id": "sales",
  "title": "Sales",
  "queries": {
    "monthly": {
      "type": "sql",
      "sql": "SELECT month, SUM(revenue) AS revenue FROM orders GROUP BY 1",
      "rows": [{"month": "2026-01", "revenue": 48210}]
    }
  },
  "charts": {
    "revenue_trend": {
      "type": "line",
      "query": "monthly",
      "title": "Revenue Trend",
      "x": "month",
      "y": "revenue"
    }
  }
}

SQL is emitted as compiled — Jinja variable references are left uninterpolated, and the values they resolve to appear under variables. A row cap declares itself on the affected query as rows_truncated: {head, tail, total}; rows are never dropped silently.

By default, links inside rendered HTML and SVG files are root-relative (/org/proj/d/slug/). That works when the file is served from the same host, but breaks when it is opened as a standalone file (file://) or embedded cross-origin.

Set public_url in your dataface.yml to make export links fully-qualified:

public_url: "https://dashboards.example.com"

With that setting, dft render produces https://dashboards.example.com/d/slug/ instead of /d/slug/. Leave it unset (the default, empty string) for local use.

Caching

The query-result cache is in-memory by default — it lives only for the duration of the dft render process and is discarded when it exits. Pass --no-cache to skip caching entirely and force re-execution from scratch.

To persist the cache across separate dft render invocations (e.g. a script that regenerates dashboards repeatedly), pass --cache <path>:

dft render faces/sales.yml --cache cache.duckdb
dft render faces/sales.yml --cache cache.duckdb   # reuses cached query results

The file is created automatically if it doesn't exist yet. --cache also reads from the DFT_CACHE_PATH environment variable, so a script can export DFT_CACHE_PATH=cache.duckdb once instead of repeating the flag. A persistent cache file supports only one writer at a time — don't point two concurrently running dft render/dft serve processes at the same file. --cache and --no-cache are mutually exclusive.

Error output

For programmatic consumers (agents, CI), --json-errors emits machine-readable errors to stdout instead of formatted Rich panels:

dft render faces/sales.yml --json-errors --format svg

The success-path output (the SVG, HTML, etc.) is still controlled by --format; only error paths change shape.

  • dft serve — interactive preview with auto-reload
  • dft validate — fast pre-render validation
  • dft query — inspect one named query without rendering the whole face