In ThoughtSpot, dashboards (Liveboards), Models and Tables are TML files you can keep in Git and deploy with REST API v2. An import creates a duplicate when ThoughtSpot can't match the incoming TML to an existing object, and it never matches by name. Turn on obj_id for your instance, export with obj_id instead of GUIDs, keep create_new: false, and every import after the first updates the same dashboard in prod.
This post uses the TML import and export APIs from your own pipeline.
Checked against REST API SDK 2.29.1 and the ThoughtSpot Cloud 26.10.0.cl documentation, October 2026.
TML (ThoughtSpot Modeling Language) is the YAML format ThoughtSpot uses to describe Liveboards, Models and Tables as text, so they can live in Git and deploy like code. On import, ThoughtSpot matches an object's obj_id first, so a deploy updates the object instead of duplicating it.
What should you check when you compare tools?
Analytics in your product should ship like the rest of it: reviewed in a pull request, promoted by a pipeline, rolled back from Git. ThoughtSpot content is TML, YAML you export, commit and import through REST API v2, from any CI pipeline, such as GitHub Actions or GitLab CI (Deploy with TML APIs).
Ask any vendor:
Is every dashboard and model a text file I can diff in a pull request?
Can my CI pipeline deploy it, with no one clicking through the UI?
Can the same object move across environments and customer tenants without copies?
Why does it happen?
ThoughtSpot's matching rules on import (create vs update rules):
"Object names are never used for determining an object to update."
"obj_id is always considered first if present", within the target Org.
Without obj_id, it falls back to GUID, and "No GUID in the TML file: always creates a new object with a new GUID."
create_new: true "on objects that already exist creates duplicates" (TML import).
obj_id is an ID you choose, shared by copies of an object across Orgs, so it's the safe key for promotion.
How do I fix it?
1. Turn on obj_id and give objects readable IDs. The export docs say to ask ThoughtSpot Support to enable it. Existing objects get an automatic obj_id only after their first change once it's on, so set your own with POST /api/rest/2.0/metadata/update-obj-id (10.8.0.cl+):
{
"metadata": [
{ "metadata_identifier": "<LIVEBOARD_GUID>", "new_obj_id": "sales-kpis" }
]
}2. Export from dev with obj_id references and no GUIDs (obj_id or GUID), and save each file to Git, for example as sales-kpis.liveboard.tml:
POST /api/rest/2.0/metadata/tml/export
{
"metadata": [{ "identifier": "<LIVEBOARD_GUID>", "type": "LIVEBOARD" }],
"edoc_format": "YAML",
"export_associated": false,
"export_fqn": false,
"export_options": {
"include_obj_id": true,
"include_obj_id_ref": true,
"include_guid": false
}
}3. Validate in prod, then import. If validation passes, resend with "import_policy": "ALL_OR_NONE".
POST /api/rest/2.0/metadata/tml/import
{
"metadata_tmls": ["<contents of sales-kpis.liveboard.tml>"],
"import_policy": "VALIDATE_ONLY",
"create_new": false
}On the first deploy, import Tables and Models from the same Connection in one request, before the dashboards. Tables match on the database table, not on obj_id. If database or schema names differ between environments, use TABLE_MAPPING variables (variables). Connection properties can be parameterized with variables too (Deploy with TML APIs).
4. Share new objects. Share imported dashboards and Models read-only with your users' groups using POST /api/rest/2.0/security/metadata/share:
POST /api/rest/2.0/security/metadata/share
{
"metadata": [
{ "type": "LIVEBOARD", "identifier": "<LIVEBOARD_GUID>" },
{ "type": "LOGICAL_TABLE", "identifier": "<MODEL_GUID>" }
],
"permissions": [
{
"principal": { "identifier": "app_users", "type": "USER_GROUP" },
"share_mode": "READ_ONLY"
}
],
"message": "Deployed by CI"
}5. Keep users' Personalized Views. An admin import removes them. Import as a non-admin with edit access, or set enable_personalized_view_upsert: true when you import Personalized View TML (Personalized Views portability). It needs 26.8.0.cl or later, and the feature must be enabled for your instance: contact your ThoughtSpot administrator.
Export and import need "Can manage data" (DATAMANAGEMENT) or "Can administer ThoughtSpot" (ADMINISTRATION).
How do I check it worked?
Import the same file twice. Prod should have one object with metadata_obj_id set to sales-kpis, and its GUID shouldn't change between imports.
Still failing?
Still getting copies. Check for create_new: true, obj_id not enabled, or objects whose obj_id is empty.
Model reference errors. Import related objects in one request.
"Invalid YAML/JSON syntax in file" in the Playground. Paste the TML through the View JSON editor.
How do I explain this to my team?
|
Who |
What they'll ask |
What you can tell them |
|
Engineering lead |
Does analytics fit our release process? |
Yes. Dashboards are YAML files in our repo, reviewed like code and deployed by our pipeline. |
|
Security |
Can a deploy overwrite the wrong object? |
No. Imports match on obj_id in the target Org, never by name, and only accounts with Can manage data or Can administer ThoughtSpot can import. |
How can I try this before I commit?
Start a free ThoughtSpot Embedded trial.




