Sources¶
Sources define where a board reads data from. Most projects use one warehouse connection for SQL queries, but a board can also read files, HTTP endpoints, inline values, dbt models, or MetricFlow metrics.
Connection sources are defined once, in the project's root dbt_charts.yml, as a
named sources: registry. A board (or charts/meta.yaml) never defines a
connection inline — it only references a source by name:
# dbt_charts.yml sources: analytics: type: dbt_profile profile: my_dbt_project target: dev
source: analytics # References the "analytics" source above queries: sales: SELECT * FROM orders
Every sources: block on this page belongs in dbt_charts.yml, not in a board.
A board's own source: field always holds a name (or, for a single colocated
data file, an inline path — see Inline File Sources),
never a connection definition.
dbt charts sources: are connection definitions. They are separate from dbt
sources: resources, which document raw tables inside a dbt project. If you are
setting up dbt source tables, use dbt's
source properties
reference.
Source Types¶
For warehouse-backed SQL, dbt charts uses dbt-compatible connection settings. In
most dbt projects, use type: dbt_profile and let dbt own the adapter-specific
credentials. Direct warehouse source types use the same field names as dbt
profiles, but they are flat because boards read data; they do not build dbt
models.
You do not need profiles.yml for direct sources such as postgres,
snowflake, bigquery, duckdb, or sqlite. dbt charts uses the direct source
block as the connection config. The dbt links below are still useful because
they document the same adapter credential fields.
| Source | dbt charts setup | Credential fields / setup |
|---|---|---|
| Existing dbt project | type: dbt_profile |
dbt profiles.yml |
| BigQuery | type: bigquery |
BigQuery connection |
| DuckDB | type: duckdb |
DuckDB connection |
| Postgres | type: postgres |
Postgres connection |
| Redshift | type: redshift |
Redshift connection |
| Snowflake | type: snowflake |
Snowflake connection |
| MySQL / MariaDB | type: mysql |
dbt community adapter; start with supported data platforms |
| SQL Server | type: dbt_profile |
dbt-sqlserver connection |
| Trino / Presto / Starburst | type: trino |
Trino connection (install dbt-charts[trino]) |
| Athena | type: dbt_profile |
dbt-athena connection |
| SQLite | type: sqlite |
dbt charts direct source; no dbt setup |
| Databricks | type: dbt_profile |
Databricks connection |
| Spark | type: dbt_profile |
Apache Spark connection |
| dbt models | sql query using ref() with a dbt profile source |
dbt profiles.yml |
| MetricFlow metrics | metricflow query with a dbt profile source |
MetricFlow |
| CSV files | type: csv |
Files and APIs |
| Parquet files | type: parquet |
Files and APIs |
| JSON files | type: json |
Files and APIs |
| HTTP endpoints | type: http query |
Files and APIs |
| Inline static data | type: values query |
No source setup |
dbt Profile Sources¶
dbt charts can either read your warehouse credentials from a dbt profile or accept a direct source definition with dbt-style field names.
Use dbt_profile when your project already has profiles.yml:
# dbt_charts.yml sources: analytics: type: dbt_profile profile: my_dbt_project target: dev
dbt charts resolves profiles.yml in this order:
profiles_diron the source configDBT_PROFILES_DIR- Project root, next to
dbt_charts.ymlordbt_project.yml ~/.dbt/profiles.yml
If none of those locations contains profiles.yml, dbt charts raises an error.
Who validates the target¶
profiles.yml is dbt's file, so dbt validates it — dbt charts applies no schema
of its own. Every field your installed dbt adapter accepts works, including
threads and dbt's canonical database: / schema: spelling for BigQuery
(project: / dataset: work too, exactly as in dbt). A field dbt requires but
your target omits is reported when the dashboard runs, naming the profile and
target.
The flip side: a misspelled key is not an error. dbt ignores keys it does not
recognise, so hostt: localhost is silently unused — by dbt charts and by
dbt run alike. If a connection behaves unexpectedly, check the spelling of your
target's fields.
This differs from the direct warehouse sources below, where dbt charts owns the schema and an unknown key is an error.
Direct Warehouse Sources¶
Direct warehouse sources are useful for small projects that do not share a dbt
project. This is the full connection config; no profiles.yml file is required.
For larger dbt projects, prefer type: dbt_profile.
Postgres¶
# dbt_charts.yml sources: analytics: type: postgres host: "{{ env_var('ANALYTICS_HOST') }}" port: 5432 dbname: analytics schema: public user: "{{ env_var('ANALYTICS_USER') }}" password: "{{ env_var('ANALYTICS_PASSWORD') }}"
DuckDB¶
# dbt_charts.yml sources: local_db: type: duckdb path: ./data/analytics.duckdb schema: crm
DuckDB sources are local-only. A .duckdb file is a version-coupled,
single-writer binary, so dbt charts Cloud does not read .duckdb files from
connected repositories. For Cloud, export the tables to Parquet or CSV and
register them as file sources instead.
SQLite¶
# dbt_charts.yml sources: local_sqlite: type: sqlite path: ./data/analytics.sqlite
Files and APIs¶
CSV, Parquet, JSON, and HTTP sources do not need dbt. They are simpler local dbt charts source definitions for examples, prototypes, and lightweight external data.
CSV¶
A CSV source is a namespace of relations. Each key under files: is a table
name; the value is the path to the CSV file relative to the project root.
# dbt_charts.yml sources: sales_csv: type: csv files: sales: assets/data/sales.csv
Then query it by name:
queries: sales: source: sales_csv sql: SELECT * FROM sales
A single source can expose multiple CSV files as separate tables:
# dbt_charts.yml sources: sales_data: type: csv files: orders: assets/data/orders.csv returns: assets/data/returns.csv
JSON¶
# dbt_charts.yml sources: product_json: type: json files: products: assets/data/products.json
queries: products: source: product_json sql: SELECT * FROM products
Parquet¶
# dbt_charts.yml sources: events: type: parquet files: events: assets/data/events.parquet
queries: event_counts: source: events sql: SELECT * FROM events
HTTP¶
Unlike SQL and file queries, an HTTP query is self-contained: set url: (and
optional headers:, method:, body:) directly on the query. It has no
source: field — there is no named registry entry to reference.
queries: forecast: type: http url: "https://api.example.com/forecast"
See Queries for the full HTTP query field reference.
Inline File Sources¶
A single CSV, JSON, or Parquet file that only one query reads doesn't need a
named registry entry — reference the file directly on source:, as a path
containing / or ending in a data-file extension:
queries: sales: source: ./data/sales.csv sql: SELECT * FROM sales
The path resolves relative to the board file's own directory. The table name is
the file's stem (sales.csv → table sales); a stem that isn't a valid SQL
identifier is a compile error rather than a silently sanitized name — rename
the file or use the named-registry form below. Only a single file is allowed
inline (no files: list); an inline file source is always materialized
straight from the file's git content.
Use the named-registry form (type: csv/json/parquet with a files: map
in dbt_charts.yml, above) instead when a file is shared across boards or a
source exposes more than one file as separate tables.
Source Defaults¶
Set source: on a board to make all queries in that board use a default source
by name. A charts/meta.yaml (or a directory's own meta.yaml) can set the
same field to default every board beneath it:
source: finance queries: monthly_revenue: sql: SELECT month, revenue FROM finance_revenue sales_pipeline: source: sales sql: SELECT stage, amount FROM sales_pipeline
Sources are resolved from most specific to broadest:
- Query-level
source: - Board-level
source: - The nearest ancestor
source:in thecharts/meta.yamlcascade
An unknown source name is a validation error.
Attribution¶
Every query dbt charts sends carries attribution so your warehouse's cost tracking can
tell a dbt charts query apart from ad-hoc human querying. On BigQuery it arrives as
job labels,
queryable as a real column in INFORMATION_SCHEMA.JOBS; on other warehouses it
arrives as a leading JSON comment on the query text.
dbt charts sets the engine half itself — you don't configure it:
| Label | Meaning |
|---|---|
app |
Always dbt-charts. The one key to filter on — dbt emits app=dbt under the same key, so one predicate covers both. |
dbt_charts_version |
The dct version that sent the query. |
dbt_charts_surface |
Which entry point: cli, serve, or cloud. |
dbt_charts_board |
The dashboard the query belongs to. |
dbt_charts_query |
The query's name within that dashboard. |
dbt_charts_target |
The dbt target, when the query names one. |
Where it lands, per warehouse¶
Only BigQuery stores the whole payload as structured key/value. Elsewhere dbt charts
fills the warehouse's own identity field so app is a column you can filter, and the
rest of the payload rides the query comment:
| Warehouse | Native field | Carries |
|---|---|---|
| BigQuery | job labels (JOBS.labels) |
everything, as key/value |
| Snowflake | QUERY_TAG |
app, version, surface — as JSON |
| Databricks | query tags | app, version, surface — as JSON |
| Trino | client_tags |
app, version, surface |
| Postgres | application_name |
dbt-charts |
| Redshift, DuckDB, SQLite | — | query comment only |
Setting the native field costs nothing: it travels with the connection, not with each
query. If you have already set query_tag, application_name, or client_tags
yourself, dbt charts leaves your value alone.
Redshift is deliberately left out: its query_group field routes WLM queues, so
writing it could move your queries to a different queue — too high a price for a label.
Your own labels¶
Add ownership labels with attribution: on a source. They apply to every
query against it:
# dbt_charts.yml sources: warehouse: type: bigquery project: my-gcp-project dataset: analytics attribution: team: architecture-analytics cost_center: data-platform
Keys and values must match BigQuery's label rules — keys [a-z][a-z0-9_-]{0,62},
values [a-z0-9_-]{0,63} — on every warehouse, so the same source config behaves
identically everywhere. A value that doesn't match is an error, not a silently
rewritten label. The dft_ prefix and the app key are reserved for the engine.
env_var() works here like anywhere else in a source:
# dbt_charts.yml sources: warehouse: type: bigquery project: my-gcp-project dataset: analytics attribution: env: "{{ env_var('DCT_ENV', 'dev') }}"
To find your dbt charts spend on BigQuery:
SELECT creation_time, total_bytes_billed, user_email
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE creation_date = CURRENT_DATE()
AND EXISTS (SELECT 1 FROM UNNEST(labels) l WHERE l.key = 'app' AND l.value = 'dataface')
This works whether the query ran under a service account or an individual developer's credentials.
Environment Variables¶
Use env_var() in source configuration to keep credentials out of YAML files:
# dbt_charts.yml sources: analytics: type: postgres host: "{{ env_var('DB_HOST', 'localhost') }}" user: "{{ env_var('DB_USER') }}" password: "{{ env_var('DB_PASSWORD') }}"
Store credentials in .env or your deployment environment:
Keep credentials out of boards
env_var() is for source configuration. Do not put secrets in board YAML,
query text, or rendered output.
Read-only Posture¶
dbt charts boards read data. They never intentionally write to your warehouse, but connection-level enforcement depends on the source type.
DuckDB and SQLite are opened with driver-level read-only settings. Every other warehouse should use credentials that can only read data. dbt charts also applies an in-process SQL allowlist before execution, but SELECT-only credentials are the warehouse-side defense.
| Warehouse | In-process enforcement | Recommended operator posture |
|---|---|---|
| DuckDB | Driver read-only mode | Handled by dbt charts |
| SQLite | Driver read-only URI mode | Handled by dbt charts |
| Postgres | SQL allowlist only | SELECT-only role |
| MySQL / MariaDB | SQL allowlist only | SELECT-only user |
| Snowflake | SQL allowlist only | SELECT-only role |
| BigQuery | SQL allowlist only | roles/bigquery.dataViewer or equivalent |
| Redshift | SQL allowlist only | SELECT-only IAM role or database user |
| dbt profile sources | Depends on adapter | SELECT-only profile credential |
File access from SQL¶
dct serve runs strictly read-only: author SQL cannot reach the filesystem or
network through DuckDB, so functions like read_csv(...), read_json_auto(...),
read_parquet(...), and httpfs are not available in query SQL. Point data at a
file source instead — declare it with type: csv, type: json, or type: parquet
and a files: mapping (see Files and APIs), then query the table
by name. dbt charts parses the file and loads it for querying without granting SQL
any file access.
Related¶
- Queries for the SQL, values, HTTP, MetricFlow, and schema query types (dbt models are queried as plain SQL via
ref(), not a separate query type) - MetricFlow for semantic-layer queries
- Quick Guide for the shortest syntax overview