Note: This is the English translation of the following article.
https://dev.classmethod.jp/articles/snowflake-try-dashboards-2/

Hi, I'm Sagara.

Snowflake has a new feature called Dashboards 2.0. It's an AI-first BI artifact. You build a dashboard as a .dash file in Snowsight Workspaces, share it with roles, and viewers open it in CoWork or Snowsight.

https://docs.snowflake.com/en/user-guide/snowflake-dashboards

The official docs below cover the sharing details.

https://docs.snowflake.com/user-guide/snowflake-artifacts-create-share

In this article, I'll define a Semantic View on the TPC-H sample data and then visualize it with Dashboards 2.0. I'll also briefly explain what's inside the generated .dash file and try granting privileges through roles.

Note: As of November 13, 2026, the official docs list this feature as "Preview Feature — Open." The specs may change before GA, so please keep that in mind.

Feature Overview

Dashboards 2.0 is a SQL-based, multi-tile dashboard that you create in Snowsight Workspaces. Analysts build it by chatting with Cortex Code (CoCo) and then share it with roles. Viewers open it in CoWork or Snowsight and can explore by clicking on charts. In CoWork, viewers can also ask follow-up questions about a tile.

A dashboard is mainly made up of these components:

Component Description
Dashboard The main body, containing the layout, filters, and tiles (the .dash file)
Tile A single display unit with SQL and a visualization type (chart / table / markdown). Placed on a 12-column grid
Tab A group of tiles. Up to 20 per dashboard. Filters apply across all tabs
Filter Defined per dashboard. Connected to tile SQL with {{ filter('name') }}
Hierarchy A hierarchy definition used for drill-down
Chart action Clicking or dragging on a chart filters or highlights other tiles
Artifact A read-only copy of the .dash file. This is the unit you share with roles

Tile queries run with the viewer's own privileges (caller's rights), and no data is extracted.

Even though queries run with the viewer's privileges, a tile that references a Semantic View only needs the viewer to have SELECT on that Semantic View. You don't need to grant privileges on the underlying tables. The privileges required to query a Semantic View are listed on this page of the official docs:

https://docs.snowflake.com/en/user-guide/views-semantic/querying

Differences from Legacy Dashboards

The official docs state clearly that Dashboards 2.0 is not a drop-in replacement for the legacy version. The main differences are:

Item Legacy Dashboards 2.0
Follow-up questions Not supported Conversational in CoWork
How to create Worksheet UI CoCo + manual
Access control UBAC RBAC
Filter scope Account-wide Per dashboard
Query cache Shared within a role Per user (results reused per viewer)

Version 2.0 doesn't recognize the legacy :filter_name syntax. You have to replace it with {{ filter('name') }}. An upgrade tool can also do this conversion automatically.

Reference Article

Pei-san, a Snowflake Data Superhero, wrote a great article (in Japanese) titled "Why Snowflake Dashboards 2.0 Is the Best, and What BI Will Need Going Forward." It covers the feature's characteristics and where BI is heading. It was a big help when I wrote the overview section of this article.

Please check it out as well.

https://zenn.dev/dataheroes/articles/snowflake-dashboards-2-and-future-of-bi

Limitations

Here are the items from the "Limitations (public preview)" section of the official docs that seem relevant to this walkthrough:

  • On the viewing screen for shared artifacts (such as CoWork), you can't add tiles or change chart types. You make those changes by editing the original .dash file in Workspaces. Users granted Can edit (the WRITE privilege) can publish changes to the artifact. Note that having WRITE is not the same as being able to edit directly on the viewing screen.
  • Artifacts are stored separately from the original .dash file. If you delete the original file, the artifact remains, but Open source file will point to a path that no longer exists. Renaming or moving the file may make its link to the artifact outdated or break it. If you then create the artifact again, it may become a separate artifact with a different link.
  • Chart actions can only be added through CoCo, and they only work between tiles that reference the same table or view.
  • Queries that use {{ hierarchy_key(...) }} must also use {{ hierarchy_rows(...) }}.
  • SQL for managing artifacts (SHOW ARTIFACTS, DESCRIBE ARTIFACT, etc.) is listed as "Coming soon" as of November 13, 2026.

Preparation

Create a Role, Schema, and Warehouse for Testing

For this walkthrough, I'll set up an author role and a viewer role.

