Reproduces the SvelteKit build-time regression described in sveltejs/kit#15554.
Building a large SvelteKit project with Vite 8 (which ships rolldown) stalls on Linux.
The vite build process starts, prints some accessibility warnings, then stops producing any
output for 60+ seconds — twice per build — before either recovering or hanging permanently.
The process is still alive and consuming CPU during the silent period; it has simply stopped
making observable progress.
This stall occurs regardless of available RAM or CPU. Giving the build 16 GB RAM and 16 CPUs does not prevent it. It is a concurrency issue in rolldown's async plugin-hook dispatch, not a resource constraint.
vite-plugin-sveltekit-guard (part of @sveltejs/kit) registers an async resolveId hook
that calls this.resolve(id, importer, { skipSelf: true }) for every imported module:
async resolveId(id, importer, options) {
const resolved = await this.resolve(id, importer, { ...options, skipSelf: true });
// build import-relationship map …
}
rolldown resolves modules in parallel using its Rust thread pool. When 10 000 routes each
import 4–5 bits-ui components (which themselves have deep import trees), the number of
concurrent this.resolve() calls saturates rolldown's async task queue. All workers end up
waiting for each other's resolutions to complete — a priority-inversion deadlock. The process
remains "running" (the Rust pool is spinning) but emits zero output until the backlog drains.
On some Linux environments the backlog never drains and the build hangs permanently.
$ npm run build
vite v8.0.2 building ssr environment for production…
[vite-plugin-svelte] src/routes/page-010/+page.svelte:46:13 '#' is not a valid href
[vite-plugin-svelte] src/routes/page-020/+page.svelte:46:13 '#' is not a valid href
… (10 more warnings) …
← 60+ seconds of silence (THE STALL)
✓ 10742 modules transformed.
… (more warnings) …
← 60+ seconds of silence (THE STALL again)
✓ 20742 modules transformed.
✓ built in 2m 30s
A normal SvelteKit project (< 100 routes) builds in under 30 s.
This project contains:
src/routes/page-001/ → src/routes/page-10000/),
each being a full page that uses 4–5 bits-ui primitives
(e.g. Accordion + Progress + Tabs + Button + Separator) with
Tailwind CSS v4 utility classes.src/lib/components/ — each using multiple bits-ui
primitives — used by the /reproduction index page./reproduction index page linking to all 10,000 routes.package.json) to reproduce the condition.The 10,000-route structure gives rolldown's resolver enough concurrent work to trigger the async task-queue saturation described above.
npm install
npm run build
Watch the terminal. You will see accessibility warnings appear, then 60+ seconds of complete silence (twice), before the build eventually completes (~2.5 min total). The silent periods are the stall.
docker build -t sveltekit-hang .
docker run --rm sveltekit-hang # stalls; may hang permanently
docker run --rm --cpus 2 sveltekit-hang # same stall
The stall occurs with any memory or CPU setting.
The build workflow runs npm run build on ubuntu-latest and
uses a stall-detection script that fails the step when the build produces no output for more
than 30 seconds. Because the genuine stall lasts 60–74 s (well above the 30 s threshold), the
step fails with:
::error::Build stalled — no output for 63s (threshold: 30s)
The build process (rolldown + vite-plugin-sveltekit-guard) is alive
but stopped producing output. This reproduces the genuine stall
described in sveltejs/kit#15554. It is NOT a resource constraint:
the stall occurs regardless of available RAM or CPU.
The failure exit code is 1 (stall detected), not 124 (bash timeout killed), making the
root cause unambiguous in the CI log.
11:58:15 Build started
11:58:16 [vite-plugin-svelte] !!! rolldown: 1.0.0-rc.11, vite: 8.0.2 !!!
11:58:21 [vite-plugin-svelte] page-010/+page.svelte '#' is not a valid href
11:58:21 … 9 more warnings …
11:58:22 [vite-plugin-svelte] page-040/+page.svelte '#' is not a valid href
████████ 63 s of silence ████████ ← STALL #1
11:59:25 [vite-plugin-svelte] page-040/+page.svelte '#' is not a valid href (client pass)
11:59:26 … 9 more warnings …
████████ 74 s of silence ████████ ← STALL #2
12:00:40 [PLUGIN_TIMINGS] vite-plugin-sveltekit-guard 56 %
12:00:42 ✓ built in 1m 18s
12:00:44 ✓ built in 2m 24s
Plugin timing (from rolldown, client phase):
[PLUGIN_TIMINGS] Warning: Your build spent significant time in plugins:
- vite-plugin-sveltekit-guard 56 %
- vite-plugin-svelte:load-custom 30 %
- vite-plugin-sveltekit-virtual-modules 6 %
- vite-plugin-svelte:compile 4 %
vite-plugin-sveltekit-guard consuming 56 % of build time is the fingerprint of the issue.
The stall-detector CI step catches the first 63 s gap and fails with exit 1.
src/routes/
page-001/+page.svelte ← Accordion + Progress + Tabs + Button + Separator
page-002/+page.svelte ← Switch + Checkbox + Slider + Button + Separator
page-003/+page.svelte ← Avatar + Tabs + Collapsible + Separator + Button
page-004/+page.svelte ← Progress + Slider + Tabs + Separator + Button
page-005/+page.svelte ← Accordion + Collapsible + Avatar + Separator + Button
…
page-10000/+page.svelte ← (cycles through 5 multi-component templates × 2000 rounds)
reproduction/+page.svelte ← index linking to all 10 000 routes
npm install
npm run dev
npm run build
npm run preview
To deploy, you may need to install an adapter for your target environment.