>DevToolReviews_
Databases2026-05-10

Turso vs Cloudflare D1 Comparison 2026

A practical Turso vs Cloudflare D1 comparison covering architecture, pricing, limits, code, and which SQLite database to use.

#Ratings

avg9.1
Turso
9.1
Cloudflare D1
9.0

I tested Turso and Cloudflare D1 the way I would evaluate a database for a small production product: start with a clean schema, wire it into an edge-friendly TypeScript app, run indexed and unindexed query paths, then price the same workload against each platform's current public docs. The short version: Turso is the better SQLite database when your application can run outside Cloudflare or needs local-first sync. Cloudflare D1 is the better choice when the app already lives on Workers or Pages Functions and you want the database, CDN, compute, and deployment model in one account.

This Turso vs Cloudflare D1 comparison sits between our broader Cloudflare D1 vs Neon vs Supabase Postgres guide and the deployment-focused Vercel vs Netlify vs Cloudflare Pages review. If you are still deciding between SQLite and Postgres, read those first. If you already know you want SQLite semantics with a hosted control plane, this is the decision point.

Architecture and Philosophy

Turso is a SQLite-family database platform built around libSQL and, increasingly, the Turso Database engine. Its strongest idea is portability: you can connect from Node, serverless functions, Docker, mobile, Electron, or edge runtimes. Turso's newer TypeScript quickstart recommends @tursodatabase/database for local or embedded use and @tursodatabase/sync when you need explicit push and pull sync. That tells you the philosophy: keep the database close to the application and make replication a first-class workflow.

Cloudflare D1 is SQLite exposed as a Cloudflare-native database binding. You do not think about TCP connection strings or connection pools. In a Worker, the database appears as env.DB, and queries run through prepared statements, batches, and the Workers runtime. That is excellent if you are already all-in on Cloudflare. It is less portable if your app also needs to run on a conventional Node server, Fly.io VM, Vercel function, or local desktop process.

DimensionTursoCloudflare D1
Core fitPortable SQLite/libSQL for apps across many runtimesSQLite database embedded into Cloudflare Workers
Runtime lock-inLow; works from standard server and edge environmentsHigh; best experience is inside Workers bindings
Replication modelLocal database plus explicit sync or remote serverless clientManaged primary plus optional global read replication via Sessions API
Operational modelDatabase platform you bring to your appCloudflare platform primitive attached to Workers

The architectural difference matters more than the API surface. D1 feels cleaner in a Worker because there is almost nothing to configure. Turso feels more flexible because the same database decision can survive a hosting migration. If I were building a Cloudflare Pages app with Workers middleware, D1 is the natural default. If I were building a SaaS with a web app, queue workers, scripts, and maybe a desktop companion app, I would start with Turso.

Feature Comparison

Both products use SQL, prepared statements, and SQLite-ish semantics. The gap is in platform features around the database. D1 gives you Workers-native bindings, batch execution, Time Travel restore windows, row-based billing, and Cloudflare's global network. Turso gives you many databases, app-local reads, sync workflows, a serverless client, and pricing tiers shaped around rows read, rows written, storage, and sync.

FeatureTursoCloudflare D1Why it matters
TypeScript API@tursodatabase/database, @tursodatabase/sync, serverless clientenv.DB.prepare(), bind(), batch()D1 is simpler inside Workers; Turso is more reusable elsewhere.
Local-first supportStrong; local database plus push/pull sync pathNot the primary modelImportant for desktop, mobile, offline, and branch-like workflows.
Read replicationDesigned around replicas and sync patternsAvailable through D1 read replication and Sessions APID1 requires session-aware code to use replicas correctly.
Restore window1 day free, 10 days Developer, 30 days Scaler, 90 days Pro7 days Free, 30 days Workers PaidBoth are enough for small apps; Turso Pro goes longer.
Maximum database sizePlan storage limits, with overages on paid tiers10 GB per database on Workers Paid, 500 MB FreeD1 pushes you toward many smaller databases.

One non-obvious gotcha: D1's row-read pricing depends on rows scanned, not just rows returned. An unindexed query that returns ten rows can still scan thousands. Turso also bills on row reads, but its product shape makes the tradeoff feel more like a database subscription with usage overages. On both platforms, indexes are not optional optimization work; they are part of cost control.

Performance Benchmarks and Practical Limits

For this review I used a small issue-tracker schema with projects, issues, comments, and events. The useful result was not a universal milliseconds chart, because D1 performance depends heavily on the Worker location, database placement, Sessions API usage, and whether the query scans indexed rows. The useful result was the performance envelope: Turso wins when reads can stay local or close to the application; D1 wins when the request, compute, cache, and database all stay inside Cloudflare's network.

Benchmark scenarioTurso result patternD1 result patternWinner
Indexed lookup by account and slugExcellent, especially with local or nearby readsExcellent inside Workers; simple prepared statement APITie
Unindexed admin searchRows-read cost grows quickly; add the indexRows scanned count directly against D1 row-read billingTie, but D1 makes the billing consequence obvious
Bulk insert seed scriptStraightforward from Node scripts and CI jobsBest via Wrangler/D1 tooling or Worker-side batchesTurso
Edge route reading session dataGood, but still an external database call unless using local/sync modelVery natural when the route is already a WorkerD1
Offline-capable desktop/mobile workflowDesigned for this with local DB plus syncNot the intended product shapeTurso

The official D1 limits are also worth reading before you commit. Workers Paid allows 50,000 databases per account, a 10 GB maximum database size, 1 TB maximum storage per account, 1000 queries per Worker invocation, 100 bound parameters per query, and a 30-second maximum SQL query duration. Free has lower ceilings, including 10 databases, 500 MB max database size, and 50 queries per invocation. Those limits are generous for SaaS control planes, personal apps, and content sites, but not a replacement for a large analytical database.

Turso's standout performance feature is the ability to pull the database closer to where the code runs. The modern docs emphasize local embedded usage and sync; older embedded replicas are now described as legacy, with Turso Sync recommended for new projects that need true local-first reads and writes. That change is important. If your mental model of Turso is only remote libSQL over HTTP, you are missing the product's stronger 2026 direction.

Pricing Comparison

Pricing is where the two products look similar at first and then diverge. Cloudflare D1 is attached to Workers pricing. On Workers Free, D1 includes 5 million rows read per day, 100,000 rows written per day, and 5 GB total storage. On Workers Paid, the current D1 pricing page lists the first 25 billion rows read per month included, then $0.001 per million rows; the first 50 million rows written per month included, then $1.00 per million rows; and the first 5 GB storage included, then $0.75 per GB-month. There are no D1 data transfer charges for data accessed from D1.

Turso's pricing page currently lists Free at $0 with 100 databases, 5 GB total storage, 500 million monthly rows read, 10 million monthly rows written, and 3 GB monthly sync. Developer is $4.99/month with unlimited databases, 9 GB storage, 2.5 billion rows read, 25 million rows written, and 10 GB sync before overages. Scaler is $24.92/month with 24 GB storage, 100 billion rows read, 100 million rows written, and 24 GB sync. Pro is much more expensive at $416.58/month, aimed at serious production workloads that need 50 GB storage, 250 billion reads, 250 million writes, 100 GB sync, and priority support.

WorkloadTurso cost shapeD1 cost shapePractical read
Small hobby appFree tier is enough for many projectsWorkers Free plus D1 is very generousD1 if hosted on Cloudflare, Turso if portable
Small paid SaaSDeveloper at $4.99/month is predictableWorkers Paid includes huge monthly row allowancesD1 can be cheaper if you are already paying for Workers
Many tenant databasesUnlimited databases on paid tiers50,000 databases on Workers PaidBoth are credible; choose by runtime
Local sync-heavy appSync is a priced first-class metricNot the natural shapeTurso
Cloudflare-native content/product appWorks, but adds another vendorIntegrated billing and deploymentD1

My pricing takeaway: D1 is hard to beat for Cloudflare-native apps because the included paid-plan read allowance is enormous. Turso is easier to justify when database portability, local sync, or non-Cloudflare runtimes are part of the product plan. Do not choose Turso just because it is SQLite. Choose it because you want SQLite that can move with the app.

Code Examples: Same Feature, Different Feel

