Limits
Every Dashies size ceiling by constant name, plus the per-engine row and byte caps a cube result is measured against.
Every ceiling on this page is read out of the server's own exported constants by a build guard, so a raise in the code turns into a wrong number here rather than a silently stale one. The guard reads the two tables below and nothing else, so a figure quoted in prose anywhere on this site is unchecked.
Per-engine cube caps
A dataset's SQL runs once per publish and once per refresh. Its result is measured on two axes, and the ceilings differ by engine.
| Engine | Rows per result | Bytes per result | Island ceiling | Refused by | Over the island ceiling |
|---|---|---|---|---|---|
self | 100,000 | 8,000,000 | 8,388,608 | executor | refused |
postgres | 100,000 | 8,000,000 | 8,388,608 | executor | Parquet |
bigquery | 100,000 | none | 8,388,608 | adapter | Parquet |
snowflake | 100,000 | none | 8,388,608 | adapter | Parquet |
redshift | 100,000 | none | 8,388,608 | adapter | Parquet |
databricks | 100,000 | none | 8,388,608 | adapter | Parquet |
mssql | 5,000 | 2,000,000 | 2,097,152 | executor | refused |
Rows per result is a hard refusal on every engine in the table. Past it the run fails; it never returns a truncated result.
Bytes per result is the serialized size at which the read-only executor
raises. none in that column means literally that: BigQuery, Snowflake, Redshift
and Databricks are reached through a REST adapter with no database executor in
the path, and nothing on that path measures serialized size. Those four are
bounded on the byte axis only by the island ceiling and by
MAX_PUBLISH_BYTES at publish time.
Refused by names the layer that produces the refusal, because the two behave
differently. An executor engine measures the assembled result and raises on
overflow. An adapter engine reads the warehouse's own reported row total before
fetching anything and refuses up front, so an over-cap cube costs you almost no
warehouse time.
Island ceiling is a Worker-side backstop on the whole serialized data island, set to the next whole binary MiB above the executor's decimal cap so a result the database accepted is never re-refused for serializing a few bytes wider here. It is also the threshold the authoring size recommender bands against.
SQL Server is the outlier on both axes
mssql allows 5,000 rows and 2,000,000 bytes per result. That is twenty times
fewer rows than the ceiling every other engine in the table carries, and it has
no Parquet offload to fall back on, so an over-ceiling cube there is terminal:
coarsen the grain, narrow the window, or fold small dimension members into an
Other bucket.
What each ceiling measures
Three byte ceilings, and they do not measure the same bytes
The two columns in the table are not interchangeable with each other. The bytes per result column is the size at which the executor raises. The island ceiling is what the size recommender bands against. Quoting one where the other belongs is a mistake this codebase has shipped twice, both times while correcting SQL Server.
A third ceiling sits outside the table:
MAX_PUBLISH_BYTES, 5,242,880 bytes on the compiled
dashboard body. It applies on every engine in the table, including the four with
no execution-time byte cap, where it and the island ceiling are the only byte
limits there are.
Do not read those thresholds as one axis. They measure different bytes:
| Ceiling | Measures |
|---|---|
| bytes per result | the query result in its row-major form, as the database serializes it, before any encoding |
MAX_PUBLISH_BYTES | the finished body, whose data island is dictionary-columnar packed |
A packing step several times smaller than the input sits between them, so 5,242,880 is not simply the tighter of the two. Measured on a board-shaped cube grown until its row-major form crossed 8,000,000: the packed island landed at 1,903,028 bytes, comfortably inside the 5,242,880 cap. On that dashboard the executor is what refuses you, not the publish cap.
Where the publish cap does bind first:
- a dashboard whose several inline datasets sum toward it, which is the case the publish-time budget message is about;
- a body whose island is not packed at all: packing is off in
look mode, and off for any dashboard carrying a
customtile; - look-mode markup that is large in its own right, since your HTML counts against the same 5,242,880.
Otherwise, on an ordinary single-dataset dashboard built from tiles, expect the
per-engine result cap to be the one you meet.
Size constants
| Constant | Value | What it bounds |
|---|---|---|
MAX_PUBLISH_BYTES | 5,242,880 | The compiled dashboard body, 5 MiB. Publish is refused past it. Inline data ships inside that body, in packed form, so this is not directly comparable to the per-engine result caps: see the note above. |
SLUG_MAX_LENGTH | 64 | Characters in a dashboard slug. |
INLINE_MAX_ROWS | 100,000 | Rows in one inline dataset result, on every engine except mssql. |
INLINE_MAX_BYTES | 8,388,608 | The island ceiling, 8 MiB, on every engine except mssql. |
EXECUTOR_MAX_BYTES | 8,000,000 | The serialized size at which the read-only executor raises, for self and postgres. |
MSSQL_INLINE_MAX_ROWS | 5,000 | Rows in one inline dataset result on mssql. |
MSSQL_EXECUTOR_MAX_BYTES | 2,000,000 | The serialized size at which the mssql executor raises. |
MSSQL_INLINE_MAX_BYTES | 2,097,152 | The island ceiling on mssql, 2 MiB. |
LATTICE_MAX_CELLS | 50,000 | Cells in one precomputed lattice, estimated from each dimension's declared cardinality. A lattice whose estimate is over this is refused at publish. |
MAX_DATASETS | 8 | Datasets in one dashboard. |
PARQUET_DATASETS_MAX | 2 | Parquet-backed datasets in one dashboard. |
FLAT_PARQUET_CEILING | 268,435,456 | A Parquet object, 256 MiB, for a dashboard whose island carries the range-read capability tag. A spec publish always emits that tag when a Parquet dataset is present, so this is the ceiling in practice. |
EXTRACT_MAX_PARQUET_BYTES | 134,217,728 | A Parquet object, 128 MiB, for an older island with no range-read tag, whose runtime downloads the whole file. |
MAX_EXTRACT_ROWS | 50,000,000 | Rows in one Parquet extract. |
SEED_PROBE_MAX_ROWS | 1,000 | Rows read from a Parquet-backed dataset at publish, to type its columns and prove the SQL runs. |
CUBE_VALIDATE_ECHO_ROWS | 200 | Sample rows validate_cube_sql echoes back. |
CUBE_VALIDATE_ECHO_BYTES | 8,192 | Bytes of that sample, whichever binds first. |
LIST_DEFAULT_LIMIT | 50 | Dashboards per list_dashboards page by default. |
LIST_MAX_LIMIT | 100 | Dashboards per list_dashboards page at most. |
The Parquet path applies only where the Over the island ceiling column above
says Parquet. On self and on mssql there is no extract path at all, so the
three Parquet constants never apply to either.
Limits stated elsewhere
These are bounds a reader looks for here, but they belong to a surface with its own contract page and are not repeated:
| Limit | Where it is stated |
|---|---|
| Structural caps: tiles, dimensions, measures, string lengths | Dashboard spec (v1) |
Per-tile limit ceilings | Tile types |
| Rate limits, version retention, upload and spec caps | Shared rules |
| Schedule cadence multipliers | Schedules |
Check it worked
Ask your AI tool to validate a candidate cube against your connection. The reply
carries the exact row count and a size band. A small band means the result fits
inline; big means it is over the island ceiling and needs the Parquet path;
extreme means it is over the Parquet ceiling and the SQL has to change.