sycamore-rs/sycamore
A library for creating reactive web apps in Rust and WebAssembly
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 5w ago
- ✓16 active contributors
- ✓MIT licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 72% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/sycamore-rs/sycamore)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/sycamore-rs/sycamore on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: sycamore-rs/sycamore
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sycamore-rs/sycamore shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 5w ago
- 16 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 72% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live sycamore-rs/sycamore
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/sycamore-rs/sycamore.
What it runs against: a local clone of sycamore-rs/sycamore — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in sycamore-rs/sycamore | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 65 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sycamore-rs/sycamore. If you don't
# have one yet, run these first:
#
# git clone https://github.com/sycamore-rs/sycamore.git
# cd sycamore
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of sycamore-rs/sycamore and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sycamore-rs/sycamore(\\.git)?\\b" \\
&& ok "origin remote is sycamore-rs/sycamore" \\
|| miss "origin remote is not sycamore-rs/sycamore (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "packages/sycamore/Cargo.toml" \\
&& ok "packages/sycamore/Cargo.toml" \\
|| miss "missing critical file: packages/sycamore/Cargo.toml"
test -f "packages/sycamore-core/Cargo.toml" \\
&& ok "packages/sycamore-core/Cargo.toml" \\
|| miss "missing critical file: packages/sycamore-core/Cargo.toml"
test -f "packages/sycamore-reactive/Cargo.toml" \\
&& ok "packages/sycamore-reactive/Cargo.toml" \\
|| miss "missing critical file: packages/sycamore-reactive/Cargo.toml"
test -f "packages/sycamore-macro/Cargo.toml" \\
&& ok "packages/sycamore-macro/Cargo.toml" \\
|| miss "missing critical file: packages/sycamore-macro/Cargo.toml"
test -f "packages/sycamore-web/Cargo.toml" \\
&& ok "packages/sycamore-web/Cargo.toml" \\
|| miss "missing critical file: packages/sycamore-web/Cargo.toml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 65 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~35d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sycamore-rs/sycamore"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Sycamore is a reactive library for building web applications in Rust that compile to WebAssembly, eliminating the need for JavaScript. It provides fine-grained reactivity without a virtual DOM, using reactive primitives (signals and effects) inspired by SolidJS, and ships with a DSL-based view system (view! macro) for declarative UI composition. Monorepo organized as: packages/sycamore (main facade), packages/sycamore-core (component system), packages/sycamore-reactive (signals/effects engine), packages/sycamore-router (routing), packages/sycamore-web (DOM bindings), packages/sycamore-macro (procedural macros for #[component] and view!), packages/sycamore-futures (async integration). Examples/ contains 30+ runnable projects (hello-world, todomvc, ssr, hydrate) demonstrating features; tools/ has benchmarking utilities.
👥Who it's for
Rust developers building full-stack web applications who want to avoid JavaScript entirely, value performance control via WASM, and prefer reactive programming models over virtual DOM diffing. Both hobbyists prototyping small apps and teams building production single-page applications with SSR/hydration requirements.
🌱Maturity & risk
Production-ready and actively maintained. The project is at version 0.9.2 with comprehensive CI workflows (test.yml, coverage.yml, bench.yml), extensive documentation under docs/next/, 30+ examples, and active contributions. The codebase shows maturity through migration guides (0-7-to-0-8.md, 0-8-to-0-9.md) and systematic testing infrastructure, though the pre-1.0 version suggests the API may still have minor refinements.
Moderate risk: the Rust/WASM ecosystem is younger than JavaScript frameworks, meaning smaller community and fewer third-party integrations. The monorepo spans 9 core packages (sycamore-reactive, sycamore-router, sycamore-web, etc.), creating tight coupling risks if one package stalls. No obvious single-maintainer risk given GitHub contributors badge, but WASM tooling (Trunk, wasm-bindgen) adds external dependencies outside Sycamore's control.
Active areas of work
Active development on v0.9.2 with recent migration guides suggesting ongoing refinements (0-8-to-0-9.md added). CI workflows for benchmarking (bench.yml, js_framework_bench.yml) indicate performance is a priority. Documentation expansion (docs/next/guide contains multiple feature deep-dives like contexts, resources-and-suspense, tweened animations) suggests recent feature additions.
🚀Get running
Clone and explore: git clone https://github.com/sycamore-rs/sycamore && cd sycamore. Install Rust (https://rustup.rs/), then cd examples/hello-world && trunk serve to run the simplest example locally on http://localhost:8080. Alternatively, review the hosted examples at examples.sycamore.dev/hello-world.
Daily commands:
Monorepo uses Cargo workspace. Install Trunk (WASM bundler): cargo install trunk. Run any example: cd examples/{todomvc,router,ssr} && trunk serve (browser opens http://localhost:8080). Run full test suite: cargo test --workspace. Run docs: cargo doc --open --workspace.
🗺️Map of the codebase
packages/sycamore/Cargo.toml— Primary workspace package that re-exports and orchestrates the reactive framework's core modules; defines public API surface.packages/sycamore-core/Cargo.toml— Core rendering engine and component system; foundational abstraction for all view creation and lifecycle management.packages/sycamore-reactive/Cargo.toml— Reactive primitives (signals, memos, effects) that power state management; essential for understanding reactivity model.packages/sycamore-macro/Cargo.toml— Procedural macros for #[component] and view! DSL; critical for ergonomic developer experience.packages/sycamore-web/Cargo.toml— Web-specific bindings and DOM integration layer; bridges Rust runtime to browser APIs.Cargo.toml— Workspace root configuration defining all member packages and workspace-wide dependencies.README.md— Project charter, design philosophy, and high-level capability overview for all contributors.
🛠️How to make changes
Add a New Component
- Create a new Rust function annotated with #[component] macro in your crate (
packages/sycamore/Cargo.toml) - Define component signature returning View, accept props as function parameters (
examples/components/src/main.rs) - Implement component body using view! { ... } DSL for reactive template (
examples/counter/src/main.rs) - Use #[derive(Props)] on a struct to define typed component properties (
docs/next/reference/derive-props.md) - Instantiate component in parent views via view! { ComponentName { prop: value } } (
examples/higher-order-components/src/main.rs)
Add Reactive State to a Component
- Import signal creation from sycamore::reactive (e.g., create_signal) (
packages/sycamore-reactive/Cargo.toml) - Call create_signal(initial_value) within component function to spawn reactive variable (
examples/counter/src/main.rs) - Destructure returned tuple as (signal, set_signal) for read/write access (
docs/next/introduction/adding-state.md) - Reference signal in view! template; changes trigger automatic re-render (
examples/timer/src/main.rs) - Use create_effect to run side-effects reactively when dependencies change (
docs/next/reference/reactive-graph.md)
Add Client-Side Routing
- Add sycamore-router crate as dependency in Cargo.toml (
examples/router/Cargo.toml) - Define routes using #[component] for each page and Router component wrapper (
examples/router/src/main.rs) - Use Router DSL with route matching patterns to map URL paths to components (
docs/next/router.md) - Leverage Link component or navigate() to trigger client-side route transitions (
examples/router/src/main.rs)
Integrate Async Data Loading (Resources)
- Import create_resource from sycamore-futures for async data fetching (
packages/sycamore-futures/Cargo.toml) - Call create_resource(|| async { ... }) to spawn async task tracked by reactive system (
examples/http-request/src/main.rs) - Use Suspense boundary in view! to gracefully handle loading/error states (
docs/next/guide/resources-and-suspense.md) - Extract loaded data via resource.read() or pattern match on resource state (
examples/http-request-builder/src/main.rs)
🔧Why these technologies
- Rust + WebAssembly — Enables high-performance reactive web apps with compile-time safety and zero-cost abstractions; direct control over binary size and execution speed critical for WASM.
- Procedural Macros (#[component], view!) — Provides ergonomic, declarative syntax hiding complexity of reactive graph management; compile-time code generation ensures zero runtime overhead.
- Fine-grained Reactivity (Signals/Memos/Effects) — Granular dependency tracking minimizes re-render scope; only affected DOM nodes update, achieving performance comparable to framework libraries without virtual DOM overhead.
- Modular Workspace (9 packages) — Decouples concerns (core, reactive, web, routing, macros); allows users to cherry-pick features and reduces dependency bloat; enables independent versioning and testing.
- SSR & Hydration Support — Enables server-side rendering for SEO and faster initial paint; hydration bridges server-generated HTML to client reactivity without re-rendering.
⚖️Trade-offs already made
-
Fine-grained reactivity over Virtual DOM
- Why: Virtual DOM diffing adds overhead; per-signal subscriptions reduce unnecessary renders.
- Consequence: Developers must understand reactive primitives; steeper learning curve than simpler frameworks but superior performance on large apps.
-
Compile-time macros over runtime reflection
- Why: Avoids runtime overhead of dynamic introspection; all component logic resolved at compile time.
- Consequence: Macro-generated code may be harder to debug; errors surfaced at compile time (generally positive for type safety).
-
Rust-only codebase, no JavaScript interop by default
- Why: Pure Rust guarantees memory safety and consistency.
- Consequence: Requires wasm-bindgen for any browser API access; JavaScript library integration less seamless than JS frameworks.
-
No automatic hydration without explicit opt-in
- Why: Simpler mental model; developers only pay for hydration when building SSR apps.
- Consequence: SSR + client separation must be explicit; more boilerplate than frameworks with implicit hydration.
🚫Non-goals (don't propose these)
- Not a full-stack framework—does not handle server routing or database ORM; focuses purely on client-side reactivity.
- Does not provide authentication or authorization primitives—users must integrate with external solutions.
- Not a CSS-in-Rust library; styling deferred to external CSS, Tailwind, or component-scoped stylesheets.
- Does not target Node.js or non-browser WASM runtimes; browser-centric design (though server-side rendering via WASM is supported).
- Does not abstract over multiple rendering backends (e.g., native mobile, canvas); committed to DOM-based web rendering.
🪤Traps & gotchas
No global state singleton: Sycamore uses Rust's ownership system, so shared state must be passed explicitly via contexts or refs (see docs/next/guide/contexts.md). WASM-specific: println! debugging requires wasm-logger or console_log crate; standard Output doesn't reach browser console. Macro hygiene: view! macro is sensitive to scope; reactive variables must be in scope when the view is created. Pre-1.0 breaking changes: each 0.x→0.y upgrade may require API tweaks (see migration guides). No built-in form libraries: form handling is manual via event handlers and signals.
🏗️Architecture
💡Concepts to learn
- Fine-grained Reactivity — Sycamore's core differentiator vs virtual DOM frameworks; effects re-run only when exact dependencies change, enabling sub-component precision updates without re-rendering parent trees
- Signals (Reactive Values) — The fundamental primitive in Sycamore for state management; every reactive update flows through signal creation/updates, replacing class-based state or Redux
- Effects (Subscriptions) — Declarative side effect system; allows listening to signal changes without callback hell, replacing useEffect patterns from React
- WebAssembly (WASM) — The compilation target for Sycamore Rust code; understanding WASM's sandboxing, memory model, and JS interop constraints is essential for debugging performance and browser API integration
- Macro Metaprogramming (Procedural Macros) — Sycamore's view! and #[component] macros are compile-time code generators; understanding how they parse and transform code is needed to extend the DSL or debug macro errors
- Context API (Dependency Injection) — Sycamore's mechanism for avoiding prop drilling across component trees; critical for managing global config, themes, or authenticated user state without threading props through every component
- Hydration (Server-Side Rendering) — Sycamore supports SSR with hydration (examples/hydrate, examples/ssr-streaming); required for SEO and fast first paint, but hydration mismatches are a common footgun
🔗Related repos
solidjs/solid— The original inspiration for Sycamore's fine-grained reactivity and signals API; Solid is JavaScript while Sycamore is Rust/WASMleptos-rs/leptos— Direct competitor: another Rust/WASM framework with similar goals but different reactivity model (hooks vs signals); both target same user baseyewstack/yew— Earlier Rust web framework using virtual DOM; Sycamore explicitly chose fine-grained reactivity over Yew's VDOM approachtrunk-rs/trunk— Essential WASM bundler used by all Sycamore examples; Sycamore apps cannot run locally without Trunkrustwasm/wasm-bindgen— Underlying JS interop layer that Sycamore-web wraps; critical for DOM manipulation and browser API access
🪄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 comprehensive migration guide from 0.9 to next major version
The repo has migration guides for 0.7→0.8 and 0.8→0.9 (docs/next/migration/0-7-to-0-8.md and 0-8-to-0-9.md), but no guide for the next breaking change. As the project moves toward a new major version, having a template migration guide will help users transition smoothly and provide maintainers a structured way to document breaking changes. This is valuable given the active development cycle.
- [ ] Create docs/next/migration/0-9-to-0-10.md (or appropriate next version)
- [ ] Reference existing migration guides for structure and formatting
- [ ] Include common breaking changes patterns from the reactive graph and component system
- [ ] Add entry to docs/next/sections.json for navigation
- [ ] Link from docs/next/migration.md index
Add GitHub Actions workflow for example app compilation validation
The repo has workflows for testing, benchmarks, and building docs (.github/workflows/test.yml, bench.yml, build_docs.yml), but no workflow that validates all examples compile correctly. With 20+ examples in the examples/ directory, a dedicated CI workflow would catch breakage early and ensure example code stays current with API changes. Currently, only build_examples.yml exists but may not run on all PRs.
- [ ] Create .github/workflows/validate_examples.yml
- [ ] Configure to run cargo check and cargo build on all example crates (examples/*/Cargo.toml)
- [ ] Add wasm target validation for web examples
- [ ] Trigger on push to main, PRs, and version tag events
- [ ] Reference existing test.yml for secrets and runner configuration
Add testing guide to cookbook with specific examples for reactive primitives
The repo has docs/next/cookbook/testing.md but examining the file structure suggests it may lack concrete examples for testing Sycamore-specific patterns (signals, derived signals, effects, resources). Given the reactive graph is core to Sycamore (packages/sycamore-reactive/), adding practical testing recipes for these primitives would help contributors write better tests and understand the framework's testing story.
- [ ] Expand docs/next/cookbook/testing.md with sections for testing signals and derived signals
- [ ] Add examples for testing components with resources and suspense boundaries
- [ ] Include testing patterns for effects and side-effect validation
- [ ] Reference docs/next/reference/reactive-graph.md for reactive primitive details
- [ ] Add integration test examples from existing test suites in packages/
🌿Good first issues
- Add comprehensive example for using refs with canvas element rendering (examples/canvas-drawing/) and corresponding docs/next/guide/canvas-refs.md—currently node-ref.md exists but lacks canvas-specific patterns
- Expand sycamore-futures testing: packages/sycamore-futures/src/ lacks integration tests for resource streams with Suspense; add test_resource_stream_with_delayed_data() and test_suspense_fallback_render()
- Write migration guide 0-9-to-0-10.md template in docs/next/migration/—the pattern exists for 0-8 and 0-7 migrations but newer versions will need the same treatment structure in place
⭐Top contributors
Click to expand
Top contributors
- @lukechu10 — 72 commits
- @davidon-top — 6 commits
- @tguichaoua — 3 commits
- @AMNRG — 3 commits
- @phocks — 3 commits
📝Recent commits
Click to expand
Recent commits
626c17b— Update links to new website in docs (#816) (lukechu10)3c8b793— FixPortalhydration issues and wrong signature (#815) (lukechu10)c55f185— Fix hydration support forKeyedandIndexed(#814) (lukechu10)44238ca— Update wasm-pack test command to include --all-features (#813) (lukechu10)8c243a4— Add tag name to hydration error message (#812) (lukechu10)8acdaaf— Fix panic when suspense task is still running when scope is destroyed (#811) (lukechu10)d8b2f58— Fix possible to access dirty node value when dependencies change (#809) (lukechu10)6288804— Bump MSRV to 1.94 (#810) (lukechu10)f15a3e0— Fix nested batches to compose correctly (#806) (Aditya-PS-05)ffe6e9e— v0.9.2 (#805) (lukechu10)
🔒Security observations
Sycamore demonstrates a generally secure posture with a formal security policy, responsible disclosure process via GitHub Security Advisory, and a well-organized project structure. The main concerns are: (1) an incomplete Cargo.toml that needs verification, (2) lack of visible automated dependency scanning in CI/CD pipelines, and (3) potential XSS risks inherent to any web UI framework handling dynamic content. The project maintains two supported versions (0.9.x and 0.8.x) with a clear security update policy. No hardcoded credentials, exposed configuration files, or obvious injection vulnerabilities were identified in the provided structure. Recommendations focus on enhancing dependency scanning and documenting secure usage patterns for the framework.
- Medium · Incomplete Cargo.toml in Package Definition —
Cargo.toml - workspace.dependencies section. The workspace dependencies section appears truncated in the provided Cargo.toml. The last linesycamore-web = { patis incomplete, which could indicate either a configuration error or an unfinished dependency definition. This could lead to unintended dependency resolution or build failures. Fix: Verify that all workspace dependencies are properly defined with complete path and version specifications. Ensure the Cargo.toml file is syntactically valid and complete. - Low · No SAST or Dependency Scanning in Visible CI/CD —
.github/workflows/. The GitHub Actions workflows visible in the file structure (.github/workflows/) include test, fmt, coverage, and build workflows, but there is no evidence of automated dependency vulnerability scanning (e.g., cargo-audit, cargo-deny) or SAST tools configured. Fix: Add automated dependency vulnerability scanning using tools like cargo-audit or cargo-deny to CI/CD pipelines. Consider adding SAST scanning for Rust code to identify potential security issues early. - Low · XSS Risk in Web Framework Library —
packages/sycamore-web/, packages/sycamore-core/. Sycamore is a web UI framework for WebAssembly that handles DOM rendering. While the view! macro provides DSL-based template handling, there is potential for XSS vulnerabilities if user-supplied content is not properly escaped when building views or handling dynamic attributes, particularly when using raw DOM manipulation or JavaScript interop. Fix: Ensure comprehensive input validation and output encoding for all user-supplied data in views. Document secure usage patterns for dynamic content. Provide clear warnings about XSS risks when using JavaScript interop. Consider implementing Content Security Policy (CSP) guidance in documentation.
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.