Here is the same basic issue lookup in both tools. D1's version is concise because the database is already bound to the Worker environment.

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const slug = url.searchParams.get("slug");

    const issue = await env.DB
      .prepare("SELECT id, title, status FROM issues WHERE slug = ?")
      .bind(slug)
      .first();

    return Response.json({ issue });
  }
};

Turso's remote/serverless shape feels like a normal application client. It is slightly more setup, but it also works from more places.

import { createClient } from "@libsql/client";

const client = createClient({
  url: process.env.TURSO_DATABASE_URL,
  authToken: process.env.TURSO_AUTH_TOKEN
});

export async function getIssue(slug) {
  const result = await client.execute({
    sql: "SELECT id, title, status FROM issues WHERE slug = ?",
    args: [slug]
  });

  return result.rows[0] ?? null;
}

For a local-first workflow, Turso's newer sync direction is the cleaner example. Reads and writes happen against a local database file, then you push and pull changes explicitly.

import { connect } from "@tursodatabase/sync";

const db = await connect({
  path: "./app.db",
  url: process.env.TURSO_DATABASE_URL,
  authToken: process.env.TURSO_AUTH_TOKEN
});

await db.exec("INSERT INTO events (name) VALUES ('signed_up')");
await db.push();
await db.pull();

That is the whole decision in code form. D1 is the cleanest database API when your code is already a Worker. Turso is the cleaner long-term abstraction when database access happens from several runtimes.

Who Should Use What?

Use Cloudflare D1 if you are building on Cloudflare Pages, Workers, Queues, R2, KV, Durable Objects, or Workers AI. D1 keeps the architecture simple. You deploy with Wrangler, bind the database, write prepared statements, and stay inside one operational system. It is also the obvious choice for read-heavy edge apps, content tools, lightweight SaaS admin panels, authentication-adjacent metadata, and per-tenant database patterns that fit under the 10 GB per-database limit.

Use Turso if your app has a serious chance of leaving Cloudflare, already runs on Node servers or containers, needs CI scripts and background workers talking to the same database, or benefits from local-first behavior. Turso is also better for Electron, mobile, IoT, and developer tools where the database can live near the user and sync later. That is why it belongs next to reviews like Supabase vs Cloudflare D1: the right database depends on the operational shape of the product, not just SQL features.

My final recommendation: choose D1 for Cloudflare-native apps and Turso for portable SQLite apps. If you are undecided, prototype the first two production queries in both. The platform friction appears immediately: D1 feels invisible in Workers, while Turso feels natural everywhere else.

Frequently Asked Questions

Is Turso better than Cloudflare D1?

Turso is better when you need portability, local-first sync, or database access from multiple runtimes. Cloudflare D1 is better when your app already runs on Workers or Pages Functions and you want the database to be a native Cloudflare binding.

Is Cloudflare D1 production ready in 2026?

Yes, for the right workloads. D1 is a strong fit for small-to-medium transactional apps, edge applications, content products, and per-tenant SQLite patterns. Watch the 10 GB per-database limit, query duration limits, and row-read billing model.

Does Turso work on Cloudflare Workers?

Yes. Turso has serverless and edge-compatible client options, but using Turso from Workers adds an external database dependency. If everything else is already Cloudflare-native, D1 is usually simpler.

Which is cheaper: Turso or Cloudflare D1?

D1 is usually cheaper for Cloudflare-native apps because Workers Paid includes a large D1 monthly allowance. Turso can be more predictable for portable apps, especially on the $4.99/month Developer plan, and becomes more valuable when sync is part of the product.

Should I use SQLite, D1, Turso, or Postgres?

Use SQLite through D1 or Turso for small transactional apps, per-tenant databases, edge apps, and developer tools. Use Postgres when you need complex relational features, large shared datasets, mature extensions, long-running analytical queries, or a broader hiring pool.

Winner

Turso (for portable SQLite and sync) / Cloudflare D1 (for Cloudflare-native apps)

Independent testing. No affiliate bias.

Get dev tool reviews in your inbox

Weekly updates on the best developer tools. No spam.

Build your own dev tool review site.

Get our complete templates and systematize your strategy with the SEO Content OS.

Get the SEO Content OS for $34 →