What actually happens to a DXP analysis file?
A DXP is a single container holding the visualization layout, the data table definitions, calculated columns, document properties, filtering schemes, scripts and — if the analysis was saved with embedded data — the data itself. Power BI splits that into two things: a semantic model that holds tables, relationships and DAX, and a report that holds pages and visuals. Nothing reads a DXP and writes a PBIX, so the file becomes a specification rather than an input.
That split is the first real change your team will feel, and it is a gain. One model can serve several reports, so the definition of a metric stops being re-entered in each analysis. Microsoft's guidance on star schema design (opens in new tab) explains why the reshape matters more than the chart work — a narrow, well-related model compresses and queries far better than the wide tables a long-lived analysis accumulates.
Scope note: this page covers Spotfire analyses delivered through Spotfire Analyst and Web Player, whether you are on a self-hosted Spotfire Server or the hosted service. Bespoke applications built on the Spotfire JavaScript or .NET APIs are software projects rather than reporting work, and we would scope those separately rather than fold them into a report rebuild.
How do Spotfire concepts map to Power BI?
Here is the working map we build the plan from. It is deliberately dull — a good migration is one where nothing surprising happens after the estimate is signed.
Spotfire objects and their Power BI equivalents
| Spotfire |
Power BI equivalent |
What changes in practice |
| DXP analysis file |
PBIX report plus a shared semantic model |
Layout and model separate, so one model can serve several reports instead of each analysis carrying its own |
| Spotfire Library folder |
Workspace and published app |
Library permissions become workspace roles and app audiences; folder structure usually simplifies on the way |
| Information Link |
Power Query query, or a Dataflow for shared logic |
A server-side reusable query becomes a documented transformation step you can see and version |
| Information Designer elements (columns, filters, joins, procedures) |
Star-schema tables, relationships and DAX measures |
The agreed semantic layer survives as a model; near-duplicate column elements collapse into one definition |
| In-database data connection |
DirectQuery, or a composite model |
Storage mode is decided per table rather than once for the whole analysis |
| Imported data table / SBDF file |
Import-mode table (VertiPaq) |
Loose SBDF extracts are usually traced back to the source and connected properly instead of re-imported |
| Calculated column and custom expression |
DAX measure, or a Power Query step |
Row-level logic moves to Power Query where it can; genuine aggregation becomes a measure instead of a column |
| OVER with node navigation (Previous, Parent, Intersect) |
DAX with CALCULATE and time intelligence |
Hierarchy-walking expressions become explicit filter context, which is more verbose but far easier to test |
| Document property and property control |
Slicer, field parameter or what-if parameter |
Text-area drop-downs that switched a measure become native field parameters with no script behind them |
| IronPython script (action control or property-change trigger) |
Bookmarks, buttons, field parameters, or DAX |
Power BI has no in-report scripting surface; each script is replaced by a native feature or declared out of scope |
| TERR or Python data function |
DAX measure, Power Query R/Python step, dataflow or Fabric notebook |
Aggregation moves to DAX; real statistics keep their code but run upstream of the report |
| Spotfire Statistics Services |
Scheduled dataflow or notebook writing results to a table |
A separate statistics server stops being infrastructure you run and patch |
| Marking |
Cross-highlighting, cross-filtering and drillthrough |
Highlighting is native; marking that feeds a calculation needs a designed replacement, usually a measure reading the selection |
| Filtering scheme |
Bookmarks over slicer and filter state |
Named filter states become named bookmarks; per-page filter scope becomes explicit rather than implicit |
| Filters panel (range, item, check box) |
Slicers and the filter pane |
The always-visible filter column usually becomes a smaller set of slicers people actually use |
| Spotfire Mod or custom visualization |
AppSource custom visual, or a native rebuild |
Each one is triaged individually; we never promise a like-for-like match we cannot ship |
| Information Link filtered by the current user |
Row-level security role |
Per-user filtering moves from the query to the model, where it can be tested by viewing as each role |
| Web Player |
Power BI Service |
Browser delivery without the Spotfire Server and node manager estate behind it |
| Automation Services job |
Scheduled refresh, subscriptions and paginated exports |
Scheduled opens and emailed PDFs become refresh schedules and subscriptions |
The modeling half of that table is the same discipline covered on our Power BI data modeling and DAX page. Where Information Links are shared across many analyses, the reusable transformation layer is built once as a dataflow — Microsoft's introduction to dataflows (opens in new tab) covers how that reuse works. Where links are filtered per user today, our guide to Power BI row level security setup covers how we build and test the replacement roles.
What do we do with the IronPython scripts?
This is the question that decides whether your estate is a three-week job or a three-month one, and it is the reason a Spotfire migration is not interchangeable with a Tableau or Qlik one. Scripts in Spotfire are wired to text-area action controls and to document-property change triggers, and where a script has to react to a marking or filtering change it is normally reached indirectly — a data function or a property binding turns the interaction into a property change, and the property change fires the script. Untangling that chain is the work.
So every script gets read and sorted into one of four buckets. Interface behaviour — resetting filters, switching a page, showing and hiding visuals, toggling a measure — becomes bookmarks, buttons and field parameters, and Microsoft's documentation on report bookmarks (opens in new tab) covers most of what that bucket needs. Calculation becomes a DAX measure. Data preparation moves to Power Query or a dataflow. What is left is genuine application logic — writing back to a database, calling an external system, orchestrating a process — and that belongs in an application, not in a report. We name those explicitly in the inventory rather than discovering them in week three, because Power BI deliberately has no in-report scripting surface and pretending otherwise is how these projects go wrong.
And the TERR data functions?
Data functions are triaged on what they actually compute. A surprising share are aggregations, rankings or variance calculations written in R because a custom expression felt harder at the time; those become DAX measures and get faster in the process. The genuine analytics — forecasting, clustering, regression, design-of-experiments work — keeps its code, but the code moves out of the report and upstream, into a Power Query R or Python step, a scheduled dataflow, or a Fabric notebook that writes its results to a table the model reads. Either way the dependency on TERR and on Spotfire Statistics Services ends with the migration, which is usually a stated goal rather than a side effect.
Where the analytics workload is substantial enough to deserve its own platform rather than a refresh step, our Microsoft Fabric consulting work picks that up as a separate workstream with its own scope.
What does it cost and how long does it take?
Work runs on prepaid Flex hours that never expire: Starter $2,500, Growth $4,600, or Power $8,000, with hourly rates from $100 on the largest block. The analysis, script and data-function inventory usually fits inside a Starter block, and it is the task we recommend buying first, because it converts a vague replatform into a list of scoped items with hours against each one.
After that, cost follows script and data-function density far more than page count — forty clean analyses over three Information Links is a different job from twelve analyses carrying sixty scripts. Individual analyses typically ship within 3–5 business days of approval, and the migration runs as a sequence of those rather than one big-bang cutover. Running both platforms in parallel for a single reporting cycle is worth the overlap: people compare old and new on live data, and the Spotfire licences get handed back with nothing left stranded.
Who this is for
Analytics, engineering and finance teams running Spotfire — commonly in life sciences, energy, manufacturing and process industries, where it took hold for good reasons — with a renewal in sight and a Microsoft 365 or Azure estate already paid for. It is a poor fit for anyone wanting a like-for-like copy with no decisions made, because the duplicated expressions and the abandoned scripts are precisely the things worth resolving in transit. Mixed estates are normal, and each source platform has its own page for a reason: Tableau to Power BI migration is scoped from workbook triage and LOD expressions, Qlik to Power BI migration from the load script and the associative model, and SAP BusinessObjects to Power BI migration from the Universe outward. None of those estates hide their logic in a scripting layer the way a Spotfire estate does, which is why the plans genuinely differ. The broader Power BI migration service covers the Excel and SSRS routes on the same prepaid model.