Skip to content

Cloudflare D1 Pricing Calculator and Batch Limits

Cloudflare D1 pricing calculator. Turn users and queries into rows read and written, check the Free plan's daily limits, and size batch inserts under D1's caps.

  • Runs in your browser

Checked

01Tool

Tool

What D1 costs

Describe the load as
Rows the query reads to answer, not rows it returns.
Each adds one written row.

Paid plan, a month

$5.00

The Workers Paid minimum plus D1 usage past its allowances.

Rows read a day

400K

Rows written a day

5,000

Free plan

Fits

Costs nothing

Everything fits the Free plan. The closest limit is D1 database size, at 40%.

Paid plan, line by line

Workers Paid minimum
$5.00
D1 rows read 12M of 25B included
$0.00
D1 rows written 150K of 50M included
$0.00
D1 storage 0.2 GB of 5 GB included
$0.00
Total a month
$5.00

Free plan limits, closest first

  • D1 database size40%

    0.2 GB of 0.5 GB

  • D1 databases10%

    1 of 10

  • D1 rows read8%

    400K of 5M a day

  • D1 rows written5%

    5,000 of 100K a day

  • D1 storage, all databases4%

    0.2 GB of 5 GB

Price the whole Worker
Monthly figures are 30 times the daily ones. Free limits reset at 00:00 UTC; Paid allowances reset on the renewal day. Everything is worked out in this tab, and nothing is sent.

How many rows fit in one INSERT

Count every column the INSERT sets, including ones your ORM fills in, such as an id or a timestamp.
Workers plan

Rows per INSERT

14

98 bound values in each statement

Statements

72

Worker invocations

2

72 statements are more than the 50 queries one Worker invocation may run on this plan. Spread them over 2 invocations, for example through a queue.
Drizzle ORM
const size = 14
const length = Math.ceil(rows.length / size)

const [first, ...rest] = Array.from({ length }, (_, i) =>
  db.insert(table).values(rows.slice(i * size, (i + 1) * size)),
)

if (first) await db.batch([first, ...rest])

The calculator counts each statement in a batch as one query toward the limit per invocation; Cloudflare's docs do not say how a batch counts.

02Guide

How it works

How D1 counts rows

Rows read are rows scanned, not rows returned. SELECT * FROM users reads every row, and so does a WHERE on a column without an index, even when it returns one row. Rows written count each row an INSERT, UPDATE or DELETE changes, and schema changes can count as both. Row size does not matter: a wide row and a narrow one count the same.

Every query's result carries a meta object with rows_read and rows_written. Run your real queries through wrangler d1 execute and read those numbers instead of guessing. Queries from the dashboard and Wrangler are billed like any other.

Indexes cut reads and add a write

An index on a column you filter or join on lets D1 find the matching rows without reading the rest of the table. A write that sets an indexed column also writes to the index, and that counts as a second row. Set the indexes each write touches to the number of indexes on the columns your writes set. Cloudflare says the saved reads offset the extra write in nearly all cases.

Too many SQL variables

D1 limits how many values a single query can bind, and the limit holds for each statement inside db.batch() too. A multi-row INSERT binds rows times columns values, so it reaches the limit sooner than it looks. The error reads too many SQL variables at offset, and Drizzle has an open issue asking it to chunk inserts on its own.

There are two fixes. Chunk the rows so each INSERT stays under the limit, and send the chunks in one db.batch(), which runs them in order as one transaction and rolls back if any fails. For lookups and updates over a list of ids, bind the list as one JSON string and expand it in SQL with json_each, so the whole list takes a single parameter.

At the Free plan's limits

Past the daily read or write limit, every D1 query on the account fails until the reset at 00:00 UTC. Storage works differently: once it is full, you have to delete data before you can insert again, create tables or add indexes. Moving to Workers Paid lifts the limits, typically within minutes.

D1 or Postgres through Hyperdrive

D1 is built on SQLite. Each database runs one query at a time and has a size cap that Cloudflare cannot raise, because D1 is designed for many smaller databases, such as one per tenant. An app that keeps every tenant in one large schema may suit Postgres through Hyperdrive better. The Workers pricing calculator prices either choice beside the rest of a Worker's bill.

