+1 (726) 227-2971

LookML Dashboards as Code: Versioning the Dashboards Your Business Cannot Afford to Break

Every Looker project reaches the same moment. A dashboard that started as one analyst's saved view becomes the thing the executive team opens every Monday, and now nobody is allowed to touch it. It lives in a folder, it has no history, it cannot be reviewed, and when someone renames a field in LookML it quietly breaks in production.

The fix is to stop treating that dashboard as content and start treating it as code. Looker supports LookML dashboards — dashboards defined in .dashboard.lkml files, versioned in Git, reviewed in pull requests, and deployed with the rest of your model. This tutorial covers when to use them, how to write one, how to convert an existing user-defined dashboard without retyping it, and how to keep the whole estate from rotting using the Content Validator.

User-defined vs LookML dashboards

Looker has two kinds of dashboard and they behave very differently.

User-defined dashboards (UDDs) are created in the UI, stored in Looker's internal database, and edited by anyone with access to the folder. They support drag-and-drop layout, dashboard-level editing by business users, and they are the right answer for exploratory or team-owned content.

LookML dashboards are text files in your project. They are:

  • Version controlled. Every change is a commit with an author, a diff, and a reviewer.
  • Promotable. Dev mode → pull request → production, the same path as your models.
  • Reproducible across instances. The same file can define the same dashboard on dev, staging, and production instances.
  • Refactor-safe. When you rename a dimension, the Content Validator can find and fix references inside LookML dashboards in the same commit.

The trade-off is real: business users cannot edit a LookML dashboard in place. They can only "Save as" a copy, which becomes a UDD. That constraint is a feature for board-level reporting and a nuisance for a marketing team iterating weekly.

A useful rule of thumb from our client work: if breaking the dashboard would trigger a phone call from someone senior, it belongs in LookML. Everything else can stay a UDD.

Your first LookML dashboard file

Create a file in your project named executive_overview.dashboard.lkml. The extension matters — Looker only parses dashboards from files ending in .dashboard.lkml.

- dashboard: executive_overview
  title: Executive Overview
  layout: newspaper
  preferred_viewer: dashboards-next
  description: "Company-level revenue and order health. Owned by the data team."
  refresh: 1 hour

  filters:
  - name: date_range
    title: "Date Range"
    type: field_filter
    default_value: "30 days"
    allow_multiple_values: true
    required: false
    model: ecommerce
    explore: orders
    field: orders.created_date

  - name: region
    title: "Region"
    type: field_filter
    default_value: ""
    model: ecommerce
    explore: orders
    field: users.region

  elements:
  - title: Revenue
    name: revenue_kpi
    model: ecommerce
    explore: orders
    type: single_value
    fields: [orders.total_revenue]
    listen:
      date_range: orders.created_date
      region: users.region
    row: 0
    col: 0
    width: 6
    height: 4

  - title: Revenue by Month
    name: revenue_trend
    model: ecommerce
    explore: orders
    type: looker_line
    fields: [orders.created_month, orders.total_revenue]
    fill_fields: [orders.created_month]
    sorts: [orders.created_month desc]
    limit: 24
    listen:
      date_range: orders.created_date
      region: users.region
    row: 0
    col: 6
    width: 18
    height: 4

Note the details that trip people up on day one:

  • The file starts with a - dashboard: list item, including the leading hyphen. LookML dashboards use YAML-style list syntax, not the curly-brace syntax of models and views.
  • listen is what wires a dashboard filter to a tile. A tile with no listen block ignores your filters entirely — this is the single most common "why isn't my filter working" bug.
  • Layout is a 24-column grid. col runs 0–23, row counts downward, and height is in grid units. Overlapping tiles will silently reflow.
  • preferred_viewer: dashboards-next keeps you on the current dashboard experience.

Save, and the dashboard appears in the LookML dashboards list for the project. In dev mode, only you see your changes; on deploy, everyone does.

Do not write these by hand — convert them

Nobody should hand-author forty tiles of YAML. The practical workflow is to build the dashboard in the UI where drag-and-drop is fast, then export it.

  1. Build or open the UDD in Looker.
  2. From the dashboard's gear menu, choose Get LookML.
  3. Copy the generated LookML into a new *.dashboard.lkml file in your project.
  4. Clean it up (see below), commit, and deploy.
  5. Move the original UDD out of the user-facing folder so you do not end up with two copies drifting apart.

