Skip to main content
A virtual view is created in the SQL Runner and lets other users reuse your custom SQL query in Lightdash. It gets listed in your Tables and can be used like the tables that come from your dbt project. A virtual view isn’t saved to or managed in your dbt project. If you expect to use the query regularly, write it back to dbt.

Create a virtual view

To create a virtual view from the SQL Runner, select the Create Virtual View option from the save drop-down.
SQL runner save menu with "Create virtual view" highlighted, beside "Save chart" and "Write back to dbt"
Your virtual view will appear in the list of Tables available to explore in Lightdash. Everyone in your team can use virtual views to build queries and charts just like they would any other Table.
The "Website sessions" virtual view listed under Virtual Views, then queried in the explorer as a bar chart by month
Virtual view columns only carry a reference and a type — each one becomes a plain dimension. Richer dimension configuration like urls or richText isn’t available on virtual views, and virtual views define no metrics; use custom metrics in the Explore view. A virtual view also can’t carry explore-level or field-level tags, so it’s invisible to any tag-scoped AI agent — only an agent with no tag restriction configured can see and query a virtual view. If you need live data with full dimension configuration, model the query in dbt instead: a model materialized as a view still queries live data and supports every dimension property. Each column’s type comes from the query result in the SQL Runner. Only date and timestamp columns get time intervals (day, week, month, quarter and year) and respond to dashboard date zoom. If a date column comes back as text, for example from a TO_CHAR expression, cast it in the view’s SQL, such as CAST(order_date AS DATE).

Edit or delete a virtual view

To edit a virtual view, you need to open it in the Explorer, then beside the name, there’s a three-dot-menu where you can choose to edit or delete the virtual view.
A virtual view page with the three-dot menu open, showing "Edit virtual view" and "Delete"
Any changes you make will affect all existing content built using the virtual view.

Manage virtual views as code

You can manage virtual views as code alongside your charts and dashboards with the Lightdash CLI. This is useful when you want to review virtual-view changes in a pull request, promote the same SQL across projects (for example from a staging to a production Lightdash instance), or template a set of virtual views for reuse. Virtual views are opt-in — a bare lightdash download does not pull them, and a bare lightdash upload does not push them. You have to ask for them explicitly with --include-virtual-views or --virtual-views <slug>.

Download virtual views

Use --include-virtual-views to download every virtual view in the project, or --virtual-views <slug> to download specific ones:
Each virtual view is written to lightdash/virtual-views/<slug>.yml. To skip virtual views when a filter is otherwise selecting them, add --skip-virtual-views.

Virtual view YAML

Virtual views serialize to a portable YAML contract keyed by a project-scoped slug (the immutable explore name used by any charts, dashboards, or joined models that reference the view). The name is the mutable display label shown in the UI.
Virtual view YAML example

Upload virtual views

Use --virtual-views <slug> on lightdash upload to target specific views, or run a bare upload (without any content filters) to include every virtual view in lightdash/virtual-views/.
The CLI compares each file against the current cached version of the view and reports one of:
  • created — no view with this slug existed yet.
  • updated — the view existed and one or more fields changed.
  • skipped — the file is byte-equivalent to the current view, so nothing is sent.
If the same slug already exists as a non-virtual explore (for example, a dbt model), the upload is rejected — Lightdash won’t adopt a dbt-managed explore into virtual-view storage.

Validation errors

Uploads fail fast with a ParameterError when the YAML isn’t a valid virtual view. Common causes:
  • slug is empty, contains slashes, or isn’t canonical snake_case.
  • name or sql is empty.
  • columns is empty, contains duplicate or blank reference values, or uses an unknown type.
  • parameters includes keys that the sql never references.
  • contentType isn’t virtual_view or version isn’t the supported version.
Fix the YAML locally and re-run lightdash upload.

Destructive changes and --force

Removing a column or changing its type is a destructive change — any charts or dashboards that reference the removed or retyped column will break. To protect against accidental breakage, the CLI rejects destructive column changes by default and lists the offending columns in the error. Re-run the upload with --force when the change is intentional:
--force also allows replacing a virtual view whose cached state can no longer be represented as YAML (for example, a legacy view with non-subquery SQL).

Permissions

Virtual view download and upload reuse the same content-as-code scopes as charts and dashboards:
  • view:ContentAsCode is required to download virtual views.
  • manage:ContentAsCode is required to upload virtual views. Uploads also check the virtual-view edit permissions the UI enforces, so the CLI, API, and app stay in lockstep.