03Rates

The numbers it uses

D1
ItemRateSource
D1 rows read, Free Rows scanned, not rows returned.5 million a daydevelopers.cloudflare.com
D1 rows read, Paid 25 billion a month included, then $0.001 per 1 million rowsdevelopers.cloudflare.com
D1 rows written, Free A write that sets an indexed column adds a row for the index.100,000 a daydevelopers.cloudflare.com
D1 rows written, Paid 50 million a month included, then $1.00 per 1 million rowsdevelopers.cloudflare.com
D1 storage, Free All databases together, tables and indexes.5 GB in totaldevelopers.cloudflare.com
D1 storage, Paid 5 GB included, then $0.75 per GB-monthdevelopers.cloudflare.com
D1 limits
ItemRateSource
Bound parameters per query Applies to each statement inside a batch.100developers.cloudflare.com
Columns per table 100developers.cloudflare.com
SQL statement length 100,000 bytesdevelopers.cloudflare.com
Queries per Worker invocation, Free 50developers.cloudflare.com
Queries per Worker invocation, Paid 1,000developers.cloudflare.com
Database size, Free 0.5 GBdevelopers.cloudflare.com
Database size, Paid Cloudflare cannot raise it.10 GBdevelopers.cloudflare.com
Databases per account, Free 10developers.cloudflare.com
Databases per account, Paid Cloudflare can raise it on request.50,000developers.cloudflare.com
Storage per account, Free 5 GBdevelopers.cloudflare.com
Storage per account, Paid Cloudflare can raise it on request.1,000 GBdevelopers.cloudflare.com
Workers
ItemRateSource
Workers Paid plan $5.00 a month minimumdevelopers.cloudflare.com
Worker requests, Free Resets at 00:00 UTC.100,000 a daydevelopers.cloudflare.com
Worker requests, Paid 10 million a month included, then $0.30 per 1 million requestsdevelopers.cloudflare.com
Static asset requests Billed at the request rate while Workers Caching is on.Free and unlimiteddevelopers.cloudflare.com
CPU time, Free 10 ms per requestdevelopers.cloudflare.com
CPU time, Paid 30 million ms a month included, then $0.02 per 1 million msdevelopers.cloudflare.com
CPU per Cron Trigger run, Free 10 ms per rundevelopers.cloudflare.com

04Questions

Questions

How much does Cloudflare D1 cost?
D1 bills rows read, rows written and storage, and nothing for compute time or egress. The Workers Paid plan includes a monthly allowance of each and charges per million rows and per GB-month past it. The calculator shows how close your load is to each allowance.
Is Cloudflare D1 free?
Yes. D1 is on the Workers Free plan, with daily limits on rows read and written and caps on storage, database size and the number of databases. Cloudflare says the Free plan will always include D1 for prototyping.
What happens when I hit D1's Free plan limits?
Past the daily read or write limit, every D1 query on the account returns an error until the limits reset at 00:00 UTC. Past the storage limit, you have to delete data before you can insert, create tables or add indexes again. Upgrading to Workers Paid lifts the limits, usually within minutes.
Why do I get 'too many SQL variables' on D1?
D1 caps the values one query can bind, and a multi-row INSERT binds one value per column per row, so a large insert passes the cap quickly. The error reads too many SQL variables at offset. Split the insert into chunks under the cap, or pass a list as one JSON value and expand it with json_each.
How many rows can I insert in one D1 query?
Divide D1's cap on bound parameters by the values each row binds, and round down. Count every column the INSERT sets, including ones your ORM fills in. The batch calculator above does the division and writes a Drizzle snippet that chunks the rows.
Do indexes make D1 cheaper or more expensive?
Usually cheaper. An index lets a filtered query read a few rows instead of the whole table. Each write that sets an indexed column writes one extra row for the index, and Cloudflare says the saved reads offset that in nearly all cases.

05Sources

Sources

Nuxter

Building a SaaS on Nuxt?

Nuxter keeps its app's tables in Postgres through Hyperdrive and gives D1 only Nuxt Content's pages, so a Nuxter app's D1 reads come from the docs and pages it serves.

See what Nuxter includesFrom $249, one-time.