USE ROLE ACCOUNTADMIN; -- Author role and viewer role CREATE ROLE IF NOT EXISTS DASH_AUTHOR; CREATE ROLE IF NOT EXISTS DASH_VIEWER; -- Database, schema, and warehouse for testing CREATE DATABASE IF NOT EXISTS DASH_TEST_DB; CREATE SCHEMA IF NOT EXISTS DASH_TEST_DB.SV; CREATE WAREHOUSE IF NOT EXISTS DASH_TEST_WH WAREHOUSE_SIZE = XSMALL AUTO_SUSPEND = 60; -- Create the sample database (run only if SNOWFLAKE_SAMPLE_DATA does not exist in your account) CREATE DATABASE SNOWFLAKE_SAMPLE_DATA FROM SHARE SFC_SAMPLES.SAMPLE_DATA; 

Next, grant the required privileges to the author role DASH_AUTHOR.

-- Privileges on the sample data (shared DB) - author only; not granted to the viewer GRANT IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE_SAMPLE_DATA TO ROLE DASH_AUTHOR; -- Author role privileges (limited to what's needed) GRANT USAGE ON DATABASE DASH_TEST_DB TO ROLE DASH_AUTHOR; GRANT USAGE ON SCHEMA DASH_TEST_DB.SV TO ROLE DASH_AUTHOR; GRANT CREATE SEMANTIC VIEW ON SCHEMA DASH_TEST_DB.SV TO ROLE DASH_AUTHOR; GRANT USAGE ON WAREHOUSE DASH_TEST_WH TO ROLE DASH_AUTHOR; -- Privilege to share artifacts (don't rely on the default grant to PUBLIC) GRANT MANAGE ACCESS ON DASHBOARD ARTIFACTS ON ACCOUNT TO ROLE DASH_AUTHOR; -- Grant the author role to your own user GRANT ROLE DASH_AUTHOR TO USER <your_user>; 

Create the Semantic View

I'll define a Semantic View using the TPC-H ORDERS, CUSTOMER, and LINEITEM tables.

Semantic View DDL (click to expand)
USE ROLE DASH_AUTHOR; USE WAREHOUSE DASH_TEST_WH; USE SCHEMA DASH_TEST_DB.SV; CREATE OR REPLACE SEMANTIC VIEW TPCH_SALES_SV TABLES ( customers AS SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.CUSTOMER PRIMARY KEY (c_custkey) COMMENT = 'Customers', orders AS SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.ORDERS PRIMARY KEY (o_orderkey) COMMENT = 'Orders', line_items AS SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.LINEITEM PRIMARY KEY (l_orderkey, l_linenumber) COMMENT = 'Order line items' ) RELATIONSHIPS ( orders_to_customers AS orders (o_custkey) REFERENCES customers, line_items_to_orders AS line_items (l_orderkey) REFERENCES orders ) FACTS ( line_items.net_price AS l_extendedprice * (1 - l_discount) ) DIMENSIONS ( customers.customer_name AS c_name, customers.market_segment AS c_mktsegment, orders.order_date AS o_orderdate, orders.order_year AS YEAR(o_orderdate), orders.order_priority AS o_orderpriority ) METRICS ( orders.order_count AS COUNT(o_orderkey), line_items.total_net_sales AS SUM(line_items.net_price) ) COMMENT = 'Semantic View for TPC-H sales analysis'; 

I based the DDL syntax on this page of the official docs:

https://docs.snowflake.com/en/sql-reference/sql/create-semantic-view

To confirm the Semantic View was created, query it directly (run these as the DASH_AUTHOR role).

-- Total sales by year SELECT * FROM SEMANTIC_VIEW( DASH_TEST_DB.SV.TPCH_SALES_SV DIMENSIONS orders.order_year METRICS line_items.total_net_sales ) ORDER BY order_year; 


-- Order count by order priority SELECT * FROM SEMANTIC_VIEW( DASH_TEST_DB.SV.TPCH_SALES_SV DIMENSIONS orders.order_priority METRICS orders.order_count ) ORDER BY order_priority; 

If you get one row per year and one row per priority, you're good. I based the SEMANTIC_VIEW clause syntax on this page of the official docs:

https://docs.snowflake.com/en/user-guide/views-semantic/querying

Note that the sales metric total_net_sales is the sum of each line item's extended price (l_extendedprice) minus its discount. It won't match amounts that include tax or the sum of ORDERS.O_TOTALPRICE.

Trying It Out

1. Create a Dashboard with CoCo

Open Workspaces in Snowsight and switch the role to DASH_AUTHOR and the warehouse to DASH_TEST_WH in the Workspace.

Then select Add new → Dashboard.

The CoCo chat panel opens on the right side of the Workspace. In the prompt, I specify which Semantic View to use. If you don't specify one, CoCo searches for a relevant Semantic View, but this time I named it explicitly. I also told CoCo not to query the underlying tables directly and not to redefine the metrics on its own. This keeps the dashboard consistent with the setup, where the viewer has no privileges on the underlying tables.

