All posts
No-Code & Tools

Cloudflare D1 Daily Row Read Limit Exceeded: Why Multiple Apps Can Fail at Once

On the D1 Free plan, the daily row-read allowance is account-wide. One noisy database workload can therefore exhaust the quota and make unrelated D1-backed applications on the same account start failing together.

Elvis Onunwa02 October 20267 min readLast updated: 02 October 2026
Cloudflare D1 Daily Row Read Limit Exceeded: Why Multiple Apps Can Fail at Once

TL;DR

  • Cloudflare currently gives Workers Free accounts 5 million D1 rows read per day and 100,000 rows written per day, measured across the account.
  • Since September 1, 2026, Free-plan D1 queries fail after the daily rows-read or rows-written limit is reached until the quota resets at midnight UTC.
  • If several Workers/D1 apps share one Cloudflare account, one high-read workload can consume the shared allowance and make other D1-backed sites fail too.
  • Recovery means reducing the hot workload and waiting for/resetting the quota boundary or upgrading when appropriate—not repeatedly redeploying unrelated Workers.
On this page⌄

A production site starts returning HTTP 500.

Then another site on the same Cloudflare account starts failing too.

Their codebases are different. Their routes are different. One was not deployed when the other broke.

The shared dependency is D1.

I have debugged exactly this kind of outage, and the important detail is easy to miss:

the D1 Free-plan daily usage allowance is account-wide, so one noisy workload can consume the quota for several applications.

Since September 1, 2026, this has an even sharper consequence. Cloudflare now actively fails Free-plan D1 queries after the daily read or write allowance is exhausted until the quota resets.

So high rowsRead can move from “cost/optimization warning” to “multiple apps unavailable.”

The current Free-plan limit

Cloudflare’s current D1 pricing/limits documentation lists the Free-plan allowance as:

  • 5 million rows read per day;
  • 100,000 rows written per day.

These limits apply across the account rather than giving every database its own independent 5-million-row bucket.

That distinction matters when you run several products, client sites or internal apps under one Cloudflare account.

A high-traffic content app can affect a conference registration app even if their databases are separate.

What changed on September 1, 2026

Cloudflare announced enforcement for Free-plan D1 daily limits.

Before that change, developers could see usage warnings without necessarily experiencing immediate query failure in the same way.

Under the current behaviour, once the Free-plan account exhausts the daily rows-read or rows-written allocation, D1 queries fail until the quota resets at midnight UTC.

Cloudflare states that the underlying data is not affected by this limit event.

That means this is primarily an availability incident, not a data-loss incident.

But from the user’s perspective, a registration form or homepage returning 500 is still an outage.

Why several apps can fail together

Imagine one account with:

  • Site A: news/content platform;
  • Site B: event registration app;
  • Site C: admin tool.

Site A runs an expensive related-content query and a homepage that scans large row sets on cache misses.

Site B is small and efficient.

Site C barely receives traffic.

If Site A consumes the account’s daily D1 read allowance, Site B and Site C do not get separate protected quotas merely because they use different databases.

Their next D1 queries can fail too.

This is why an account-wide usage graph should be part of incident response when several unrelated Workers fail around the same time.

The misleading signal: Worker outcome can still look healthy

In one incident, a Worker request could have an execution outcome that looked ok while the user received an HTTP 500.

That is not contradictory.

The Worker runtime may have executed your JavaScript without crashing at the platform level.

Your application then attempted a D1 query, received an error, and deliberately or indirectly returned a 500 response.

So when debugging, separate:

  • Worker execution/runtime outcome;
  • HTTP response status;
  • application exception/error;
  • D1 operation result.

Do not use one green runtime metric as proof that the database path succeeded.

How to recognize a quota incident

The useful signals are:

1. D1 usage is near or above the daily allowance

Check account-level D1 analytics and usage notifications.

2. Several D1-backed apps fail at nearly the same time

Especially suspicious when they share an account but not a deployment.

3. Static/non-D1 routes may still work

A health endpoint or static asset can respond while routes that require D1 fail.

4. The code failure appears suddenly without a matching release

A limit crossing can happen because traffic/scan cost accumulated throughout the day.

5. Errors stop after the daily reset

That is strong retrospective evidence, although you should not wait for midnight to start investigating the workload.

Do not redeploy everything first

When multiple apps fail, redeployment feels productive.

But if the account-wide D1 allowance is exhausted, deploying identical code does not restore the quota.

Before changing unrelated applications:

  1. inspect D1 usage;
  2. identify the database/query consuming the rows;
  3. confirm whether the failure is quota-related;
  4. reduce or disable the hot read path if possible;
  5. serve cached/stale content where the product can tolerate it;
  6. decide whether the workload needs architectural optimization or a different plan.

Random deployments can obscure the timeline without fixing the shared dependency.

Find the workload, not just the database

Once you know rows-read is the issue, use query-level analytics.

I look for:

  • total rows read per SQL statement;
  • executions;
  • rows read per execution;
  • which Worker/route calls that statement;
  • whether the statement is user-facing or a background rebuild.

