sveltejs/svelte
web development for the rest of us
Healthy across the board
- ✓Last commit 3d ago
- ✓5 active contributors
- ✓Distributed ownership (top contributor 41%)
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
- ⚠Small team — 5 top contributors
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Embed this verdict
[](https://repopilot.app/r/sveltejs/svelte)Paste into your README — the badge live-updates from the latest cached analysis.
Onboarding doc
Onboarding: sveltejs/svelte
Generated by RepoPilot · 2026-05-04 · Source
Verdict
GO — Healthy across the board
- Last commit 3d ago
- 5 active contributors
- Distributed ownership (top contributor 41%)
- MIT licensed
- CI configured
- Tests present
- ⚠ Small team — 5 top contributors
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
TL;DR
This is the official sveltejs/svelte monorepo — the compiler and runtime for the Svelte web framework. Svelte compiles declarative .svelte component files into surgically efficient vanilla JavaScript DOM updates at build time, eliminating virtual DOM overhead. The repo contains the compiler (parsing, analysis, code generation), the runtime reactivity system (signals-based, in packages/svelte), and the full test/benchmark infrastructure. Monorepo managed by pnpm workspaces: the primary package lives in packages/svelte/ containing the compiler, runtime, and type definitions. Benchmarking infrastructure is isolated under benchmarking/benchmarks/reactivity/. CI, release, and ecosystem trigger workflows live under .github/workflows/.
Who it's for
Web developers building production UIs who want minimal bundle sizes and high runtime performance without a virtual DOM, plus Svelte core contributors working on the compiler pipeline, reactivity primitives, or language tooling.
Maturity & risk
Svelte is a widely-adopted, production-ready framework with millions of weekly npm downloads and a long public history (Svelte 5 is the current major version introducing runes/signals). The repo has active CI via .github/workflows/ci.yml, a changeset-based release process, and vitest-powered test suites. It is unambiguously production-ready and under heavy active development.
Very low risk for consumers: Svelte has a large community, multiple maintainers (Rich Harris + Vercel-backed team), and a stable release cadence managed via @changesets/cli. The .changeset/ directory shows at least 10 in-flight changesets, indicating active but controlled churn. Svelte 5's runes API is a significant breaking change from v4, so upgrading existing apps requires migration effort.
Active areas of work
At least 10 active changesets are queued (e.g. easy-singers-retire.md, smooth-poems-tap.md, three-pears-build.md), indicating ongoing bug fixes and features in flight. The benchmark suite under benchmarking/benchmarks/reactivity/tests/ (kairo_avoidable, kairo_broad, clean_effects) suggests active reactivity performance work. The autofix.yml and pkg.pr.new.yml workflows suggest automation improvements are also in progress.
Get running
git clone https://github.com/sveltejs/svelte.git cd svelte corepack enable # ensures pnpm@10.4.0 is used pnpm install pnpm build # builds all packages under packages/
Daily commands: pnpm build # compile packages pnpm test # run all vitest tests pnpm bench # run reactivity benchmarks (NODE_ENV=production) pnpm bench:compare # compare benchmark runs pnpm lint # eslint + prettier check pnpm format # prettier write
Map of the codebase
packages/svelte/src/compiler/index.js— Main compiler entry point that orchestrates parsing, analysis, and code generation — every Svelte component passes through here.packages/svelte/src/internal/client/reactivity/sources.js— Core runtime implementation of reactive sources ($state), the foundation of Svelte 5's runes-based reactivity system.packages/svelte/src/internal/client/reactivity/effects.js— Implements the $effect rune runtime logic including scheduling, dependency tracking, and cleanup — central to Svelte 5's reactive execution model.packages/svelte/src/compiler/phases/3-transform/client/index.js— Client-side code generation transform phase that converts analyzed Svelte AST into executable JavaScript DOM operations.packages/svelte/src/compiler/phases/1-parse/index.js— Entry point for the Svelte template parser that converts raw .svelte file content into an AST for further analysis.packages/svelte/src/compiler/phases/2-analyze/index.js— Semantic analysis phase that resolves scopes, validates rune usage, and annotates the AST before transformation.packages/svelte/src/internal/client/dom/blocks/each.js— Runtime implementation of {#each} blocks with keyed diffing — one of the most performance-critical DOM reconciliation paths.
How to make changes
Add a new compiler warning
- Define the warning message key and text in the centralized warnings registry (
packages/svelte/src/compiler/warnings.js) - Add detection logic in the appropriate analysis visitor (e.g., for a template construct, add to the relevant visitor file) (
packages/svelte/src/compiler/phases/2-analyze/index.js) - Write a test fixture demonstrating the warning is emitted correctly (
packages/svelte/tests/compiler-errors/samples)
Add a new built-in DOM element binding
- Implement the runtime binding handler (get/set value, event listeners) for the new element (
packages/svelte/src/internal/client/dom/elements/bindings/input.js) - Register the binding in the compiler's analysis phase so it is recognized as a valid bind: target (
packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js) - Add the codegen path in the client transform to emit the correct runtime call (
packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js) - Add SSR equivalent (serialize the bound value to string for hydration) (
packages/svelte/src/compiler/phases/3-transform/server/visitors/BindDirective.js)
Add a new built-in store (like tweened/spring)
- Implement the store factory function using the Svelte store contract (subscribe/set/update) (
packages/svelte/src/motion/index.js) - Export the new store from the svelte/motion sub-package entry point (
packages/svelte/src/motion/public.js) - Add TypeScript type definitions for the new store's options and return value (
packages/svelte/src/motion/public.d.ts)
Add a new template block syntax (like {#each} or {#if})
- Extend the parser to recognize and produce an AST node for the new block (
packages/svelte/src/compiler/phases/1-parse/index.js) - Add semantic analysis visitor to validate the new block's usage and children (
packages/svelte/src/compiler/phases/2-analyze/index.js) - Add client-side code generation visitor that emits the correct runtime calls (
packages/svelte/src/compiler/phases/3-transform/client/index.js) - Implement the runtime DOM helper that performs the actual DOM operations for the block (
packages/svelte/src/internal/client/dom/blocks/each.js)
Why these technologies
- Compiler-first approach (no virtual DOM) — Moves reactivity overhead to build time, producing minimal runtime JavaScript that directly manipulates the DOM, resulting in smaller bundles and faster runtime performance.
- Signals/Runes reactivity (Svelte 5) — Fine-grained push/pull reactive graph eliminates the need for whole-component re-renders, enabling precise DOM updates with O(changed) complexity instead of O(component tree).
- TypeScript for compiler internals — The compiler is complex (~20k+ LOC) and processes structured ASTs; TypeScript's type system prevents category errors between AST node types and transform phases.
- Vitest for testing — Native ESM support and fast HMR-aware test execution align with Svelte's ESM-first build output; shares Vite configuration with user projects.
- pnpm worksp — undefined
Traps & gotchas
pnpm version is strictly enforced at 10.4.0 via packageManager in package.json — using npm or yarn will not work and older pnpm versions may silently fail. You must run pnpm build before pnpm test because tests import the compiled output from packages/svelte. Playwright tests require browser binaries (pnpm exec playwright install). Node.js must support ESM natively (v18+ recommended). The --allow-natives-syntax V8 flag is required for benchmark runs (already in npm scripts).
Architecture
Concepts to learn
- Compiler-as-framework (ahead-of-time compilation) — Svelte's entire value proposition is shifting framework work to compile time — understanding AOT vs runtime frameworks explains every architectural decision in this repo
- Fine-grained reactivity / Signals — Svelte 5 runes implement a signals-based reactivity graph (visible in the kairo benchmarks); this is fundamentally different from React's re-render model and drives the runtime internals
- Incremental DOM / surgical DOM updates — Unlike VDOM diffing, Svelte emits direct imperative DOM mutations — understanding this explains why the compiled output looks the way it does
- Changeset-based versioning — This repo uses
@changesets/clifor coordinated multi-package semver bumps and changelogs — contributors must add a changeset file or CI will fail - Kairo benchmark suite — The kairo benchmarks (kairo_avoidable, kairo_broad, kairo_deep) are a standardized reactivity stress test used across signal libraries — results here directly compare Svelte against Solid, Vue, etc.
- pnpm workspaces (monorepo) — All packages are linked via pnpm workspace protocol (
workspace:^) — running commands in the wrong directory or with npm/yarn will break resolution silently
Related repos
sveltejs/kit— SvelteKit is the official meta-framework built on Svelte, providing routing, SSR, and adapters — most Svelte apps are built with itvuejs/core— Vue 3's composition API and signals-based reactivity are the closest conceptual alternative to Svelte 5 runes in the same compile-friendly UI spacesolidjs/solid— Solid shares Svelte's fine-grained reactivity and no-VDOM philosophy and is a direct performance/design comparison pointsveltejs/language-tools— Provides the Svelte VS Code extension and TypeScript language service plugin that depends directly on the compiler in this repoRich-Harris/svelte-devtools— Browser devtools extension for Svelte, historically maintained alongside the core repo as a companion debugging tool
PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add benchmark comparison CI workflow to automate regression detection
The repo has a sophisticated benchmarking infrastructure under benchmarking/ (including benchmarking/compare/index.js, runner.js, generate-report.js) and bench/bench:compare npm scripts, but there is no GitHub Actions workflow in .github/workflows/ that automatically runs these benchmarks on PRs to catch performance regressions. This is high-value for a compiler/runtime like Svelte where micro-optimizations matter significantly.
- [ ] Study the existing .github/workflows/ci.yml to understand how jobs are structured and what Node/pnpm versions are used
- [ ] Study benchmarking/compare/index.js and benchmarking/compare/runner.js to understand how the comparison tool works and what outputs it produces
- [ ] Create .github/workflows/benchmark.yml that triggers on pull_request, checks out both base and PR branches, runs 'pnpm bench:compare' against the base branch SHA, and posts the output from benchmarking/compare/generate-report.js as a PR comment using actions/github-script
- [ ] Ensure the workflow only runs when files under packages/svelte/src or benchmarking/ are changed to avoid wasting CI minutes
- [ ] Add the workflow to .github/PULL_REQUEST_TEMPLATE.md as a note so contributors know benchmark results will be posted automatically
Add missing reactivity benchmark tests for snapshot/derived chaining patterns
The benchmarking/benchmarks/reactivity/tests/ directory has tests for specific patterns (kairo_diamond, kairo_deep, kairo_broad, mol, repeated_deps, clean_effects, etc.) but is missing coverage for derived-chain scenarios (e.g. long chains of $derived values that are partially invalidated) and snapshot/state-copy patterns that are common in real Svelte 5 runes-based apps. Adding these fills a concrete gap in the performance test suite and helps maintainers detect regressions in the runes reactivity graph traversal.
- [ ] Read benchmarking/benchmarks/reactivity/util.js and an existing test like benchmarking/benchmarks/reactivity/tests/kairo_deep.bench.js to understand the benchmark authoring pattern
- [ ] Read benchmarking/benchmarks/reactivity/index.js to understand how tests are discovered and registered
- [ ] Create benchmarking/benchmarks/reactivity/tests/derived_chain.bench.js that builds a linear chain of N $derived signals (e.g. depth 100, 500, 1000) where only the root changes, measuring propagation time
- [ ] Create benchmarking/benchmarks/reactivity/tests/partial_invalidation.bench.js that models a diamond-then-chain topology where only one branch is dirtied, verifying that the other branch is not recomputed (avoidance benchmark)
- [ ] Run 'pnpm bench' locally to validate the new benchmarks execute correctly and produce stable numbers, then open the PR with baseline numbers included in the description
Split benchmarking/compare/index.js into focused modules (runner orchestration vs. report formatting)
The benchmarking/compare/ directory contains index.js, runner.js, and generate-report.js, but index.js likely conflates CLI argument parsing, orchestration logic, and result aggregation into a single file (a common pattern in benchmark tooling that grows organically). Separating concerns makes it easier for contributors to extend the comparison tool (e.g. add JSON output, integrate with GitHub Actions step summaries, or support additional benchmark suites under benchmarking/benchmarks/ssr/).
- [ ] Read benchmarking/compare/index.js in full and identify the distinct responsibilities: CLI arg parsing, process spawning/orchestration, result collection, and output formatting
- [ ] Extract CLI argument parsing into benchmarking/compare/cli.js exporting a parsed options object, keeping index.js as the thin entry point that imports from cli.js, runner.js, and generate-report.js
- [ ] Move any result aggregation/diffing logic that
Good first issues
- Add missing benchmark tests for
kairo_deepandkairo_diamondpatterns that exist in other signal-library benchmarks but are absent frombenchmarking/benchmarks/reactivity/tests/. 2. The.github/ISSUE_TEMPLATE/bug_report.ymlexists but there is noARCHITECTURE.md— document the compiler pipeline stages (parse → analyze → transform → codegen) with pointers to the real source directories. 3. Add vitest coverage thresholds toci.ymlusing the already-installed@vitest/coverage-v8package, which is listed as a devDependency but not yet enforced in CI.
Top contributors
- @dummdidumm — 32 commits
- @Rich-Harris — 30 commits
- @github-actions[bot] — 11 commits
- @dependabot[bot] — 3 commits
- @paoloricciuti — 3 commits
Recent commits
dc5bd88— fix: resolve stale deriveds with latest value (#18167) (Rich-Harris)e65025b— docs: fix testing docs (#18163) (Rich-Harris)572444a— fix: ignore false-positive errors of$inspectdependencies (#18106) (dummdidumm)90a70cb— fix: flush eager effects in production (#18107) (dummdidumm)9521b9f— fix: don't rebase just-created batches (#18117) (dummdidumm)7719a74— chore: fix constructor typo in attributes comment (#18115) (Rohan5commit)146cb5e— fix: lazy props reactivity (#18146) (eduardo-kurek)bc82a55— fix: ensure scheduled batch is flushed if not obsolete (#18131) (dummdidumm)4c96b46— fix: allow@debugtags to reference awaited variables (#18138) (dummdidumm)69b4c9f— fix: skip block comments in read_value to prevent apostrophe parsing error (#18153) (DORI2001)
Security observations
- Medium · Outdated jsdom Dependency with Potential XSS Risk —
package.json (devDependencies: jsdom@25.0.1). The project pins jsdom to version 25.0.1 while newer versions exist. jsdom has historically had XSS-related vulnerabilities due to its HTML parsing and script execution capabilities. Being a test dependency used with vitest, exploitation is limited to the test environment, but a compromised or malicious test fixture could execute arbitrary code within the jsdom sandbox. Fix: Upgrade jsdom to the latest stable version. Regularly audit devDependencies with 'pnpm audit' and set up automated dependency update tooling (e.g., Dependabot or Renovate). - Medium · XSS Risk in Svelte Compiler Output —
benchmarking/benchmarks/ssr/wrapper/App.svelte, packages/svelte (compiler). As a compiler framework, Svelte processes user-supplied templates and component code. If untrusted template content (e.g., user-generated component code) is passed through the Svelte compiler without sanitization, the compiled output could contain injected scripts or HTML. The SSR benchmarking wrapper (benchmarking/benchmarks/ssr/wrapper/App.svelte) is one such surface. This is an architectural risk inherent to compiler-based frameworks when used with untrusted input. Fix: Document clearly that the Svelte compiler should never be used on untrusted user input at runtime. Ensure server-side rendering pipelines sanitize dynamic content before passing to {@html} blocks. Audit all uses of {@html} in the codebase and benchmarks. - Medium · Supply Chain Risk via Broad devDependency Version Ranges —
package.json (devDependencies). Many devDependencies use caret (^) version ranges (e.g., eslint@^10.0.0, playwright@^1.58.0, typescript@^5.5.4, vitest@^2.1.9). This allows automatic minor and patch upgrades, which could introduce malicious or breaking changes via a compromised package update, increasing supply chain attack risk. Fix: Consider pinning critical dependencies to exact versions or using a lockfile integrity check in CI (pnpm install --frozen-lockfile). Implement automated security scanning (e.g., 'pnpm audit' in CI pipeline) and consider using a software composition analysis (SCA) tool. - Medium · Node.js Flags Enabling V8 Native Intrinsics in Benchmark Scripts —
package.json (scripts: bench, bench:compare, bench:debug), benchmarking/run.js. The benchmark scripts use 'node --allow-natives-syntax', which enables V8 native intrinsics (e.g., %OptimizeFunctionOnNextCall). While used legitimately for performance benchmarking, running these scripts with untrusted or user-supplied benchmark files could expose low-level V8 internals, potentially allowing memory inspection or JIT manipulation. Fix: Ensure benchmark scripts are only run in controlled, trusted environments. Never execute benchmark scripts against untrusted input. Document this risk in the benchmarking README. - Low · Debug/Inspect Flag Exposed in npm Script —
package.json (scripts: bench:debug). The 'bench:debug' script uses '--inspect-brk', which opens a Node.js debugger port (default 9229) and pauses execution until a debugger attaches. If run in a shared or networked environment, this port could be exposed to unauthorized access, allowing remote code execution via the Node.js debugger protocol. Fix: Restrict the debug script to localhost only (--inspect-brk=127.0.0.1:9229) and ensure it is never executed in CI, production, or shared network environments. Add a warning comment in the script. - Low · GitHub Actions Workflow Potential for Secret Exposure —
.github/workflows/ (autofix.yml, release.yml, ecosystem-ci-trigger.yml). The repository contains multiple GitHub Actions workflows (ci.yml, release.yml, autofix.yml, ecosystem-ci-trigger.yml, pkg.pr.new.yml). Workflows triggered on pull_request_target or with write permissions and external contributor access risk secret exfiltration if workflow files are not carefully scoped. Fix: Review all workflow triggers, especially 'pull_request_target' and 'workflow_dispatch'. Ensure secrets are not passed to untru
LLM-derived; treat as a starting point, not a security audit.
Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.