/dashboard Using DASH_TEST_DB.SV.TPCH_SALES_SV, please create a TPC-H sales dashboard. - Total sales trend by year (line chart) - Total sales by market segment (bar chart) - Order count by order priority (table) - Filter: order year All tile SQL, and any SQL used to fetch the options for the order year filter, must reference DASH_TEST_DB.SV.TPCH_SALES_SV. Do not reference the underlying tables in SNOWFLAKE_SAMPLE_DATA directly. Use line_items.total_net_sales for sales and orders.order_count for order count, and do not redefine the metrics on your own. 

(The prompt in the screenshot is the original Japanese version.)

CoCo shows this as in the screenshot below and starts by drafting an implementation plan. For some reason it wrote the plan in English, so I asked it to reply in Japanese.

The implementation plan then appeared in Japanese. It looked fine, so I asked CoCo to build it.

After a short wait, a .dash file was created in Workspaces and opened, with charts showing in the tiles.

2. Refine It Through Conversation

Next, I asked CoCo to add a chart action. Chart actions can't be added from the tile editor; they can only be added through CoCo.

I sent CoCo the following request:

When a bar in the sales by market segment chart is clicked, add a chart action that filters the sales by year and the order count by order priority to the selected market segment. 

As a result, a chart action was added: clicking a bar in "Total Sales by Market Segment" now updates the other tiles, as shown below.

By the way, here's what the definition of the added filter looked like.

