Support
Log In

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 TableauIn Credible
Published data sources & relationshipsMalloy sources and joins
Calculated fieldsDimensions 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 permissionsFine-grained access control in the model, versioned and enforced on every surface
Field captions & comments#(doc) / #(index), indexed by the AI Analytics Engine
Workbooks & dashboardsRebuilt 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 to all().
  • 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 →

Next Steps

On this page