Skip to content

Speed up macOS Node builds #177

@robertsLando

Description

@robertsLando

Context

The macOS jobs in build-macos.yml compile Node from source and are by far the slowest in the matrix — the x64 (Intel) job has been hitting GitHub Actions' 6h job limit. #176 addresses the immediate breakage (drops --enable-lto for macOS, bumps the arm64 runner to macos-15 for std::atomic_ref, adds ccache + GNU make). This issue tracks further speedups beyond that.

Related: #170, #176.

Candidate improvements (ranked by impact)

Biggest wins

  • Cross-compile the x64 build on an arm64 runner instead of natively on Intel. lib/build.ts already has the arm64→x64 macOS cross-compile path (--dest-os=mac --dest-cpu=x64, -arch x86_64 — see lib/build.ts:83-86 and 267-272). Intel runners are the slowest macOS hardware GitHub offers and are being wound down. Building x64 on Apple Silicon would likely halve that job and remove the most fragile runner. Trade-off: a cross-built binary can't be smoke-tested on its build runner — rely on the SHA/verify step or a separate Rosetta check.
  • Or drop the native x64 macOS job entirely. If Intel Mac support is no longer a goal, removing macos-x64 is the cheapest option. Product decision, not technical.
  • Larger runners. macos-15-large (12-core x64) and arm64 large variants give more cores and RAM. The arm64 job is capped at MAKE_JOB_COUNT: 2 because the standard runner has ~7 GB RAM; more RAM allows a higher -j. Trade-off: premium per-minute billing.
  • Skip majors that are already published. "Build All Latest Assets" rebuilds every major on every run. A guard comparing the resolved Node version + patch hash against the already-released artifact (the repo already has expected-shas.json) would skip whole jobs — the biggest wall-clock win when a run only touches one major.

Medium

  • ccache tuning (re-runs only): raise CCACHE_MAXSIZE from 2 G to ~5 G (a full Node+V8 object set may not fit in 2 G), add CCACHE_SLOPPINESS (e.g. time_macros,include_file_mtime,locale), enable depend mode. Caveat: GitHub's per-repo cache budget is 10 GB total.
  • Cache the Node source tarball. tarFetch downloads + SHA-verifies node-vX.tar.gz every run; an actions/cache keyed on the version removes that. Small but free and zero-risk.

Marginal / probably not worth it

  • Ninja instead of make — Drarig29 already tested this for Note on supporting Node 26 #170 and reported it "wasn't improving a lot"; the build is CPU-bound on compilation.
  • --with-intl=none — removes ICU compilation but changes binary behavior; a product call, not a free speedup.
  • Trimming extra components (corepack, amaro/TS-stripping) — shaves only minor time.
  • Lowering optimization / debug info — minor compile speedup at the cost of shipped-binary quality; not advisable.

Suggested first step

Cross-compile x64 on arm64 — it attacks the slowest job at its root (slow hardware) via a codepath that already exists, with no premium-runner cost.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions