TE CLI 0.7.0 release blog

Written by Ruben Van de Voorde | Sep 9, 2026, 3:14:45 PM

Key Takeaways

  • The Tabular Editor CLI 0.7.0 is now available Limited Public Preview: This release focuses on safer defaults, a more consistent command syntax, and more consistency in showing model changes and reporting problems. The preview period has been extended from September 30 to October 31, 2026.
  • Update existing scripts: Property assignments use -p <Property>=<Value>, several commands move under get or util, and others are removed. The update checklist below maps the old commands to their replacements.
  • Review changes and read results consistently: Model edits show before/after values, and validation, BPA, tests, and queries share a JSON findings structure. Update scripts that read the CLI's JSON output.
  • Run the same built-in BPA checks as in Desktop: The CLI now uses the same built-in rules, IDs, and severities as TE3 Desktop, so switching tools no longer changes which built-in checks run.

This summary is produced by the author, and not by AI.

Release overview

We're excited to share another release of the Tabular Editor CLI: 0.7.0. The Tabular Editor CLI lets you inspect, edit, validate, deploy, and refresh semantic models from your terminal, in CI/CD pipelines, and by agents. This release is about safer defaults for deployment and refresh, a more consistent command syntax, and consistent ways to show model changes and report problems.

NOTE

The TE CLI is in limited public preview and offered for evaluation with a Tabular Editor account. We recommend against using the CLI in production CI/CD pipelines during preview, as commands, flags, and outputs may change before general availability. The preview period has been extended from September 30 to October 31, 2026. This build will stop functioning after that date. After the preview period, a license will be required.

Safer by default

Defaults are the safety net you don't plan for; they help prevent small mistakes from having big consequences. That's why deploy and refresh now default to dry-run; you must pass --execute to actually make changes. These commands print the TMSL script that would run, so you can check what exactly will happen before changing a deployed model or starting a refresh. Add --execute to existing automation that should still deploy or refresh; otherwise, your pipeline will only preview the operation and leave the model unchanged.

You can now also deploy models published to the Power BI Service, and models running in Power BI Desktop, without first exporting them to disk.

  • Use --model for a local file or folder, or -s/-d for a remote source.
  • Use --target-server and --target-database for the deployment target.

Simplified, consistent commands

There's now one syntax to assign properties: -p <Property>=<Value>, for example te set 'Invoiced Sales/Revenue' -p IsHidden=False --model '<model path>' --save to unhide the Revenue measure. This syntax replaces the paired -q/-i property flags. To read a property, use te get 'Invoiced Sales/Revenue' -p Description --model '<model path>' to return the description of the Revenue object.

We consolidated several commands:

  • save is being renamed to save-as (save is kept as an alias). In interactive mode, save commits staged edits, while save-as writes a model to another location or a different format.
  • get becomes the core command for listing and dependency inspection. ls/ list still work and become aliases of get, as does deps. You can inspect properties, for example, te get 'Invoiced Sales/Revenue' -p Description --model '<model path>' to read the description of the Revenue object in the Invoiced Sales table. Filter objects, with te get Measures --where 'Name=*Revenue*' --model '<model path>' to return only the measures with Revenue in their name; list objects, for example te get Hierarchies --model '<model path>' to list the all hierarchies in the model; and check dependencies, for example te get 'Invoiced Sales/Revenue' --deps --model '<model path>' to see what Revenue depends on and what depends on Revenue. The original commands still work as shortcuts, so existing scripts can keep using them.
  • format has been removed. Formatting a model expression now happens with te set '<table>/<object>' --format Expression --model '<model path>' --save. DAX expressions and M scripts can be passed into te util format-dax '<DAX expression>' and te util format-m '<M expression>' for formatting.
  • migrate also moves under util, i.e. te util migrate.
  • incremental-refresh has been removed. You can inspect a table's policy with te get '<table>/RefreshPolicy' --model '<model path>', and configure it with te set '<table>/RefreshPolicy' -p '<Property>=<Value>' --model '<model path>' --save. Then apply a policy already saved on a deployed model with te refresh --apply-refresh-policy '<table>' -s '<workspace>' -d '<model>' --execute, which also loads data, whereas the old apply only created partitions. To bootstrap empty partitions without loading data, run te script --inline 'Model.Tables["<table>"].ApplyRefreshPolicy();' -s '<workspace>' -d '<model>'.

More predictable output

Commands that change a model, such as set, add, and remove, will now show the values before and after the change. Changing the Revenue description prints both the old description and the replacement, so you can review the actual edit. The same diff is shown whether you save the change or preview it, and the final status line tells you whether the change was saved, staged, or left unsaved.

diff now uses the same output format as these set, add, and remove editing commands. For structured output with --output-format json, the changes array contains one entry per changed object, with the changed properties and their before/after values grouped together. Previously, diff reported a separate entry for each property. Existigin scripts that read this output will need to account for the new structure and field names, including objectPath and changeKind.

Informational notices like which connection or model you're using now go to the stderr stream, keeping stdout for command results. When you pipe output into another command or save it to a file, meta information like connection notices and progress messages no longer get mixed in with the data. This also applies to text and CSV output.

validate, bpa run, test run, and query now all report problems using the same JSON structure. Each output has a summary with error, warning, and information counts, and a findings array with the individual messages, codes, and severities. If the affected ojbect is known, findings also include an objectPath so you can pass it path to get to inspect it. You'll need to update scripts that read this JSON output, but a pipeline can then read findings from all four commands in the same way.

Checks and BPA

The CLI's BPA now uses the same built-in rules as TE3 Desktop, including the same IDs and severities. Switching between the two no longer changes which built-in checks run.

To align with TE3, the six VertiPaq rules (those with IDs starting with VPA_) are no longer included, and --vpa-rules has been removed. You can still run these checks if you supply the rules yourself:

  • With bpa run, point the CLI to the rules file with --rules, e.g. te bpa run --rules BPARules.json --model '<model path>'.
  • With Bpa.Analyze() in a C# script, save the rules inside the semantic model. That scripting method doesn't read external rules files.

BPA now also returns a non-zero exit code when a rule cannot be evaluated. Previously, BPA could report success (a zero exit code) even though a rule had failed to run. Pipelines that check the exit code can now detect that rules couldn't be evaluated.

Source schema

You can now add a table from a data source already defined in the model, with te add '<table>' -t Table --source-table '<schema.table>' --model '<model path>' --save. The CLI will read the source table schema, and creates the table with a partition bound to the source (refresh is still a separate action). You don't need to specify connection details when the model uses one data source; if there are several, use te add '<table>' -t Table --source-table '<schema.table>' --data-source '<data source name>' --model '<model path>' --save to specify which source. This works for SQL Server, Azure SQL, and Fabric SQL sources.

For existing tables, you can now:

  • Add a single data column without recreating the table, with te add '<table>/<column>' -t DataColumn -p 'SourceColumn=<source column>' -p 'DataType=<type>' --model '<model path>' --save.
  • Add new source columns and update changed data types without losing existing column metadata, with te set '<table>' --update-schema --source sql --endpoint '<source server>' --source-database '<source database>' --source-table '<schema.table>' --model '<model path>' --save for a SQL source.

Columns that are in the semantic model but missing from the source flash a warning and are kept unless you pass --drop-removed-columns. A source-column rename is treated as a removal and an addition. To preserve the existing model column and DAX expressions that refer to it, update its binding with te set '<table>/<column>' -p 'SourceColumn=<new name>' --model '<model path>' --save.

Refresh and tracing

refresh --trace previously stopped collecting events as soon as the refresh command returned, even when the server still had events waiting to be delivered. Logs could therefore end mid-processing, without the events confirming that processing and the commit had finished. The CLI now waits briefly for those final events. Selecting a model with -d '<model ID>' also used to produce an empty log because the CLI did not recognise the model name in the incoming events. The CLI now matches both the model's name and its ID, so --trace can match either.

