Regulation
The EU Data Act wants cloud customers to be able to leave. Could you?
A right to switch means little if your data only opens in one product. Try the exit before you need it.
Published 7 min read
Jump to the export drill
Photo: Belgique - Bruxelles - Schuman - Berlaymont - 01, EmDee, CC BY-SA 4.0, via Wikimedia Commons.
The EU Data Act, formally Regulation (EU) 2023/2854, has applied since 12 September 2025. Among other things, it sets rules for customers who want to switch data-processing services, such as cloud and SaaS products, to another provider or to their own systems. Law-firm commentary describes duties on providers to remove obstacles to switching and to be clear about how switching works.
This article is not legal advice, and it summarises law-firm commentary rather than the full text. The regulation phases in over time, some duties start on later dates, and what applies to you depends on where you and your provider operate. Check the regulation and ask a lawyer before you rely on any detail below.
| Point reported by commentators | Date or detail |
|---|---|
| Regulation applies | 12 September 2025 |
| Cloud switching and portability duties | Providers must support switching to another provider or to on-premises systems, and remove obstacles that block it. |
| Notice to end a contract | One law-firm summary says customers can terminate with a maximum of two months' notice. |
| Switching and data-extraction charges | Generally barred from 12 January 2027, with limited cost-based exceptions in the meantime and for some cases. |
| Connected products | Further design duties for data access by default apply from 12 September 2026, according to one summary. |
Sources for the table are Morgan Lewis and Kennedys. They agree on the September 2025 start and the January 2027 fee date.
A right on paper, a file in practice
Even where the law helps, you still need to know what you would take with you, in what format, how long it would take and whether it would work somewhere else. Many teams discover the answers in the middle of a bad week, such as a price rise, an outage or an acquisition. A drill beforehand turns surprises into a checklist.
Start with an inventory
List what each service holds. Include things that are easy to forget: files, settings, user accounts and permissions, history and audit logs, automations, and anything stored in the provider's own proprietary format.
CREATE TABLE service_inventory (
id INTEGER PRIMARY KEY,
service TEXT NOT NULL,
data_kind TEXT NOT NULL,
export_format TEXT,
export_tested_on TEXT,
rows_expected INTEGER
);
-- What have we never tried to get out?
SELECT service, data_kind
FROM service_inventory
WHERE export_tested_on IS NULL;Anything that returns from the last query is a lock-in risk you have not measured.
Run an export drill
Pick one system and try to leave it, as a test. This example moves a table out of one SQLite file, through CSV, into another SQLite file, and then checks that nothing changed. It was run exactly as shown.
-- source.db
CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_code TEXT NOT NULL,
total_cents INTEGER NOT NULL, created_at TEXT NOT NULL);
INSERT INTO orders VALUES (1,'00123',1999,'2026-01-05'),
(2,'00456',4500,'2026-02-11'),
(3,'00789',250,'2026-03-30');
.headers on
.mode csv
.once orders.csv
SELECT * FROM orders;-- target.db: declare the types before importing
CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_code TEXT NOT NULL,
total_cents INTEGER NOT NULL, created_at TEXT NOT NULL);
.mode csv
.import --skip 1 orders.csv ordersDeclaring customer_code as TEXT before the import is deliberate. It kept the leading zeros in codes such as 00123. If a tool guessed the type, it could have turned that into the number 123. The CSV export article covers that pitfall in detail.
Prove the copy is complete
"The import finished" is not proof. Compare counts, totals, ranges and a fingerprint of the rows in both databases.
SELECT COUNT(*) AS rows_n,
SUM(total_cents) AS total_cents,
MIN(created_at) AS first_date,
MAX(created_at) AS last_date,
group_concat(customer_code) AS codes
FROM orders;
-- both databases: 3 | 6749 | 2026-01-05 | 2026-03-30 | 00123,00456,00789import sqlite3, hashlib
for db in ('source.db', 'target.db'):
c = sqlite3.connect(db)
h = hashlib.sha256()
for row in c.execute('SELECT * FROM orders ORDER BY id'):
h.update(repr(tuple(row)).encode())
print(db, h.hexdigest()[:16])
# source.db a2644abc819adaf0
# target.db a2644abc819adaf0Matching fingerprints mean the two copies hold the same values for that table. For tables too large to hash row by row, compare counts and totals per month or per key range, and spot-check some rows by hand.
What usually does not come out
- Permissions, roles and sharing settings.
- Change history, comments and audit logs.
- Automations, scheduled jobs and integrations.
- Files and attachments referenced by ID but stored elsewhere.
- Calculated fields and views defined in the provider's own language.
- Identifiers that only mean something inside the old system.
Write down each one and decide whether you need it. A migration plan that mentions only the main tables will meet the rest on the day.
Which formats to prefer
| Format | Good for | Watch for |
|---|---|---|
| CSV | Simple tables, readable everywhere. | No types. Dates, leading zeros and encodings need care. |
| JSON | Nested data and APIs. | Large files, and number precision in some readers. |
| SQLite file | A whole database in one portable file. | Not for heavy concurrent writes. Copy it with the backup command, not a plain file copy, if it is in use. |
| SQL dump | Recreating a database with schema. | Dialect differences between engines. |
| Proprietary export | Moving between versions of the same product. | May only open in the product that made it. |
Read the exit terms before you need them
- 01NoticeHow long does the contract require before you can leave?
- 02Export tools and formatsWhat does the provider offer, and is it documented?
- 03FeesAre there charges for extraction or for data transfer out?
- 04RetentionHow long is your data kept after you leave, and how do you confirm deletion?
- 05Backups and logsDo they come with you, and what happens to the copies the provider keeps?
Measure what you would have to move
An exit plan starts with a number. How big is the data, and how long would a copy take? Both are easy to find out ahead of time. In PostgreSQL, the size functions give you the total for a database and a ranking of the largest tables. These queries were run on a small test server.
SELECT pg_size_pretty(pg_database_size(current_database()));
-- 7847 kB on the test server
SELECT relname, pg_size_pretty(pg_total_relation_size(oid)) AS total_size
FROM pg_class
WHERE relkind = 'r' AND relnamespace = 'public'::regnamespace
ORDER BY pg_total_relation_size(oid) DESC
LIMIT 5;For a SQLite file, the size is the file size. Inside SQLite you can ask for it with two pragma functions, which also worked on the test file:
SELECT page_count * page_size AS bytes
FROM pragma_page_count(), pragma_page_size();Then do the arithmetic. A 200 gigabyte database over a connection that sustains 100 megabits a second moves about 12.5 megabytes a second, so the copy alone takes a little over four hours, before any verification and before any provider throttling. If your provider charges for data leaving its network, ask for the price in writing. The Data Act commentary reports that switching and extraction charges are generally to be barred from 12 January 2027, so the answer may change over time.
Check that the data is portable between engines
Moving between providers often means moving between engines or versions. Differences in types and identifiers are where migrations stall. A short table of the usual suspects:
| Topic | What can differ | What to do |
|---|---|---|
| Types | SQLite stores values by their actual type in a flexible column. PostgreSQL enforces column types strictly. | Declare types explicitly before importing, and check that no values are rejected. |
| Auto-generated IDs | SQLite uses an integer primary key. PostgreSQL uses sequences or identity columns. | After import, set each sequence past the highest existing ID. |
| Dates and times | Stored as text, numbers or native types depending on the engine. | Pick one format, ideally ISO 8601 text or a native timestamp, and convert on export. |
| Booleans | Stored as 0 and 1, or as true and false. | Convert explicitly and test with both values. |
| Collation and case | Sorting and equality rules differ. | Compare sorted samples, not only counts. |
| Views, triggers and functions | Written in engine-specific dialects. | Plan to rewrite them, and test results against the old system. |
Restore somewhere else
The real test of an export is loading it into a different environment and using it. Stand up the target, load the data, and run the five queries your business cannot live without. Compare their results with the source.
- 01Pick the five most important queriesReports, invoices, the customer lookup, the month-end totals. Write them down.
- 02Run them on the source and save the outputKeep the numbers with a date.
- 03Load the export into the targetA scratch database or a laptop is enough.
- 04Run the same queries and compareTotals should match. Differences are your migration bugs.
- 05Time every stepThe slowest step is your real downtime.
A one-page exit plan
Write the result down while the details are fresh. One page is enough, and it is worth more than a ten-page plan nobody reads.
- What the service holds, and who owns each part.
- How to export it, in which format, and how long that takes.
- Where it would go and what that costs.
- What you would lose and how to replace it.
- Who decides, and the contract notice period.
- The date you last tested it.
Questions that come up
- Does the Data Act apply outside the EU?
- It concerns services offered to customers in the EU. Whether it applies to you depends on where you and your provider operate. Ask counsel.
- What is the safest format to export to?
- One that is open, documented and readable without the original product. CSV, JSON and SQLite are common choices.
- How often should I run an export drill?
- At least once a year for each important service, and whenever you change plans, providers or schemas.
- Is a successful export the same as being able to switch?
- No. You also need to load the data somewhere, check it, and rebuild what did not come out, such as permissions and automations.