(You can also add filters manually through the GUI. However, the GUI didn't let me pick a Semantic View dimension, so the filter uses a SELECT statement that extracts a single dimension from the Semantic View.)

3. Look Inside the Generated .dash File

Let's open the generated .dash file and look at its contents.

You can view it by clicking View JSON in the top-right corner of the dashboard.

The file is in JSON format. The file generated this time is made up of the following main blocks. (The full file is included in a collapsible section at the end of this step.)

Key Contents
version / spec_version / spec_revision Format version information (2 / 2 / 17 in this case)
title Dashboard title
filters Filter definitions (order_year, market_segment)
datasources SQL definitions used by tiles and filter options
tabs Tabs and the tiles (charts and tables) inside them
layout Position and size of each tile on the 12-column grid
scopes Definitions of how far chart actions reach

Filters (filters)

Order year is defined as single_select, and market segment as multi_select. The options use "source": "query" and reference a datasource that fetches them (such as ds-order_year-options).

The official docs write filter modes with hyphens, like multi-select, but the actual file uses underscores, like multi_select.

Datasources (datasources)

Each datasource is "type": "sql", with the SQL embedded as a string. For example, the SQL for sales by year looked like this:

SELECT order_year, AGG(total_net_sales) AS TOTAL_NET_SALES FROM DASH_TEST_DB.SV.TPCH_SALES_SV WHERE {{ filter('order_year') }} AND {{ filter('market_segment') }} GROUP BY order_year ORDER BY order_year 

Key points:

  • The SQL puts the Semantic View directly in FROM and aggregates metrics with AGG(). Every datasource referenced only TPCH_SALES_SV and none touched the underlying tables in SNOWFLAKE_SAMPLE_DATA directly. Sales used total_net_sales, order count used order_count, and neither metric was redefined. So the instructions from Step 1 were followed.
  • Filters are connected through {{ filter('order_year') }} in the SQL and the filter_id in filter_bindings.
  • Sales by market segment (ds-sales-by-segment) is bound only to order_year; the market_segment filter isn't connected. My guess is that this is because this tile is the source of the chart action.
  • The option datasources (such as ds-order_year-options) use SQL that extracts a single dimension from the Semantic View with GROUP BY, as mentioned in Step 2.

Tiles and Chart Actions (tabs)

There are two tile types, chart and table. A chart tile's spec uses mark (line / bar) and encoding (field, type, and title for x / y). The official docs say chart tiles are rendered with Vega-Lite, and this format is indeed close to Vega-Lite syntax.

The chart action added in Step 2 is defined as interactions on the sales by market segment tile.

"interactions": [ { "trigger": "select", "operator": "set_filter", "fields": ["MARKET_SEGMENT"], "targets": [ { "scope": "segment_action", "fields": ["MARKET_SEGMENT"], "filter": "market_segment" } ] } ] 

When a bar is selected (select), this sets the market_segment filter (set_filter). The target tiles (sales by year and order count by order priority) have "scope": "segment_action", and segment_action is defined in scopes at the end of the file.

Layout (layout)

layout specifies x / y / w / h for each tile, per tab. Sales by year has a width of 12 (full width). Sales by market segment and order count by order priority have a width of 6 each and sit side by side in the bottom row. This matches the "12-column grid" described in the official docs.

Full .dash file (click to expand)
{ "version": 2, "title": "TPC-H 売上ダッシュボード", "filters": { "order_year": { "label": "注文年", "mode": "single_select", "valueType": "STRING", "options": { "source": "query", "datasources": [ "ds-order_year-options" ] }, "default_values": [] }, "market_segment": { "label": "市場セグメント", "mode": "multi_select", "valueType": "STRING", "options": { "source": "query", "datasources": [ "ds-market_segment-options" ] }, "default_values": [] } }, "datasources": { "ds-order_year-options": { "type": "sql", "sql": "SELECT\n order_year\nFROM DASH_TEST_DB.SV.TPCH_SALES_SV\nGROUP BY\n order_year\nORDER BY\n order_year" }, "ds-sales-by-year": { "type": "sql", "columns": [ { "name": "ORDER_YEAR", "type": "NUMBER" }, { "name": "TOTAL_NET_SALES", "type": "NUMBER" } ], "sql": "SELECT\n order_year,\n AGG(total_net_sales) AS TOTAL_NET_SALES\nFROM DASH_TEST_DB.SV.TPCH_SALES_SV\nWHERE\n {{ filter('order_year') }}\n AND {{ filter('market_segment') }}\nGROUP BY\n order_year\nORDER BY\n order_year", "filter_bindings": [ { "filter_id": "order_year" }, { "filter_id": "market_segment" } ] }, "ds-sales-by-segment": { "type": "sql", "columns": [ { "name": "MARKET_SEGMENT", "type": "VARCHAR" }, { "name": "TOTAL_NET_SALES", "type": "NUMBER" } ], "sql": "SELECT\n market_segment,\n AGG(total_net_sales) AS TOTAL_NET_SALES\nFROM DASH_TEST_DB.SV.TPCH_SALES_SV\nWHERE\n {{ filter('order_year') }}\nGROUP BY\n market_segment\nORDER BY\n TOTAL_NET_SALES DESC", "filter_bindings": [ { "filter_id": "order_year" } ] }, "ds-orders-by-priority": { "type": "sql", "columns": [ { "name": "ORDER_PRIORITY", "type": "VARCHAR" }, { "name": "ORDER_COUNT", "type": "NUMBER" } ], "sql": "SELECT\n order_priority,\n AGG(order_count) AS ORDER_COUNT\nFROM DASH_TEST_DB.SV.TPCH_SALES_SV\nWHERE\n {{ filter('order_year') }}\n AND {{ filter('market_segment') }}\nGROUP BY\n order_priority\nORDER BY\n order_priority", "filter_bindings": [ { "filter_id": "order_year" }, { "filter_id": "market_segment" } ] }, "ds-market_segment-options": { "type": "sql", "sql": "SELECT\n market_segment\nFROM DASH_TEST_DB.SV.TPCH_SALES_SV\nGROUP BY\n market_segment\nORDER BY\n market_segment" } }, "tabs": [ { "tab_id": "tab-0", "title": "概要", "tiles": [ { "tile_id": "sales-by-year", "type": "chart", "title": "年別 売上合計の推移", "datasources": [ "ds-sales-by-year" ], "spec": { "mark": "line", "encoding": { "x": { "field": "ORDER_YEAR", "type": "ordinal", "title": "注文年" }, "y": { "field": "TOTAL_NET_SALES", "type": "quantitative", "title": "売上合計" } } }, "scope": "segment_action" }, { "tile_id": "sales-by-segment", "type": "chart", "title": "市場セグメント別 売上合計", "datasources": [ "ds-sales-by-segment" ], "spec": { "mark": "bar", "encoding": { "x": { "field": "MARKET_SEGMENT", "type": "nominal", "title": "市場セグメント", "sort": "-y" }, "y": { "field": "TOTAL_NET_SALES", "type": "quantitative", "title": "売上合計" } } }, "interactions": [ { "trigger": "select", "operator": "set_filter", "fields": [ "MARKET_SEGMENT" ], "targets": [ { "scope": "segment_action", "fields": [ "MARKET_SEGMENT" ], "filter": "market_segment" } ] } ] }, { "tile_id": "orders-by-priority", "type": "table", "title": "注文優先度別 注文件数", "datasources": [ "ds-orders-by-priority" ], "spec": { "columns": [ { "field": "ORDER_PRIORITY" }, { "field": "ORDER_COUNT" } ] }, "scope": "segment_action" } ] } ], "layout": { "tab-0"Source:https://dev.to/sagara/building-an-ai-first-dashboard-with-snowflake-dashboards-20-1pii

Related posts