Manifest & .trex

What is actually inside a .trex file

A .trex is twenty lines of XML doing one job: pointing Tableau at a URL. Every element explained, why order matters, and the empty tag that breaks first loads.

Eric SummersUpdated 2026-09-18markdown

People treat the .trex as the extension. It is not. It is a twenty-line XML file whose entire job is to tell Tableau where the real thing lives, plus enough metadata to draw a dialog box. Understanding those twenty lines removes most of the mystery from extension development. This is the narrative, element-by-element tour. For the dry field reference, see the .trex manifest reference.

The whole file

This is a complete, valid dashboard-extension manifest. Nothing has been trimmed:

<?xml version="1.0" encoding="utf-8"?>
<manifest manifest-version="0.1" xmlns="http://www.tableau.com/xml/extension_manifest">
  <dashboard-extension id="com.yourorg.yourext" extension-version="1.0.0">
    <default-locale>en_US</default-locale>
    <name resource-id="name"/>
    <description>What it does, in one line.</description>
    <author name="Your Name" email="you@example.com"
            organization="YourOrg" website="https://example.com"/>
    <min-api-version>1.4</min-api-version>
    <source-location>
      <url>https://your-host.example.com/index.html</url>
    </source-location>
    <icon/>
  </dashboard-extension>
  <resources>
    <resource id="name"><text locale="en_US">Display Name</text></resource>
  </resources>
</manifest>

One line, the <url>, does the actual work. Everything else is labelling. When you install an extension, Tableau parses this file, embeds a copy in the workbook, and loads that URL into an iframe. That is the entire mechanism.

Element by element

Element What it is
manifest-version Always 0.1. The manifest schema's version, not yours, and it has not changed. Your version goes in extension-version.
<dashboard-extension> The root, and what decides the extension's kind. A viz extension uses <worksheet-extension> instead. Its id should be reverse-domain (com.yourorg.kpicard) and genuinely unique.
<default-locale> en_US unless you are localising. It selects which <resource> block supplies the display name.
<name resource-id="name"/> A pointer to a <resource> at the bottom of the file, not the name itself. Both halves must exist and the ids must match, or the manifest fails to parse. It exists so one extension can carry names in several languages.
<description> One line, shown in Tableau's dialog while a user decides whether to grant data access.
<author> name, email, organization, website. Check this before you ship: scaffolds carry their author's details.
<min-api-version> The oldest Extensions API your code needs. 1.4 is a safe floor for dashboard extensions. Viz extensions need 1.11 or later. Raise it only when you use something newer: it locks out older Tableau for no gain otherwise.
<source-location><url> The only line that does anything. Must be HTTPS with a real certificate in production; self-signed fails. http://localhost:PORT/index.html is allowed for local development in Desktop only.
<icon/> An empty element that breaks more first loads than anything else. Omit it and some Tableau builds throw error FD722608, because the schema lists it without the ? that marks optional elements. It can hold a base64 PNG; empty is fine, present is what matters.
<resources> The other half of <name>, a sibling of the extension root. A resource-id with no matching resource is a parse error.

Order is not negotiable

The schema defines a sequence, not a set. A manifest with every required element in the wrong order fails exactly like one that is missing an element, and the message will not tell you order is the problem. Inside the root, the order is: default-locale, name, description, author, min-api-version, source-location, icon (last, immediately after </source-location>).

Do not memorise it. Keep one known-good manifest in the repo and diff against it. That single habit removes the most common first-load error permanently.

Keep two of them, and mind the reload trap

Every extension wants two manifests that differ by exactly one line: a local one pointing at http://localhost:PORT/index.html, and a hosted one pointing at your HTTPS URL. Name them manifest.local.trex and manifest.hosted.trex and you will never ship the localhost one by accident. See local vs hosted manifests for the full split.

Manifests do not hot-reload. Tableau embeds a copy of the .trex in the workbook when you add the extension, so editing the file afterwards changes nothing. HTML and JS respond to Reload; any manifest edit needs a full remove and re-add.

Where viz extensions diverge

A viz extension's manifest is the same skeleton with a different root (<worksheet-extension>) and one addition: <encoding> blocks after <icon/>, one per tile you want on the Marks card. Each declares what it accepts (a measure, a dimension, a date) and which icon Tableau draws next to it. The icon token must come from a fixed enumeration compiled into Tableau, the published docs list tokens the parser rejects, there is a cap of four encodings, and reusing a token across two of them throws error ED626076 at add time. See encoding icon tokens for the authoritative list.

FAQ

What actually happens when I install a .trex?

Tableau parses the file, embeds a copy of it in the workbook, and loads the <source-location> URL into an iframe. The workbook now carries its own copy of the manifest, which is why editing the file on disk afterwards changes nothing.

Why does my manifest fail with FD722608?

Most often a missing <icon/> element, which some Tableau builds treat as required. The same code also covers a required element in the wrong order or a -- inside an XML comment. Read the parenthesised content model in the message: it is the schema, in required order.

Do I need the block?

Only if you use the <name resource-id="name"/> form. You can inline the name as <name>Display Name</name> and drop <resources> entirely unless you genuinely localise. Nesting <resources> inside the extension root is a parse error.

My manifest edit did nothing. Why?

Manifests do not hot-reload. Reload refreshes HTML, JS, and CSS only. Any .trex change requires removing and re-adding the extension so Tableau re-reads and re-embeds it.