Dmitriy Kononov
Let’s talkContact

News and analysis

Schema changes, no surprises. Supabase branches, pg-delta and millions of SQLite at Cloudflare

Supabase branches and pg-delta, Cloudflare D1 on SQLite, sequences in Neki, pgrecon for Oracle. How I change a database schema in a live system without broken reports.

Four posts in one week about database structure. Supabase showed how a branch copy of a project is created and how migrations are now built on pg-delta. Cloudflare explained how D1 holds millions of SQLite databases. PlanetScale explained why a sequence in sharded Postgres can't be handed to a shard. And the PostgreSQL news announced pgrecon, a tool for assessing a migration off Oracle. They share one theme: a change to the data structure has to be predictable. For a business it sounds like this: a new field was added to the order, and not a single report or integration broke.

What came out

On October 15, Supabase broke down how a new branch gets its config, migrations and functions. A branch is a separate project, and when it is created three parts run in parallel: copying the settings from the main project, the migrations, and deploying the Edge Functions; the median time to ready is about 20 seconds. Each migration file runs as a single transaction. Each step has a state, RUNNING, EXITED, PAUSED or DEAD, so on a failure you can see what managed to complete.

On October 13, Supabase described Declarative Schemas 2.0 on pg-delta, which it showed on October 2 at Supabase Select. The schema is kept in SQL files, and the CLI writes the migration itself. pg-delta spins up two temporary databases, loads the schema files into one, replays the migration history into the other, compares them through the system catalog and orders the result by the dependency graph. The diff now includes RLS policies, grants, domains, partitions and extension objects, and the CLI flags destructive calls separately.

On October 14, PlanetScale published a note on sequences and other volatile expressions in Neki, its sharded Postgres. There is a class of router-only expressions: now() on different shards gives different times because of clock drift, so it is computed on the router once per query. A sequence needs a center for the same reason: the guarantee that a number won't repeat can't be split between shards.

On October 13, Cloudflare explained how D1 scales to millions of databases. D1 is its serverless database on SQLite. By their numbers as of October 8, 2026, the number of live databases grew 15 times in a year and 65 times in two, and the number active per day grew 18 times in a year. The principles they name: design every process to expect failure and a rerun with no side effects, keep centralized components off the request path, and test the system under load close to the real thing.

On October 22, the PostgreSQL news carried pgrecon 0.7.3, a tool for assessing a migration from Oracle to PostgreSQL under the Apache-2.0 license. It works offline: a read-only script makes a dump, the tool builds an inventory from it, runs 80 rules and gives a range in person-days. Everything that can't be migrated goes into a separate remainder report.

Example: a rental company adds a child seat

A car rental company keeps bookings in a Google Sheet and adds a column, “child seat fee.” The CRM integration expects the old set of columns, the managers' app knows nothing about the new field, and the revenue report sums the wrong thing. That is a schema migration with no tools and no branch where it could be checked. In South Africa that is where I started: the first task was to connect AmoCRM to a Google Sheet so that service cost, mileage and the child seat fee updated in it, then to map the fields of the FlutterFlow app to AmoCRM and set up syncing for the chosen fields. A schema is a contract between systems, and it has to be changed so that every side learns about it in advance.

How it works for me

The “Coffee Together” service is written in React and TypeScript and runs in the Cloudflare Workers runtime with the D1 API on top of a local SQLite database in a Docker volume, on a shared server with 2 GB of memory. The kononov.dev website is on SQLite too.

The first of Cloudflare's principles, a rerun with no side effects, is at work in “Coffee Together”: the import log from the old Google Sheet ties each order to the number of the source row, so loading it again doesn't create duplicates, and a changed row shows up as a conflict. Next to it is a rule I keep for myself: a failed step doesn't damage the working data. The catalog syncs with the Tasty Coffee wholesale API on a schedule, and a failed attempt doesn't wipe the published catalog.

At the PDR company in the US, in 2023 I proposed moving from Google Sheets to a SQL database for speed and a single data format. The idea was accepted, and after the move to MariaDB we connected new services one after another. Any migration is best run on a copy of the database first and released only after that. I haven't run Supabase branches, pg-delta or pgrecon myself and go by their descriptions.

What I would do

Keep migrations as files in the repository with a version number and a table of applied versions in the database itself, the way Supabase does.

Run every migration on yesterday's copy of the working database together with the application and the reports.

Change fields in two steps: first add the new one and move every system to it; remove the old one in a separate release once the list of consumers is empty.

Read the diff the tool wrote with your own eyes, especially everything flagged as destructive.

If the move is between different database engines, start with an inventory and a list of what can't be migrated, following the pgrecon pattern.

On why the state of a system should live in one place, there is an article about the server as the core of the system. The service from this review: “Coffee Together”. Three database decisions people regret later are in the review on cascading deletes, shards and replicas, platforms versus your own server in the review of backends on Vercel, Fly and Supabase, the blast radius of updates in the review of the Netflix tool and TypeScript 7.1. I checked the proxies in front of a database upgrade earlier. Service areas: infrastructure and DevOps and internal systems. If you are about to change the data structure in a running system, tell me what changes and who uses that data. Discuss your task.