Engineering

Updating ten thousand rows at once

Changing a price across ten thousand records is one line of SQL. On Airtable it is roughly 1,100 HTTP requests, because the write endpoints take ten records at a time and the read endpoints hand back a hundred. Nothing is malfunctioning. That is the documented design, and for your first few thousand records you will never feel it.

The arithmetic of a ten-record cap

Airtable's support documentation puts it plainly: batching "can handle up to 10 records per request, enabling you to update up to 50 records per second." The Web API allows 5 requests per second per base. So to change a field on 10,000 rows you first need their record IDs, and list records pages at a maximum of 100, which is 100 GET calls. Then come 1,000 PATCH calls. Call it 1,100 requests, and at five per second the floor is 220 seconds. Not an hour, but also not the instant you were imagining.

Wall clock is the cheaper half of the bill. Those 1,100 calls come out of a monthly allowance: 1,000 per workspace per month on Free, 100,000 on Team. A single ten-thousand-row update spends more than a Free workspace gets in a month. On Team it is about one percent, which sounds harmless until the job runs nightly and eats a third of your allowance by itself.

The 220 seconds also assume nothing goes wrong. Go over five per second and Airtable returns a 429, and you wait 30 seconds before requests succeed again. A retry halfway through a thousand-call loop means you suddenly care which batches already landed, so you write bookkeeping you did not plan to write. There is a faster door: the Sync API swallows 10,000 CSV rows in one request, capped at 2MB and 20 requests per five minutes per base. It syncs a table rather than editing fields on records you already have, so it solves imports and not the price change.

Bubble batches creates and nothing else

Bubble does give you a bulk endpoint. POST to /obj/typename/bulk accepts up to 1,000 objects per request, one JSON object per line, with a four-minute ceiling on the request. For seeding a table or importing a customer list, that genuinely works.

There is no counterpart for changes. Making changes to a Thing is a PATCH with one unique ID in the path. Replacing is a PUT with one ID. Deleting is a DELETE with one ID. Ten thousand price changes is ten thousand requests, and Bubble's own docs caution that bulk work "can consume a lot of application capacity" and suggest testing in smaller chunks first. Capacity is the same pool your logged-in users are drawing from while your script runs.

The asymmetry makes sense from the platform's side. Creates are independent, so a thousand of them parallelise cleanly. An update has to resolve a reference and respect whatever workflows are watching that field, which is much harder to batch safely. The reasoning is sound. You still pay for it in request count.

What the same job looks like with a database underneath

In Postgres the operation is one statement with a WHERE clause, and the server works out how to touch the rows. PostgREST exposes that same shape over HTTP, so a PATCH to /products?category=eq.outdoor with a JSON body updates every matching row in a single request. Upserts take an array plus a Prefer: resolution=merge-duplicates header. There is no batch size to tune, because there is no batch.

When we moved Stay World Class off Webflow and Xano onto Next.js, NestJS and Supabase, the data move itself was a four-stage ETL that mapped every legacy ID onto a PostgreSQL UUID so nothing lost its references. The headline numbers were performance: Lighthouse climbed from 55.91 to 91 out of 100, and LCP came down 77%. The quieter change was that bulk edits stopped being projects. A correction across the whole catalogue became something you ran, read the row count from, and moved on.

When ten at a time is perfectly fine

Most tables never reach this. If your largest bulk edit touches a few hundred rows, the ten-record cap costs you a few dozen requests and finishes before you have switched tabs. Writing migration code to dodge that is a pure loss, and anyone who tells you otherwise is selling something.

It also stays irrelevant when the edits are human-paced. Someone fixing records in the Airtable grid is not going through the API at all, and Airtable's editing surface is better than what you would build in a quarter. Rebuilding it to win a WHERE clause you use twice a year is bad arithmetic.

The cap starts to bite when bulk writes become routine, like a nightly reprice or a monthly billing pass over every active account. Once you can name the job, know its row count, and see that the count grows with your customer base, the ten-record ceiling is no longer an API footnote. It is your runtime and your monthly call budget. Staying put can still be the right call. Price it with these numbers instead of a guess.

Sources

Is your platform outgrowing its stack?

Book a call and we'll walk through how we'd approach your platform, with an estimate grounded in a working prototype.