In one production investigation, just 85 executions of a related-content query accounted for about 147,820 rows read.

Another homepage query pattern repeatedly scanned category/recent-content rows.

Those are the fixes that matter.

Deleting a few records or clearing browser cache does not solve an unbounded query shape.

Read D1 Rows Read vs Query Count if the dashboard’s query numbers seem too low to explain the quota consumption.

Add a circuit breaker before the next incident

If an optional feature is expensive, do not let it take the whole product down.

Examples:

  • related stories;
  • trending content;
  • recommendations;
  • analytics summaries;
  • expensive homepage aggregations.

A circuit breaker can say:

If this snapshot cannot be rebuilt, serve the last known good result or temporarily omit the optional section.

That is better than repeatedly hammering D1 with the query that is already causing the problem.

Core transactional paths such as payment confirmation need different guarantees. Do not serve stale truth where correctness matters.

The architecture should distinguish optional freshness from authoritative state.

Cache the public read path before D1

For public SSR pages, a cache-first design can prevent every page view from touching the database.

The general flow is:

  1. check edge/cache snapshot;
  2. if fresh, return it;
  3. if stale but usable, return stale and trigger one controlled refresh;
  4. only the refresh path queries D1;
  5. store a last-known-good copy for temporary database degradation.

This pattern is especially valuable for:

  • homepage sections;
  • categories;
  • related stories;
  • site configuration;
  • event information that changes infrequently.

It can turn D1 from “database queried on every request” into “database queried when the read model needs refresh.”

Account architecture matters when workloads have different risk

If you place many unrelated production products under one account, shared limits become a shared blast radius.

That does not automatically mean every project needs a separate account.

But you should understand the dependency.

Ask:

  • Which workloads share D1 allowances?
  • Which one can consume the most rows?
  • Which products are business-critical?
  • Do we have usage alerts before 75%, 90% and exhaustion?
  • Can optional workloads degrade safely?
  • Is the Free plan still appropriate for production traffic?

This is an operational design question, not only a pricing question.

Free versus paid should be a workload decision

Do not upgrade merely to avoid understanding a bad query.

A table scan that burns 5 million rows on Free can still be wasteful on Paid.

First remove accidental work:

  • full scans;
  • duplicated loaders;
  • hydration refetches;
  • per-image D1 reads;
  • global ranking over large candidate sets;
  • repeated snapshot rebuilds.

Then compare the legitimate workload with the plan that fits it.

Paid capacity is useful for real production scale. It should not be a substitute for a bounded read architecture.

A practical outage response checklist

When D1-backed apps begin failing together:

  1. Check the account-wide D1 usage immediately.
  2. Confirm current daily limit/enforcement in Cloudflare docs/dashboard.
  3. Identify top queries by rows read.
  4. Map them to routes/background jobs.
  5. Disable or degrade optional hot paths.
  6. Serve safe cache/stale snapshots where appropriate.
  7. Do not ask transactional routes to guess. Preserve correctness for payments, auth and writes.
  8. Measure after the reset/fix. Ensure consumption rate changed rather than only waiting for quota recovery.
  9. Add alerts and per-route budgets. Catch the next runaway query before the account reaches exhaustion.
  10. Re-evaluate account/plan architecture. Reduce shared blast radius where the business requires it.

The important lesson

A database quota incident is not only a database problem.

It exposes how your applications share infrastructure and how gracefully they behave when one dependency is constrained.

The strongest fix I have seen combined three layers:

cheaper SQL + fewer live D1 reads + controlled degradation.

That is much more durable than simply waiting for midnight.

If several Cloudflare apps are failing and you cannot tell whether the problem is Worker code, D1 limits or one runaway query, contact me or see my MVP development service. I can trace the shared dependency and reduce the workload before the next production window.

Sources checked

Frequently asked questions

Questions, answered.

What happens when I exceed Cloudflare D1's Free-plan row-read limit?

Cloudflare now fails D1 queries after the daily Free-plan read/write allowance is exhausted. Data is not deleted; queries begin working again after the daily reset, or you can move to an appropriate paid plan.

Why did multiple Cloudflare apps fail at the same time?

D1 Free-plan usage limits are account-wide. If several databases/apps belong to the same account, a high-usage app can consume the shared allowance and unrelated D1-backed Workers may then encounter query failures.

What is the current D1 Free-plan row-read limit?

Cloudflare currently documents 5 million rows read per day and 100,000 rows written per day for the Free plan, subject to Cloudflare's current platform terms and limits.

Does a Worker outcome of `ok` prove D1 succeeded?

No. A Worker can execute normally at the runtime level while application code receives a D1 error and returns a 500. Inspect the response, application logs and D1 errors rather than relying on the Worker outcome alone.

NEED HELP WITH THE BUILD?

Turn what you learned here into a clearer website or MVP.

Share the goal, current stage, and constraints. I’ll help you identify the smallest responsible next step.

Continue reading

Related notes.