“We need to move to Qlik Cloud.” That sentence kicks off a project that sounds like a lift-and-shift but is actually a full rethink of how your data reaches your dashboards.
I recently completed a migration of a large QlikView environment to Qlik Sense Cloud for a manufacturing company. What started as “migrate the apps” became a ground-up redesign of the data architecture — because QlikView’s patterns don’t survive the move to cloud unchanged.
Here’s what I learned, and what I’d tell you before you start yours.
Why You Can’t Just Lift and Shift
QlikView apps are self-contained. Each app typically has its own data connection, its own load script, its own transformations. This works on-premises because you’re connecting directly to databases via ODBC. Network latency is negligible. Security is handled by Active Directory. The server does everything.
Qlik Cloud changes all of that:
- No direct ODBC to your ERP. Your data must travel through a pipeline — a gateway, an API, or a replication tool — before Qlik can touch it.
- Data residency and egress matter. Moving gigabytes through APIs daily has cost and performance implications.
- Spaces replace server folders and security rules. The entire governance model changes.
- Section Access uses email addresses, not Windows usernames.
- No Qlik Publisher. Distribution and automation work differently.
If you approach this as “convert QlikView scripts to Qlik Sense scripts,” you’ll end up with dozens of apps that each pull data independently, hammering your pipeline and duplicating transformations. The same mess you had before, now slower and more expensive.
Step 1: Map Your Data Before Touching Apps
Before converting a single app, I mapped every data dependency:
- Which QlikView app uses which tables?
- Which fields from each table?
- Where do transformations happen — in the load script or in the front-end?
- Which apps share data that could be centralised?
This produced an app-to-QVD matrix — a lookup table showing exactly which ERP tables feed which apps. Without this, you’re migrating blind.
The matrix immediately revealed that several tables were loaded and joined independently in almost every app — article master data, supplier info, cost prices. In QlikView, this was tolerable. In cloud, it’s dozens of apps each making the same API calls and running the same joins. That’s where the architecture redesign starts.
Step 2: Design the Data Layer
The core architecture decision: build a shared data layer that all apps consume, instead of letting each app extract its own data.
Three tiers:
Tier 1: Raw QVDs (landing zone)
A pipeline extracts data from the ERP’s cloud data lake using CDC (Change Data Capture) and lands it as QVD files in Qlik Cloud’s managed storage. Dozens of tables, refreshed daily. These are the raw materials — append-only CDC records, not yet deduplicated.
Tier 2: Deduplicated QVDs
Here’s the challenge with CDC from a cloud data lake: it’s often append-only. Every change to a record creates a new row with the same business key but a newer timestamp. Your raw QVDs grow indefinitely, and every record has duplicates.
I built a generic deduplication subroutine that:
- Reads each raw QVD
- Groups by the ERP’s business primary key (composite keys handled via concatenation)
- Keeps only the most recent version of each record
- Filters out soft-deleted records
- Writes a clean QVD
This runs as a backend app in Qlik Cloud, processing all tables in one reload. The dedup key definitions are maintained in a CSV — adding a new table means adding one row, not writing new code.
Tier 3: Custom QVDs (shared dimensions)
Some data doesn’t exist in a single source table. The article master, for example, requires joining a dozen ERP tables — general attributes, procurement data, production parameters, warehouse settings, purchase prices, costing, planning, sales config.
In QlikView, each app did this join independently. In the new architecture, a single backend app produces one unified article master QVD that all frontend apps consume.
Same pattern for the calendar dimension. The old QlikView apps had multiple inline calendar definitions, each slightly different. One had weeks starting on Sunday. Another calculated “rolling 12 months” differently. I replaced all of them with a single shared calendar QVD — one definition, consistent everywhere.
Step 3: CDC vs. Full Load — The Architecture Decision
This was the biggest design decision of the project. Two options:
Full Load (Replicate-style): Extract the entire table every night. Simple. Guaranteed fresh. But: some tables are over 1 GB. Extracting dozens of tables in full daily means moving several gigabytes through the API every night. Egress costs add up. Pipeline runtime grows with data volume, not change volume.
CDC with deduplication: Extract only changes. Smaller payloads, faster pipelines. But: requires a dedup step, stores two copies of each QVD (raw + dedup), and needs careful key management.
I chose CDC. The reasoning:
- Scalability. Full loads get slower as the business grows. CDC stays proportional to daily change volume.
- Future-proofing. The raw CDC layer preserves change history — useful for slowly changing dimensions, audit trails, and temporal analysis down the road.
- Cost. API egress is metered. Moving only changes is cheaper at scale.
The trade-off is complexity. You need reliable dedup logic, and you need to handle edge cases — tables where CDC keys differ from the business primary key, records that arrive out of order, tables where the data lake doesn’t expose all fields.
This is a decision you should make deliberately, not by default. For smaller deployments (under 20 tables, under 1 GB total), full load is simpler and the cost difference is negligible. For larger environments, CDC earns its complexity.
Step 4: Space Governance
Qlik Cloud uses spaces instead of QlikView’s server folders and security rules. Getting this right early saves painful restructuring later.
The model I implemented:
| Space | Type | Purpose |
|---|---|---|
| ERP Data | Data | QVD storage, pipeline connections, backend reload apps |
| Apps DEV | Shared | Development and testing — developers have full access |
| Apps PRD | Managed | Production — business users have view-only access |
The workflow: develop in DEV, test, then publish to PRD. Publishing creates a read-only copy. Business users never touch the development version.
This mirrors a DTAP pattern (Development → Test → Acceptance → Production) adapted for Qlik Cloud’s space model. QlikView had no native equivalent — most QlikView environments relied on folder permissions and manual file copies.
Step 5: Convert the Apps
With the data layer in place, converting the actual apps is the straightforward part:
- Rewrite load scripts to consume QVDs from the shared data layer instead of making direct ODBC connections.
- Remove redundant transformations — if the data layer already handles dedup, calendar, and master data joins, the app script shrinks dramatically.
- Update Section Access from Windows usernames to email addresses.
- Recreate visualizations in Qlik Sense’s sheet-based UI.
For dozens of apps, this is still significant work. But the data layer means each app’s load script is now 50-200 lines of QVD reads and field selections, instead of 500+ lines of ODBC queries and inline transformations.
Deployment Automation
At dozens of apps, manual deployment doesn’t scale. I built a CLI-based deployment pipeline:
- Create apps in DEV with correct space assignment
- Set load scripts from version-controlled
.qvsfiles - Upload branded thumbnails (generated programmatically — consistent 640x400 PNGs)
- Reload and validate
- Publish to PRD space
All scripts and QVS files live in git. Deploying a change to production is: edit the .qvs file, push, run the deploy script.
Step 6: The Reload Chain
In QlikView, reloads were typically triggered by Qlik Publisher or Windows Task Scheduler. In Qlik Cloud, you use Automations (or the API).
The daily reload chain:
01:00 Pipeline lands CDC data from ERP data lake
03:00 Raw QVDs stored automatically
03:30 Backend: Deduplicate all tables → clean QVDs
04:00 Backend: Generate MasterCalendar + shared dimension QVDs
05:00 Frontend: Reload all apps (parallel)
Order matters. Frontend apps depend on backend QVDs. Backend QVDs depend on the pipeline landing. Getting this chain wrong means dashboards showing yesterday’s data — or worse, partially updated data from a mix of today and yesterday.
What I’d Do Differently
Start with the data layer earlier. I initially underestimated how much work the CDC dedup pipeline would require. The generic subroutine handles most tables, but edge cases (composite keys, missing fields, tables not in the Data Lake) consumed more time than expected.
Build the app-to-QVD matrix first, not in parallel. The dependency mapping revealed the shared data opportunities that shaped the entire architecture. Doing this before any conversion would have saved rework.
Budget time for Qlik Cloud quirks. Thumbnail propagation doesn’t work via the REST API — you need the Engine WebSocket. New apps created via CLI have a phantom “Section” tab. These are small issues individually, but they add up when you’re deploying dozens of apps.
The Dataflow Lens
This migration is a textbook example of why full-chain thinking matters. The apps — the visible part — are the last step. The real work is upstream:
- Business processes generate ERP data
- Source system exposes it via data lake API (CDC, append-only)
- Pipeline lands it in cloud storage (daily)
- Data layer deduplicates, joins, and standardises (QVDs)
- Apps consume clean data and present it as dashboards
Touch any layer without understanding what’s upstream and downstream, and something breaks. That’s true for QlikView-to-Cloud migrations. It’s true for any data project.
Planning a QlikView to Qlik Cloud migration? Book a call and let’s map what your migration actually involves — before you start converting apps.