Guides
Choose a dataset mode
A decision flow for picking cube, lattice, hybrid or rows on data Dashies provides, and how to tell when the server picked one you did not expect.
On the data Dashies provides, each dataset in a dashboard picks one of four materializations independently, and the choice is mechanical once you know two things about the dataset: whether any measure is non-additive, and how its filters work. The warning headed This flow is about data Dashies provides says what that phrase rules out and why.
This page is the decision flow. For what each mode actually is and why the positioning runs the way it does, see Datasets and the four modes.
This flow is about data Dashies provides
A dataset that reads a warehouse you connected, or the workspace's
uploaded-file source, does not choose between these four. Its rows stay with
Dashies and are queried when a reader opens the page, so the only mode it can be
given is resolved, and a publish that asks for cube, lattice, hybrid or
rows on such a connection is refused. There is nothing here for you to decide.
The measures do not pick a different mode there either, but they can stop you
reaching it: percentile_disc, stddev, variance and mode cannot be worked
out on such a dataset, so declaring one is refused at publish, naming the
measures, rather than steered onto anything else
(the aggregate table).
One exception to all of this, and it turns on the plan rather than on the connection: on a free plan a dashboard built on the shared Dashies sample data is prepared the in-file way instead, so this flow is the one that applies to it.
The connection also decides what the statement itself returns, and that is the part that goes wrong silently: a dataset whose rows Dashies holds returns one row per underlying record and declares each number rather than computing it, so a statement that has already aggregated gets aggregated a second time. Datasets carries that fork, and a warehouse dashboard is served carries the mechanism behind where those rows live.
The flow
Answer in order. The first rule that fires is your answer.
1. Is every measure additive?
Additive means summing partial totals gives the right answer. sum, count,
min, and max are additive.
Non-additive means it is not. Any of these makes the dataset non-additive:
count(distinct ...)avgmedianpercentile_contor any percentilestddevvariancemode(...)
If every measure is additive, use cube. Stop here.
2. Is every dimension low-cardinality?
That means every field the dashboard filters, charts, or tabulates on has a small bounded set of values, and dates are bucketed rather than raw timestamps.
If not, use rows. Skip to step 4.
3. Are all the filters single-select?
A single-select filter fixes one value at a time.
If yes, use lattice. Stop here.
If a multi-select or range filter has to stay exact on a non-composable
measure, use hybrid. Non-composable means a distinct count, a true average, a
median, a percentile, a standard deviation, a variance, or a mode. A sum, count,
min, max, or a ratio of them composes across selected values without help, so
those do not force hybrid.
4. If you landed on rows, decide where the bytes go
A rows dataset can declare Parquet offload, which moves its rows out of the
shared inline budget so it can grow between publishes.
On a warehouse you connect this is not a declaration at all. Its data already lives in a Parquet object Dashies holds and answers from, which is the one shape such a dashboard has, so there is nothing here to decide; offloading to Parquet is what that buys and what it costs.
Where it IS a declaration, three conditions hold, and each is a hard publish error rather than a surprise:
- Only a
rowsdataset. Nevercube,lattice, orhybrid. - Only on a warehouse connection, never on
self. - A cap on how many of one dashboard's datasets may be backed that way. The number is in sizes and ceilings rather than here, so there is one copy of it to keep right. Measured 2026-09-20: the figure that stood on this page said two while that table said three.
SQL Server had no Parquet path until 2026-09-11 and this page said so. It has one now, and a SQL Server dashboard is served like the other warehouse engines: its data is held by Dashies rather than shipped inside the file. See Connect SQL Server, which carries what is still narrower there - the statement shapes it refuses, the four column types it cannot carry, and a case-insensitive collation that merges rows before Dashies sees them.
The short form
| If | Use |
|---|---|
| Every measure is additive | cube |
| Something is non-additive, all dimensions low-cardinality, all filters single-select | lattice |
| As above, but a multi-select or range filter must stay exact on a non-composable measure | hybrid |
| A dimension cannot be bounded, or you need row-level detail | rows |
Cost and power both run cube then lattice then hybrid then rows. Take the
first one that is correct, not the most capable one. The reasoning behind that
ordering is in
how the choice is actually made.
You do not have to declare it
Leave mode off and the server auto-selects cube or lattice from the
measures and dimensions. rows and hybrid ship row-level bytes, so they must
be declared explicitly.
The publish report's mode_choices says what each dataset resolved to and why,
for example:
main -> lattice: a distinct count over low-cardinality dimensions
Read it. A mode you did not expect is usually the server noticing a measure is not what you thought it was, which is worth knowing before it becomes a wrong number.
The rule is enforced, so a wrong choice is loud
A cube dataset whose SQL computes a non-additive aggregate is rejected at
publish, naming the construct. Why it refuses rather than warns is
explained here. A cube measure declared with a non-additive
aggregation is a schema error. Validation warns about the same SQL earlier, when
your AI passes the dataset's mode.
The enforcement reads the SQL text, so it has a blind spot
A ratio or a distinct count computed inside a CTE or a subquery, then selected as a plain column, reads as additive from the outside and passes every check.
That is why Verify your numbers is a required step and not a nicety. The check there is exactly what catches a mode chosen wrongly for this reason.
A lattice must stay bounded
A lattice precomputes one cell per filter state, so its size is roughly the product of each dimension's number of values plus one. Every dimension declares its bound: a list of values for a category, or buckets for a date.
If it grows past the inline cap, the fix is to drop or bound a dimension. A lattice can never offload to Parquet, so there is no way to buy your way out of an unbounded one. The arithmetic is in the lattice cell budget, and offloading to Parquet covers what Parquet does and does not buy.
Check it worked
mode_choicesin the publish report names the mode you intended for each dataset.- The publish was not refused for a non-additive aggregate in a
cube. - You ran Verify your numbers on each additive measure, and the two legs agreed. That is the step that confirms the mode was right, rather than merely accepted.