Keep Free Workers Apps Alive: Index D1, Trim AI SDK
A free-tier Workers app stays free by treating row scans and uncompressed bundle size as limits, then fixing the offenders before midnight.

Midnight failures are budget failures
A free Workers app can look fine on the weekend and fail after midnight. The limit counts rows scanned by the query engine, not requests or rows the application actually uses. D1 queries on Cloudflare Workers Free accounts fail on September 1, 2026, when the account crosses a daily row-read or row-write limit. After a free-tier D1 account goes over a daily limit, requests made with the Workers Binding API or REST API fail until the quota resets at midnight UTC. The free plan gives 5 million rows read per day, 100,000 rows written per day, and 5 GB of storage.
The app can still feel fast. A small feature can run a few queries per page, and weekend traffic can look harmless. If a page triggers a slow lookup, the app can use the daily allowance before the user sees anything.
Hope for lighter traffic will not save the app. Audit the row budget before the weekend ends. For a side project, that is a short pass over the database queries and the build output.
Rows scanned are the real counter
A query that returns one row can still scan many. Start with the query list, not the dashboard. The checklist below is a row audit, and each item is small enough to finish before the next episode.
Begin with the queries your app actually runs. A weekend app usually has a short list: fetch a user, load recent items, count something, update a status. Write them down with the table they touch and the condition they use. The list is a record of where the app looks at the database.
Then look for the queries that scan the whole table. A filter on a column without an index can force the engine to check every row, even when only a few match. The same problem appears in joins and sorts that the database cannot shortcut. If a query asks for a subset of rows and the table lacks an index for that lookup, the engine may scan many rows.
The cheapest fix is often a small schema change. It changes how the engine finds the rows without changing the feature. If the app has a few hot tables, this change can turn a slow lookup into a fast one.
- List every database query and note the table, filter, and sort.
- Mark the queries that scan whole tables.
- Add indexes to the columns your filters and joins use to reduce row reads.
- Verify the scanned count after the change, not the returned count.
- Choose index-or-pay when scans stay high after the obvious fixes: add indexes or upgrade to a Workers Paid plan.
- Check the AI SDK bundle against 64 MiB uncompressed.
The early items find the problem. The later items decide whether the problem is fixable or billable. If the app is close to the limit, do this pass before the next deploy.
The bundle has its own ceiling
The bundle ceiling is separate from the row counter. A big dependency can use uncompressed size before a single query runs. Keep the AI SDK whole, and keep the bundle small enough to deploy. If the build passes, the app can keep working through the weekend.
Row limits and bundle limits fail in different ways. One shows up after the counter fills. The other shows up at deploy time, before the app can start. The bundle check feels like a chore, but it is the one that can stop a release.
Do not rely on compression to hide the problem. Watch the uncompressed size after each dependency update. If one package is the heaviest part, keep it in a single place and trim what you can.
When the bundle is close to the limit, the fix is usually boring. Remove an unused dependency, shrink a huge asset, or move a heavy utility out of the main path. Aim for a bundle that deploys, so the row fixes can actually reach users.