Skip to content

docs deploy: every push to main rebuilds the docs site — 98.6% of the team's build time, $171/mo, and a 92-deep queue; turbo-ignore alone would silently stop publishing docs #12743

Closed

Description

@hotlong

The docs project rebuilds on every push to main, and almost none of those pushes change what the site renders. Measured over the last 7 days across the whole team:

project production builds build-minutes avg
objectstack (docs) 228 2835 (98.6%) 12.4 min
objectui 123 36 0.3 min
hotcrm 42 5 0.1 min

Three consequences, all measured:

  1. Head-of-line blocking. The team has concurrentBuilds: 1. An 18-second objectui build queues behind a 12–46 minute docs build. At the time of writing the team queue held 92 deployments, the oldest 34 hours old.
  2. Cost. ~977 docs builds/month at 4 vCPU ≈ $171/month against a $20 included allowance — and in the last 7 days 168 of 228 were failures, so most of it bought nothing.
  3. Risk. Every unnecessary build is another chance to hit the memory ceiling measured in docs deploy: production builds are OOM-failing now — the peak is the Turbopack compile phase, not the prerender; turbopackSourceMaps is a free knob #12683's option set missed #12711.

The project's Ignored Build Step is currently if [ "$VERCEL_ENV" == "production" ]; then exit 1; else exit 0; fi — production always builds, preview always skips. The preview half is right. The production half is the waste.

⚠️ The obvious fix is wrong, and would silently stop publishing docs

#12698 suggests npx turbo-ignore @objectstack/docs. Measured: that alone loses documentation updates.

turbo --filter=<pkg>...[range] decides which packages changed by package directory. This repo's MDX lives at the repo root in content/docs/**, outside the apps/docs package boundary. turbo.json does declare "$TURBO_ROOT$/content/**" in @objectstack/docs#build's inputs — but inputs only feeds the cache hash, it does not widen the affected-package calculation.

Verified against real commits on main:

commit changes turbo verdict correct?
72f91652 .claude/** only SKIP ✅
366f8957 packages/spec/** BUILD ✅ (docs depends on spec)
1265f12b content/docs/api/client-sdk.mdx only SKIP ❌ doc update never ships

So turbo-ignore must be combined with an explicit path check, not used on its own.

Proposed shape

apps/docs/vercel.json gains an ignoreCommand (which per Vercel docs overrides the dashboard Ignored Build Step, so this moves the rule into version control where it can be reviewed and reverted):

  1. non-production → exit 0 (skip) — preserves today's behaviour exactly
  2. content/** or apps/docs/** changed since the last successful deploy → exit 1 (build)
  3. otherwise → hand off to turbo-ignore for the dependency-graph verdict (catches packages/spec etc.)
  4. anything indeterminate (no previous SHA, shallow clone, git object missing) → build, never skip

Rule 4 matters: Vercel builds from a shallow clone, so the previous-SHA comparison can legitimately fail. The failure mode of this whole change must be "build unnecessarily", never "silently skip".

Relationship to #12698

Opposite direction, so it is filed separately rather than as a comment there. #12698 argues the ignore step skips too much (it read a PR's Preview being skipped as production being skipped — corrected in #12711). This card argues production skips too little. #12698's suggested command is adopted here only as one branch of the rule, with the content/** gap above closed.

Refs: #12711 (memory ceiling — every avoided build is one less chance to hit it) · #12698 (correction) · #12683.

Activity

  1. hotlong commented on Aug 27, 2026

    @hotlong
    ContributorAuthor

    Claimed. session 3100934e-af9d-4104-9145-a37b8280a504 · branch claude/issue-12743-docs-ignore-command · worktree sort-dot-path-fallback-fc72e9.

    Scope: the ignoreCommand rule for apps/docs plus its changeset. The build-machine size (#12683 option A, already applied by the maintainer) and the memory work in #12711 are separate and untouched here.

  2. hotlong commented on Aug 28, 2026

    @hotlong
    ContributorAuthor

    Verified in production — 80% of pushes now skip the docs build

    PR #12746 merged as 168941ce. All three decision branches confirmed on real main commits, with the script printing its reasoning into the build log:

    commit change decision correct
    168941ce apps/docs/vercel.json build: content/ or apps/docs/ changed since … ✅
    f75a38af packages/spec build: 2 task(s) in the docs dependency graph affected ✅
    aacc248a, 7d587ac1 pm skills only skip: nothing in @objectstack/docs dependency graph changed since … ✅

    The dependency-graph branch working in production settles the one thing that could not be checked locally: npx turbo does run in the ignoreCommand phase, before installCommand, with no node_modules present.

    Measured over the last 90 minutes: 5 production deployments, 1 built, 4 skipped — an 80% skip rate. A skipped deployment costs 0.2 min (just the decision script) against 1.6–3.0 min for a build.

    Team queue: 0 queued, 0 building — it held 92 deployments with the oldest 34 hours old before this and the machine upgrade landed.

    ⚠️ Still unexercised in production: a commit touching only content/**. That is the dangerous direction — a wrong verdict there means documentation silently stops publishing. It is pinned in scripts/vercel-ignore-docs.selftest.sh against commit 1265f12b, and the content/-path branch did fire correctly on the merge commit, but the pure-docs case will only be exercised the next time someone edits a page. Worth a glance then.

    ⚠️ Correction to this card's own cost figure: the $171/month it cites is unverified and probably overstated. Vercel's docs state that a Pro plan's first concurrent build slot is included and standard build minutes within it are not billed; those builds likely ran in that slot. The billing API does not expose metered quantities (quantity: null), so the real number has to come from the dashboard Usage page. The other two arguments for this change — 98.6% of team build time, and the 92-deep queue — are measured and stand.

    Closing: shipped and verified. Refs #12711, #12698, PR #12746.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions