Skip to main content
INTERNAL TOOLING

Power BI reports you can diff and review

A generator for validated report JSON, a hook that blocks hand-written files, and a deploy that runs from a script.

THE PROBLEM

What was in the way

A Power BI report normally ships as a binary. Two people cannot work on one without overwriting each other, a change cannot be reviewed before it goes live, and the only record of what changed is whoever remembers clicking it.

For a reporting team keeping an operational dashboard alive, every fix is a manual rebuild in Power BI Desktop and a manual publish afterwards. Nothing about that is reviewable.

THE APPROACH

How it was built

Power BI's project format stores a report as text. The data model becomes TMDL files, and every visual on every page becomes its own JSON file. The report is now reviewable line by line, so the real work is generating those files correctly instead of clicking them into place.

A TypeScript library builds each visual from a field reference, checks that field against the live semantic model, then validates the output against Microsoft's published schemas before anything reaches disk. An editor hook refuses hand-written visual JSON outright. Publishing to the workspace runs from a script rather than a person pressing a button.

Field reference to published report
Field reference to published report
HIGHLIGHTS

How it works

Fields are checked against the real model

A visual binds to a field reference. If that field does not exist, the build stops and hands back the closest matches from the model instead of a report that opens broken.

The guard exists because of one bad batch

Twenty-seven hand-written visual files passed field validation, then produced 102 schema errors in Power BI Desktop. A pre-write hook now blocks hand-written report JSON.

Windows failure modes caught at write time

Path length and a stray byte order mark both break Power BI quietly. The writer checks the path before writing and verifies the encoding after.

RESULTS

What it does now

22 visual typeseach built from a field reference, schema checked
invalid JSON never landsthe write is blocked before the file exists
deploys from sourceno manual publish out of the desktop app
STACK

What it is built on

TypeScriptvisual generation library
Ajvschema validation
Model Context Protocolsemantic model queries
PowerShellpre-write guard hook
Python and fabric-cicddeploy from source
PBIP and TMDLreport stored as text

Got something in your workflow that looks like this?