Migrate from Tableau
Convert your Tableau data sources and calculated fields into governed Malloy semantic models
Your Tableau published data sources carry the calculated fields, relationships, and LOD expressions your analysts rely on — and workbooks carry even more. Credible reads both, re-expresses the calculations as Malloy, and — where you connect it — validates them against Tableau's own query service.
What Credible Reads
Your published data sources (.tds / .tdsx) — calculated fields, default aggregations, folders, and the logical/physical data model — plus the calculated fields embedded in workbooks (.twb). These files are all the agent needs to translate. Connecting the official Tableau MCP server (tableau/tableau-mcp, hosted at mcp.tableau.com) is optional: it reads model metadata via the Metadata API and validates through the VizQL Data Service.
What Comes Across
The everyday modeling carries over. Here's how the bigger pieces land — and where they get better:
| In Tableau | In Credible |
|---|---|
| Published data sources & relationships | Malloy sources and joins |
| Calculated fields | Dimensions and measures |
LOD expressions (FIXED / INCLUDE / EXCLUDE) | Aggregates at a declared grain — no LOD workarounds for fan-out |
Table calculations (RUNNING_SUM, WINDOW_*) | Reusable window calcs defined in the model — not view-position-dependent calcs that break when the viz changes |
| Data-source & workbook permissions | Fine-grained access control in the model, versioned and enforced on every surface |
| Field captions & comments | #(doc) / #(index), indexed by the AI Analytics Engine |
| Workbooks & dashboards | Rebuilt as data apps or notebooks |
The Migration Flow
Credible reads the data source and workbook calcs, translates fields and relationships to Malloy, enriches with #(doc)/#(index) tags, and — where you connect it — validates row-by-row against the VizQL Data Service.
What Credible Handles
- LOD expressions encode a grain independent of the viz. A
{ FIXED [Customer ID] : SUM([Amount]) }becomes a Malloy aggregate at an explicit grain. Credible also distinguishes "real" LODs from workaround LODs that only existed to dedupe joins — the latter are unnecessary in a clean model. - Table calculations run over the rendered viz and depend on Compute-Using direction. They're reconstructed as explicit Malloy window functions with a declared
partition_by/order_by;TOTAL()maps toall(). - Workbook-embedded calculated fields — business logic frequently lives in
.twb, not the published.tds, so Credible scans both. - Viz-level formatting — Compute-Using direction, table layout, cosmetic styling — is presentation and is dropped; threshold-based color rules become model logic, and model-worthy defaults and labels carry over.
Before & After
Tableau calculated fields as authored against a data source:
// Relationship: Orders ── Customers (many-to-one)
[Order Date Only] = DATETRUNC('day', [Created At])
[Shipped Revenue] = SUM(IF [Status] = "shipped" THEN [Amount] END)
[Shipped Revenue %] = SUM(IF [Status] = "shipped" THEN [Amount] END) / SUM([Amount])
// LOD: revenue per customer, independent of view grain
[Revenue per Customer] = { FIXED [Customer ID] : SUM([Amount]) }
// Table calcs (viz-context dependent)
[Running Revenue] = RUNNING_SUM(SUM([Amount]))
[Pct of Total Revenue] = SUM([Amount]) / TOTAL(SUM([Amount]))source: orders is conn.table('sales.orders') extend {
primary_key: order_id
join_one: customers is conn.table('sales.customers') on customer_id
dimension:
#(doc) Order date truncated to day
order_date is created_at::date
measure:
#(doc) Total revenue in USD
# currency
total_revenue is sum(amount)
#(doc) Revenue from shipped orders
# currency
shipped_revenue is sum(amount) { where: status = 'shipped' }
#(doc) Share of revenue that shipped
# percent
shipped_revenue_pct is shipped_revenue / total_revenue
view:
#(doc) Revenue per customer (LOD FIXED equivalent — aggregate at customer grain)
revenue_per_customer is {
group_by: customers.customer_id
aggregate: total_revenue
}
#(doc) Running revenue and percent of total by day (table-calc equivalent)
revenue_trend is {
group_by: order_date
aggregate: total_revenue
calculate:
running_revenue is sum_cumulative(total_revenue) {
partition_by: order_date.year
order_by: order_date asc
}
pct_of_total is total_revenue / all(total_revenue)
}
}A FIXED LOD becomes an aggregate declared at its grain; table calcs become explicit window calculations. Purely visual constructs — Compute-Using direction, quick table calcs, worksheet formatting — have no model equivalent and are dropped.
More than a reformat. Logic that lived inside workbooks becomes a reusable, AI-discoverable model that serves every surface, not just Tableau — and Malloy's symmetric aggregates keep totals correct where Tableau needed LODs to avoid double-counting. See what you gain →