Cloudflare D1 Pricing: Budget for Rows Scanned, Not Results Returned
Cloudflare D1 bills for rows scanned, which can differ from the results your application displays. Counting returned records therefore leaves a critical gap in an operating-cost estimate. To judge a database budget, separate application requests, rows read, rows written, storage, and Workers execution, then apply the current pricing rules to the appropriate inputs.
Read usage: estimate from scanned rows, using rows_read as evidence.
Write and storage usage: track rows_written and stored data separately.
Application execution: assess Workers pricing alongside D1, without treating their usage as interchangeable.
That is the useful answer before any purchase decision: a short result list is not evidence of a small database bill.
The receipt is a billing definition
Documentation review date: 2026-09-09. This article is a documentation-based buying decision aid. No production workload or customer installation was tested, and no measured bill is available.
The official D1 pricing documentation identifies rows read, rows written, and storage as billing dimensions. It defines rows read around scanning work rather than only records returned to the caller. It also explains that indexes can affect read and write usage.
The D1 metrics and analytics documentation provides the corresponding measurement handles: query metadata exposes rows_read and rows_written. Neither field is a request counter.
Those definitions are the receipts behind this worksheet. They support a method for collecting cost inputs. They do not establish what your application will cost.
Current D1 allowances and rates
Checked against Cloudflare’s official D1 pricing documentation on 2026-09-09. These are D1 rates and allowances only; Workers compute and the base plan are separate.
| Plan | Reads | Writes | Storage |
|---|---|---|---|
| Free | 5,000,000 rows/day | 100,000 rows/day | 5 GB total storage |
| Workers Paid D1 | 25,000,000,000 rows/month included; overage per 1,000,000 rows: $0.001 | 50,000,000 rows/month included; overage per 1,000,000 rows: $1.00 | 5 GB included; storage overage $0.75/GB-month |
For reads, the overage is $0.001 per 1,000,000 rows; for writes, it is $1.00 per 1,000,000 rows. Exhausting a Free daily D1 limit returns query errors. Workers Paid usage is billed under its separate D1 allowances and rates; Workers compute and the base plan remain separate.
The result tells you what came back; the read metric tells you what was scanned.
A small result can hide a larger scan
Hypothetical example, not a measured workload: a fictional appointment app displays a short list of matching bookings. Its budget worksheet counts the displayed records and labels that total “database reads.”
That label is the mistake. The query may scan records that never appear in the response. The displayed list describes the output; it does not establish the work performed to find it.
Now imagine comparing an existing query with a version supported by a suitable index. The decision should depend on the observed read and write usage under comparable conditions. It should not depend on the result lists looking identical.
Indexes belong in this comparison because they can change usage on both sides. A potential read improvement needs to be considered alongside write usage and storage. “Add an index” is a candidate change, not a completed cost analysis.
The relevant question becomes: what usage does this query produce against representative data, and how often will it run?
Give each input its own place
Copy this table into a budget document. Keep missing values marked unknown. A blank field should never quietly become an assumption of free operation.
| Input | What to record | Evidence or collection point | Budget role |
|---|---|---|---|
| Application requests | Requests reaching each relevant route during a defined period | Application request observations | Workload context; not a substitute for database usage |
| Query executions | Database operations associated with each route | Query observations linked to route activity | Connects application activity to database work |
| Rows read | rows_read for the relevant queries | D1 query metadata | Read-usage input |
| Rows written | rows_written for the relevant queries | D1 query metadata | Write-usage input |
| Storage | Stored amount, measurement date, and expected changes | Database storage observations | Storage-pricing input |
| Workers execution | Usage required by the applicable Workers pricing rules | Runtime observations and current documentation | Separate compute estimate |
| Pricing conditions | Plan, rates, allowances, units, and check date | Current official pricing documentation | Converts usage into a conditional estimate |
This separation prevents a common spreadsheet error: multiplying a request estimate by a database rate without establishing the relationship between requests and database work.
It also makes uncertainty visible. A request forecast may be hypothetical while the query metadata is measured. Those inputs can share a worksheet, but their evidence labels should remain distinct.
Comparison-diagram caption: Application requests connect to query executions and Workers execution. Query executions produce separate read and write measurements; storage remains a separate budget input.
Build the estimate from observable work
Begin with a relevant application action, such as loading a result page or saving a record. Identify the database queries associated with that action. Record the runtime, project configuration, query shape, and dataset conditions so the measurement has a clear scope.
Run the action in an environment you control and retain the query metadata. Capture rows_read and rows_written rather than inferring them from the response length. Record returned records separately if they help explain the query’s behavior.
Repeat the collection across the query patterns that matter to the application. If conditions differ, keep those observations separate. Combining unlike queries too early can hide the expensive path.
For a hypothetical forecast, use this structure:
Projected read usage = sum of each query pattern’s projected executions × its representative rows read.
Apply the equivalent structure to writes. Label the execution forecast as hypothetical and explain what makes the observed query usage representative. Storage requires its own estimate, while Workers execution requires its own pricing calculation.
Finally, apply the current plan’s billing rules to each component. Preserve their units and allowance conditions. Do not assume that every dimension follows the same calculation.
A useful budget keeps measurements, forecasts, and pricing assumptions visibly separate.
The shortcuts this worksheet rejects
There is no verified failure log behind this article. The following are estimation pitfalls, not reported incidents.
Using returned records as scanned rows ignores the distinction in D1’s billing definition. Using request totals as query usage skips the database work that needs measuring. Declaring an index a saving without examining changed usage leaves the comparison unfinished.
Another pitfall is presenting a forecast as an invoice. Even measured query metadata does not establish future execution frequency, future storage, or the applicable pricing conditions at deployment.
The worksheet also has a practical limit: it cannot validate compatibility. Your actual runtime and project configuration still need checking against current documentation. A cost estimate and an installation check answer different questions.
The buying decision stays conditional
For a source-license purchase, assess the software offer and the hosting budget separately.
The optional Saju source-license example is a Korean web-app source license for a single project. Its product page is the reference for current price, deliverables, and installation requirements. That description does not prove a customer installation, runtime compatibility in every configuration, or a particular operating cost.
The final decision is to defer a firm operating-cost conclusion when the worksheet contains only request counts or returned records. Collect the missing usage inputs before treating the budget as dependable.
Use this closing checklist as the reusable artifact:
- Pricing source and check date recorded.
- Runtime, configuration, and dataset conditions documented.
- Request counts kept separate from query executions.
- Read and write metadata retained.
- Storage and Workers execution assessed separately.
- Forecasts labelled hypothetical; missing inputs marked unknown.
- Estimate presented with its conditions, without a free-operation guarantee.
Copy the table and fill it for a representative application action before committing to an operating budget.
Related build logs
- Different Saju Results? Match the Input Before the Comparison
- Source Pack Pricing: Check Running Costs Before Buying a Digital Product
Budget D1 from rows scanned, rows written, and storage, then assess Workers execution separately; returned records cannot establish operating cost.