> ## Documentation Index
> Fetch the complete documentation index at: https://docs.credibledata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 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 [Context Engine](/how-to/analyzing/overview)                             |
| Workbooks & dashboards                            | Rebuilt as [data apps](/how-to/analyzing/data-apps) or [notebooks](/how-to/analyzing/workspaces)               |

## The Migration Flow

Credible [reads](/how-to/migrating/overview) 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]))
```

```malloy theme={"languages":{"custom":["/languages/motly.tmGrammar.json","/languages/malloy.tmGrammar.json"]}}
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 →](/how-to/migrating/overview#more-than-a-reformat)

## Next Steps

<CardGroup cols={2}>
  <Card title="Migration Overview" icon="diagram-project" color="#5C7A93" href="/how-to/migrating/overview">
    The method behind every migration
  </Card>

  <Card title="Metadata & Discovery" icon="tags" color="#94793A" href="/how-to/modeling/metadata-tags">
    Tune your migrated model for AI retrieval
  </Card>
</CardGroup>