Refresh durations and throughput are now reported using the server's event timestamps when available. Previously, the CLI used the time each event arrived. Events delivered together could make a long operation appear to finish almost instantly, inflating the rows/second metric. Refresh output also reports measurements such as duration, throughput, CPU time, and memory use instead of subjective verdicts like "excellent" or "below typical".

Post-refresh VertiPaq statistics, such as each table's row count and size in bytes, are now included in JSON output when enabled by vertipaqOnRefresh. Previously, these statistics were only shown in text output. Automation can now read these values from the vertipaq array, so you can track model growth after a refresh.

Other fixes

  • te save-as --model '<model path>' -o '<output folder>' --serialization pbip fixes invalid semantic model exports within Power BI projects (the .SemanticModel folder), which previously prevented Power BI Desktop from opening the project.
  • Saving a model now produces consistent files across Windows, macOS, and Linux. Exports committed to Git on macOS and Linux can be cloned or checked out on Windows without invalid filenames. Table definitions are read from model folders in a consistent order, so saving them to a .bim file no longer rearranges the table list depending on the machine. Together with consistent line endings, this reduces file differences when the model itself has not changed.
  • diff now reports the correct object types and paths and detects changes in collections it previously missed, including partitions, hierarchies, and named expressions such as the shared Power Query parameters (e.g. RangeStart and RangeEnd). A CI/CD pipeline comparing models can now detect these changes instead of treating the models as identical. Checks that previously passed because a difference was missed may now fail and need review.
  • Hitting Ctrl-D on an empty prompt now exits interactive mode. Previously, the shortcut left the session open and you had to type exit or quit. With --non-interactive, a command that needs input, such as choosing between multiple local databases, now reports an error instead of waiting for a response that could never come. A pipeline can detect the non-zero exit code and report a failed step instead of remaining stuck.
  • Names containing square brackets no longer crash progress spinners. A workspace or model name such as Order to Cash [Dev] is now printed as written; previously, the terminal formatting code tried to interpret [Dev] as a color or style and failed.
  • Errors on the stderr stream retain their coloring when stdout is piped or redirected, so errors remain highlighted in the terminal while command results go elsewhere.

Update checklist

If you are upgrading from an earlier preview, check scripts for these changes. Removed flags and commands will fail; deployment and refresh need --execute to perform the operation:

UsageBeforeIn 0.7.0
Read a propertyte get '<table>/<object>' -q Description --model '<model path>'te get '<table>/<object>' -p Description --model '<model path>'
Set a propertyte set '<table>/<object>' -q Description -i '<description>' --model '<model path>' --savete set '<table>/<object>' -p 'Description=<description>' --model '<model path>' --save
Select a local modelte get '<table>/<object>' '<model path>'te get '<table>/<object>' --model '<model path>'
Deploy to a targetDeployment used -s / -d for the target and executed by defaultte deploy --model '<model path>' --target-server '<workspace>' --target-database '<model>' --execute
Refresh a deployed modelRefresh executed by defaultte refresh -s '<workspace>' -d '<model>' --execute
Save a deployment previewDeployment script output used --xmlate deploy --model '<model path>' --target-server '<workspace>' --target-database '<model>' > deploy.tmsl
Preview a refreshPreview required --dry-runte refresh -s '<workspace>' -d '<model>'
Save to a format or locationte save --model '<model path>' -o '<output folder>' --serialization tmdlte save-as --model '<model path>' -o '<output folder>' --serialization tmdl; save remains an alias outside interactive mode
List objectste ls --model '<model path>'te get --model '<model path>'; ls and list remain shortcuts
Inspect dependencieste deps '<table>/<object>' --model '<model path>'te get '<table>/<object>' --deps --model '<model path>'; deps remains a shortcut
Format a model expressionte format --path '<table>/<object>' --model '<model path>' --savete set '<table>/<object>' --format Expression --model '<model path>' --save
Format standalone DAXte format -e '<DAX expression>'te util format-dax '<DAX expression>'
Format standalone Mte format -e '<M expression>' --lang mte util format-m '<M expression>'
Look up TE2 command equivalentste migratete util migrate
Read a refresh policyte incremental-refresh show '<table>' --model '<model path>'te get '<table>/RefreshPolicy' --model '<model path>'
Change a refresh policy's rolling windowte incremental-refresh set '<table>' --rolling-window-periods 5 --model '<model path>' --savete set '<table>/RefreshPolicy' -p RollingWindowPeriods=5 --model '<model path>' --save
Apply a saved policy and refreshThe old policy-application command created partitions onlyte refresh --apply-refresh-policy '<table>' -s '<workspace>' -d '<model>' --execute
Create policy partitions without loading datate incremental-refresh apply '<table>' -s '<workspace>' -d '<model>'te script --inline 'Model.Tables["<table>"].ApplyRefreshPolicy();' -s '<workspace>' -d '<model>'
Run a script file and save editste script --script '<script.cs>' --model '<model path>' --savete script --file '<script.cs>' --model '<model path>' --save
Run inline C# and save editste script -e '<C# code>' --model '<model path>' --savete script --inline '<C# code>' --model '<model path>' --save
Compile a script without running itte script --script '<script.cs>' --dry-run --model '<model path>'te script --file '<script.cs>' --validate
Inspect a local modelte load --model '<model path>'te get . --model '<model path>'
Inspect a deployed modelte load -s '<workspace>' -d '<model>'te get . -s '<workspace>' -d '<model>'
Open the desktop applicationThe open command launched TE3 DesktopTabularEditor3.exe
Replace text in model propertiesThe replace command performed bulk replacementste script --file replace-descriptions.cs --model '<model path>' --save; the script is below
Read findings from JSONDifferent structures across commandste validate --model '<model path>' --output-format json returns summary and findings; BPA, tests, and queries use the same findings structure
Read changes from JSONCommand-specific output; diff had an entry per propertyte diff '<before model path>' '<after model path>' --output-format json returns one entry per object in changes, with objectPath, changeKind, and a properties array
Run the six VertiPaq BPA rulesBundled VPA_ rules and --vpa-ruleste bpa run --rules BPARules.json --model '<model path>'; for Bpa.Analyze(), store the rules in the model
Address names containing reserved charactersUnquoted names could be acceptedte get "Invoiced Sales/'Revenue?'" --model '<model path>' in PowerShell

With deploy, -s and -d now select the source model. To copy between workspaces, use te deploy -s '<source workspace>' -d '<source model>' --target-server '<target workspace>' --target-database '<target model>' --execute.

For bulk replacements previously done with replace, use a C# script that selects the objects and properties to change. For example, save this as replace-descriptions.cs to replace "euros" with "EUR" in the descriptions of measures in the Invoiced Sales table:

foreach (var measure in Model.Tables["Invoiced Sales"].Measures)
{
    measure.Description = measure.Description?.Replace("euros", "EUR");
}

Preview the description changes with te script --file replace-descriptions.cs --model '<model path>'. To save them, run te script --file replace-descriptions.cs --model '<model path>' --save. Both commands print a before/after diff of the changed descriptions.

The shared change format applies to diff, set, add, remove, move, script, and bpa run --fix. Update any scripts that read JSON output from these commands.

Object names containing {, }, *, or ? now need quotes around them when used as input. For a measure named Revenue? in the Invoiced Sales table, the PowerShell example is te get "Invoiced Sales/'Revenue?'" --model '<model path>'. The inner single quotes (') tell the CLI that ? is part of the measure's name. The outer double quotes (") keep the full path together when PowerShell passes it to the CLI. Update paths in scripts that address objects with these characters in their names.

Further Reading

In conclusion

The main changes in 0.7.0 give you more visibility into what a command will change and make its results easier to read in automation. Before upgrading an existing pipeline, check which commands need replacing, add --execute where deployment or refresh should run, and update scripts for the new JSON formats.

Download the preview from the Tabular Editor CLI download page. The CLI documentation covers installation, authentication, and command usage.

Report bugs through GitHub issues, or share questions and feedback in GitHub discussions.

Take your semantic models further with Tabular Editor.

Give Tabular Editor a spin
Plagiarism-freeScanned on September 9, 2026 Human-writtenScanned on September 9, 2026