Build1 distinct publisher3 min readPublished
Roughly 2 GB per JavaScript build, a hard failure floor at 2 GB of RAM, and a formula that subtracts headroom first. Exceed it and the 504s land on sites nobody was deploying.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
The numerator is where this usually goes wrong, because it gets read off an idle box. `free -m` prints two columns and only one of them is the answer: `available`, because it counts the page cache the kernel will hand back under pressure [10]. Then subtract everything that is only true mid-deploy. The app you are replacing is still running, which is what zero-downtime means [19]. On a Node project the new process comes up on a standby port and is soaked for 60 seconds before nginx switches and the old worker drains, so for that window the machine holds both copies [20]. The PHP-FPM pool sizes itself to traffic rather than to your deploy schedule [21], and the database will not give its buffers back because a bundler asked [22]. Build concurrency is spent out of whatever survives that subtraction [23], which means the real peak during a soak is the build plus two resident copies of the app, not the build figure alone [3].
The denominator needs the same suspicion. `/usr/bin/time -v` reports the maximum resident set size of the largest single process, not the sum of what was running, so a bundler forking parallel workers goes past it and the number is a floor [12]. The full path matters, since the shell builtin has no `-v` [11]. What settles it is a ceiling: `systemd-run --scope -p MemoryMax=2G npm run build` fails the way the server will fail [13], and a build that completes inside 2 GB means two of them fit in 4 GB free [14].
The comfortable rows are not the maximum, and the gap between them is where the damage lives. Five builds start on the 8 GB row and will probably finish [6]. At roughly 2 GB each that is about 10 GB of demand on a box that holds 8, before the served apps and the database are counted [1]. Nothing refuses. Memory pressure rises across the machine, the apps already serving traffic get squeezed, the deploys themselves slow down competing for the same memory, and the symptom you see is 504s on sites nobody was deploying [7]. Build failures come later, if they come [8].
This is also why core count is a bad input. Bundling and type-checking saturate RAM long before CPU [15], and the two starvation modes are not symmetric: a build short of CPU finishes late, a build short of memory dies, or kills something else on the box [16]. Counting projects gets sizing wrong in both directions; counting peak RSS does not [18]. A Laravel deploy that is `composer install` and a migration is cheap in memory terms, but add a Vite front end and it runs `npm ci && npm run build` and pays the Node price like anything else [17]. Framework choice moves the rows too: Astro is light enough to take the 8 GB row to four, while Next.js is heavier than most [9]. And the 2 GB floor is not a rule of thumb [4]. At that tier one build wants the entire machine, leaving nothing for the kernel, the app still serving, or the database [2].
Ranked by verification strength, evidence, and original report placement.
Concurrent build capacity is not a property of the deployment tool; it is the server's available memory divided by what one build takes at its peak.
The stated formula is: concurrent builds = (RAM available while the site is serving - headroom) / peak RAM per build.
What changes first is not the build: memory pressure rises across the whole machine, applications already serving traffic get squeezed, deploys get slower as they compete for the same memory, and the visible symptom is 504s on sites nobody was deploying.
The build failures come later, if at all.
In free -m the 'free' column is not the answer; 'available' is, because it counts the page cache the kernel will hand back under pressure.
Peak usage is measured with /usr/bin/time -v npm run build piped to grep for 'Maximum resident set size'; the full path matters because the shell builtin does not have -v.
Follow any of these and your For You feed starts watching them — no settings page required.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Reproducible method, unpublished numbers
The mechanisms and diagnostics are specific and independently checkable by any reader (free -m 'available', /usr/bin/time -v peak RSS with its stated floor caveat, a systemd MemoryMax scope test, exit 137 and dmesg OOM forensics), which raises the floor. But the load-bearing quantitative claims — roughly 2 GB per JavaScript build, a categorical failure floor at 2 GB of RAM, and the per-tier rows — rest on one author's unpublished field observation, the table itself is absent from the supplied text, and no second publisher corroborates anything.
No adoption signal in cluster
The supplied material contains no releases, deployments, usage disclosures, benchmarks, pricing or licence changes — only sizing guidance and diagnostic commands. The one product reference (a deployment tool that provisions a swapfile) carries no usage, install or customer data, so adoption cannot be measured without inferring facts the source does not provide.
Certainty outruns the shown numbers
Overstatement is modest but real and mostly rhetorical: a figure the author concedes is not a benchmark is used to declare a categorical hard floor ('the build fails — not sometimes'), and the reassurance that five builds run at once on the 8 GB row with 'nothing refuses' cannot be reconciled with the same article's 2 GB divisor and headroom-first formula. Offsetting this, the underlying mechanism claims — memory saturating before CPU, collateral 504s and OOM victims, double-resident copies during the soak window — are conservative and well argued, so the gap is not large.
Vendor-adjacent practitioner content
The post is authored on a developer platform by someone commercially adjacent to a deployment product: it refers to machines 'Depfloy provisioned' as already carrying a swapfile and points to 'the zero-downtime sequence' as an internal reference, and the 60-second soak with standby-port cutover is described as that tool's behaviour. The framing — capacity is arithmetic, not a tool property — is credible and not self-serving on its face, but the piece functions as top-of-funnel content for a deploy tool and no affiliation is disclosed in the supplied text.
Moderate on mechanism, low on numbers
Confidence is limited by a single publisher, a single author, no independent corroboration and an internal arithmetic inconsistency, and by the absence of any adoption dimension. It is supported by the specificity and reproducibility of the diagnostic method and by the author's explicit hedging on the per-build figure, which makes the mechanism claims safe to act on even where the tiers are not.
build
Five frameworks, one store, and a benchmark that measures when the button works1 distinct publisher
build
Eight months of JSON as a database: the bill came due on slug identity, not read latency1 distinct publisher
build
With CRA out of React's docs, the new project default is a rendering decision1 distinct publisher
build
The optional EntityManager is the bug: moving the transaction boundary into AsyncLocalStorage1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 26, 2026