The generated output is correct but verbose. It is worth spending ten minutes on:

  • Delete cosmetic defaults. The export dumps every visualization option, including dozens set to their default value. Strip them; a diff you can read is the entire point of this exercise.
  • Name your elements. Auto-generated names like orders_count are fine; element_7 is not.
  • Replace hardcoded filter values with default_value on a dashboard filter so the tile stays reusable.
  • Check every tile for a listen block.

Reusing tiles: extends and merged results

LookML dashboards support the same inheritance machinery as the rest of LookML, which is where the code-based approach starts to pay off.

- dashboard: executive_overview_emea
  extends: executive_overview
  title: Executive Overview — EMEA
  filters:
  - name: region
    default_value: "EMEA"

One base dashboard, three regional variants, one place to fix a bug. Doing the same with UDDs means three copies and three chances to forget one.

For tiles built from a saved Look, merged_results and query_timezone also carry over from the export. If a tile depends on a Look, prefer inlining the query into the dashboard file — an external Look reference is a dependency your Git history cannot see.

Themes, drills, and links

Two parameters do most of the polish work:

  - title: Orders by Category
    name: orders_by_category
    model: ecommerce
    explore: orders
    type: looker_bar
    fields: [products.category, orders.count]
    series_types: {}
    drill_fields: [products.category, products.name, orders.count]
    listen:
      date_range: orders.created_date
    note_state: collapsed
    note_display: hover
    note_text: "Excludes cancelled orders. Source: orders_fact, nightly ETL."

note_text is underrated. A one-line definition on the tile prevents most "why doesn't this match finance" tickets, and because it lives in Git, it gets reviewed along with the metric.

For navigation between dashboards, use a link on the underlying dimension in your view file rather than hardcoding URLs in the dashboard. Dashboard IDs change when you rename a file; a link defined in LookML with {{ value }} templating does not rot in the same way.

Deployment and the Content Validator

LookML dashboards deploy exactly like models: dev mode, commit, pull request, deploy to production. Which means they also participate in validation.

The Content Validator (Develop → Content Validator) scans dashboards and Looks for references to fields that no longer exist. Two habits make it useful rather than a wall of noise:

  1. Run it before you merge, not after. Rename users.state to users.region, then use the validator's Replace field action to update every reference — including LookML dashboards, which it rewrites in your dev branch as part of the same commit.
  2. Keep the error count at zero. A validator that always shows 140 errors tells you nothing. Getting to zero once, then treating any new error as a broken build, converts it into an actual test.

Pair this with LookML validation in your CI pipeline and you have a genuine deployment gate: model validates, content validates, tests pass, deploy.

When LookML dashboards are the wrong tool

Being honest about the limits saves projects:

  • Business users need to self-serve edits. If the request queue for tile tweaks would land on your data team, keep it a UDD.
  • Heavy embedding with per-customer layout. For embedded analytics where each tenant sees a different arrangement, the Extension Framework or an embedded UDD per tenant is usually a better fit than dozens of near-identical dashboard files.
  • One-off analysis. Do not put throwaway work in Git. Its cost is the review, and a throwaway dashboard is not worth a review.

A migration plan that works

For an estate of a few hundred dashboards, do not attempt a big-bang conversion. What we do on client engagements:

  1. Rank by blast radius. Use System Activity to find dashboards by view count and by number of distinct viewers over 90 days. The top 20 usually account for most of the traffic.
  2. Convert the top tier only. Get LookML → clean up → commit. Ten to twenty dashboards is typically a week of work, and it covers the content whose breakage would actually be noticed.
  3. Freeze the originals. Move the source UDDs into an archive folder with restricted access so nobody keeps editing the shadow copy.
  4. Set the rule going forward. New executive or contractual reporting is authored as LookML; team dashboards stay UDDs.
  5. Wire the validator into CI so the newly-versioned content stays consistent with the model that feeds it.

The result is that the dashboards your business genuinely depends on gain the same guarantees as your models: reviewed changes, a readable history, a rollback path, and a validator that catches a rename before your CFO does.


Rolling out dashboards-as-code across an existing Looker estate — or untangling one where the same metric appears on nine dashboards with eight different definitions? Vistelio's senior Looker developers do this work every week. Get in touch with a description of your project and we will tell you what it would take.