Best Cloudflare D1 Alternatives (2026)
D1 is a good product with a very specific shape: SQLite, managed by Cloudflare, bound directly to a Worker, billed on rows read and written. If your app lives inside Workers and your data is modest, it is close to frictionless — no connection strings, no pool, no separate provider to pay.
The reason people go looking for alternatives is almost always a wall rather than a preference, and which wall you hit determines which alternative is right. There are four common ones: database size, write throughput and the single-writer model, feature gaps where you wanted Postgres semantics, and the awkwardness of reaching that data from anything that is not a Worker. Diagnose yours first — moving from D1 to something that shares the same constraint is a lot of migration for no benefit.
Which wall did you hit?
- Size. SQLite databases in a managed edge product carry a per-database size cap. The usual workaround is sharding by tenant, which is elegant if your data is naturally per-tenant and miserable if it is not.
- Writes. SQLite has one writer. Read replication is easy and write concurrency is not, so a write-heavy workload will feel this no matter how it is hosted.
- Postgres features. If you found yourself wanting real types, extensions like pgvector or PostGIS, materialised views, or LISTEN/NOTIFY, you did not outgrow the host — you outgrew SQLite.
- Access from elsewhere. A queue worker, a cron job, a batch importer, or your analytics stack all wanting the same data is where an edge-bound database starts to feel like a locked room.
Turso — stay on SQLite, lose the ceiling
If SQLite is right for you and only the hosting is wrong, Turso is the obvious move. It is libSQL — a SQLite fork — as a managed service, with embedded replicas that put a local copy next to your app and sync in the background, and a database-per-tenant model that is a first-class pattern rather than a workaround.
This is the least disruptive migration on the list, because your SQL barely changes. It also does not fix anything that is inherent to SQLite: writes still funnel through one writer per database, and you still do not get Postgres extensions. Choose Turso when the answer to 'is SQLite still the right engine?' is yes.
Neon and Supabase — the serverless Postgres answer
If you outgrew the engine rather than the host, you want Postgres, and Neon is the most direct swap: managed Postgres with separated storage and compute, scale-to-zero on idle, and database branching that fits the preview-per-pull-request workflow well. Supabase gives you Postgres plus a whole backend — auth, storage, realtime, generated APIs — which is more than you asked for if all you wanted was a database, and exactly right if you were going to build those anyway.
The friction to plan for when moving from D1 to any Postgres is connections. A Worker or a serverless function can open a connection per invocation, and Postgres does not enjoy that. Every serious option in this tier ships a pooler or an HTTP driver for exactly this reason — use it, and do not try to hold a raw pool in a serverless runtime.
PlanetScale — if the wall was write throughput
PlanetScale's Vitess heritage means horizontal scaling is the core capability rather than an add-on, which makes it the right shape for genuinely write-heavy or very large workloads. The trade is that its constraints are opinionated — the schema-change workflow is a feature, and the historical limits around foreign keys and certain query patterns are real. It is a serious platform for a serious scale problem, and overkill for a D1 app that outgrew a size cap.
PandaStack — a Postgres VM per database, asleep when idle
PandaStack is our project. Our managed databases are real PostgreSQL 16, each running in its own Firecracker microVM on a durable volume rather than as a schema on a shared cluster — so a noisy neighbour is a different machine, not a different row in the same table. You get a normal connection string over TLS, plus an HTTP query broker for callers that cannot hold a TCP connection, which is the relevant one if you are coming from Workers.
# Create a database and read the connection string back.
pandastack db create --label app-prod --size 1g
pandastack db get <id>
# connection_url: postgres://pandastack:...@<id>.db.pandastack.ai:5432/pandastackWhat we do well for the D1 refugee: databases auto-suspend when idle and wake on connect, so a dev or low-traffic database bills storage only while asleep. Branching a database is a copy-on-write clone of the source rather than a dump and restore, which makes per-pull-request databases practical. Point-in-time recovery, backups, and failover are included rather than a tier. Billing is $0.054 per active vCPU-hour and $0.0162 per working-set GiB-hour while awake, plus $0.15 per GiB-month of storage, with no egress charge.
What we do not do, plainly: we are not at the edge. Your database lives in a region, and a Worker in Sydney talking to a database in Virginia pays the round trip — that is physics, and D1's colocation with your Worker is a real advantage we do not replicate. We do not offer read replicas across regions today. And if your reason for using D1 was that it required no connection management at all, a Postgres connection string is a step back in convenience even with a pooler.
When the right answer is to stay
Worth saying, because roundups rarely do: a lot of D1 migrations should not happen. If your app is Workers-native, your data is small and per-tenant, your traffic is read-dominated, and you are hitting a quota rather than a structural limit, sharding across more D1 databases or raising a limit is far less work than moving to a different engine and rewriting your data access. Migration is only cheap in the planning document.
Choosing, briefly
SQLite still right, host wrong: Turso. Outgrew the engine and want Postgres with the least fuss: Neon. Want the rest of a backend with it: Supabase. Genuinely write-heavy at scale: PlanetScale. Want isolated Postgres that sleeps when unused, branches cheaply, and does not charge for egress — and you can live with a regional database instead of an edge one: that is where we fit.
Frequently asked questions
Can I use Postgres from a Cloudflare Worker?
Yes, but not with a conventional connection pool — Workers are short-lived and a per-invocation TCP connection to Postgres is a good way to exhaust its connection limit. The two workable patterns are an HTTP query endpoint, which most serverless Postgres providers offer, or Cloudflare's own outbound TCP support pointed at a pooler running in transaction mode. Either way the pooler is not optional; treat it as part of the database, not an optimisation.
Is SQLite good enough for production?
For an enormous number of applications, yes. The honest limit is not reliability — SQLite is among the most tested software in existence — but concurrency: one writer at a time per database. If your workload is read-dominated, or naturally shards into one database per tenant, that limit may never bind. If you have many concurrent writers touching shared rows, you will feel it early, and no amount of hosting cleverness removes it.
How do I migrate data out of D1?
Export the database to SQL, then adapt the schema for the target engine — the schema is where the work is, not the data. Moving to Turso or another libSQL host is close to a lift-and-shift. Moving to Postgres means real translation: SQLite's flexible typing becomes strict column types, AUTOINCREMENT becomes an identity column or a sequence, and datetime handling needs deliberate attention because SQLite stores dates as text or numbers by convention rather than as a type. Do it on a copy, run both in parallel behind a flag, and cut over when the read path matches.
What does 'scale to zero' actually mean for a database?
That the compute stops when nothing is connected, and you keep paying only for stored data. It matters most for the long tail of databases that are not production — dev, staging, per-branch previews, a demo — where the machine is idle for the majority of every day. The number to check is what waking costs: if a first connection after idle takes many seconds, scale-to-zero is a bad trade for anything user-facing and a good one for everything else.
Keep reading
49ms p50 cold start. Fork, snapshot, and scale to zero.