Compared

FSR and seven other frameworks

Teams build and deploy their own sites on their own schedules. One Rust binary serves them all under one layout, session and store, with no Node. Below, FSR next to five JavaScript frameworks and two Rust ones, on the questions that decide a project.

  • One runtime for independently developed sites.
  • One shared application model across UI frameworks.
  • Native rendering without a JavaScript engine on the serving path.
TypeScript, run by RustJavaScriptRust
SnapFire FSRExcerion SunNext.jsVercelNuxtNuxtLabsSvelteKitSvelte teamAstroAstroRemix 3ShopifyLeptosCommunityDioxusDioxusLabs
Best forWhat is it built for?
Best forWhat is it built for?Large appsIndependent teams each deploy their own site into one app, served by one Rust binary.React SaaSSEO-heavy React apps and e-commerce.Vue appsVue content sites and SaaS.Interactive UIsApps where bundle size matters.Content sitesBlogs, docs and marketing.Full-stack server appsA fetch-based server that renders HTML and hydrates only the components you mark.DocsAll-Rust teamsApps written end to end in Rust.Cross-platform RustOne Rust codebase for web and native.
SubsitesCan teams deploy parts on their own?
SubsitesCan teams deploy parts on their own?Native microfrontendsEach team builds and deploys its own app. The host mounts it at a path inside the shared layout, session and store.GuideMulti-zonesSeparate apps joined by rewrites. Crossing zones reloads the page.DocsLayersLayers merge apps at build time. Separately deployed apps can share a domain under different baseURL paths.DocsBase path onlyEach app mounts under its own paths.base behind a proxy. Crossing apps is a full page load with no shared layout or state.DocsBase path onlyEach app mounts under its own base behind a proxy. Links between them are full page loads.DocsNot built inrouter.mount() splits one deployment. A separately deployed part sits behind fetch-proxy.DocsBase path onlyRouter base mounts one app under a path. Separate apps go behind a proxy.DocsBase path onlyEach app sets base_path to mount under its own path behind a proxy.Docs
Cross-island stateHow do separate widgets share a value?
Cross-island stateHow do separate widgets share a value?One store across islandsLoaders seed a keyed store the server renders from. React, Vue and Svelte islands read the same keys, with optimistic writes and rollback.GuideShared React treeContext and state libraries span the page. Only Client Components read them.DocsuseState built inShared state carried from the server to the browser. Server components cannot read it.DocsOne appRunes and context span the page.DocsLibraryNano Stores between islands. Nothing seeded by the server.DocsA model through contextAn event target made at the nearest shared client boundary and passed down.DocsSignals and contextShared in a hydrated app. In islands mode context passes only to nested islands.DocsOne appSignals and context span the page.Docs
FrameworksWhat do I write the UI in?
FrameworksWhat do I write the UI in?React, Vue, Svelte, Tera and web componentsAll five render on the server when the build can lower them.ReactServer and client components.VueVue single-file components.SvelteSvelte components.React, Vue, Svelte, Solid, PreactMixed on one page as islands.Its own JSX componentsremix/component, a JSX runtime of its own. React libraries do not work.DocsLeptos componentsWritten in Rust with the view! macro.Dioxus componentsWritten in Rust with RSX.
SSR or CSRWho decides server or browser?
SSR or CSRWho decides server or browser?AutomaticServer-rendered by default. The build moves only what needs the browser into islands.Per componentYou mark browser code with "use client".Per routeRoute rules pick SSR, static or SPA.Per routePage options turn SSR, CSR and prerendering on or off.Per islandStatic by default. You add a client directive to hydrate.Per componentPages render on the server. Components wrapped in clientEntry() hydrate.DocsYou chooseSSR with hydration, CSR or islands, set by feature flags.You chooseFullstack SSR with hydration. Also builds desktop and mobile apps.
Rendering modesStreaming, prerendering, caching?
Rendering modesStreaming, prerendering, caching?SSR, SSG, ISR, streaming, SWRPrerendered pages can be regenerated while the host serves, from the app's own Rust. Service data serves stale while it refreshes. Server islands and SPA navigation.GuideSSR, SSG, ISR, streamingPartial prerendering mixes static and dynamic.SSR, SSG, SPA, SWRRoute rules set each one per route.SSR, prerender, CSRLoad functions can stream promises.Static, SSR, server islandsServer islands render after the page.Streaming SSRFrames with a fallback stream in later. No prerender or static export.DocsStreaming, islands, CSRIn-order and out-of-order streaming.SSR, streaming, SSGPlus CSR, desktop and mobile.
PerformanceHow fast does it serve a page?
PerformanceHow fast does it serve a page?116,484 req/sThe arena's product page with 32 clients. Serves on every core.Benchmarks1,514 req/sThe same page from the standalone server, one Node process.Benchmarks3,893 req/sThe same page from the Nitro server, one Node process.Benchmarks13,800 req/sThe same page from adapter-node, one Node process.BenchmarksNot measuredNot in the arena. Zero JavaScript by default.Not measuredNot in the arena. ES modules through an import map. Only client entries ship JavaScript.93,882 req/sThe same page from its Axum server, on every core.Benchmarks32,289 req/sThe same page from its fullstack server, on every core.Benchmarks
Loading and isolationDoes one slow or broken widget hold up the page?
Loading and isolationDoes one slow or broken widget hold up the page?Islands load on their ownEach island fetches its own code and mounts in its own root, on load, on view or when idle. One that fails leaves the rest working.GuideOne React treeSuspense boundaries split hydration. error.tsx contains a failure to its segment.DocsOne appLazy hydration per component is opt-in. Server components are experimental.DocsOne appThe page hydrates as one component tree. Streamed promises and svelte:boundary keep a slow or failing part from blocking the rest.DocsIslands per componentEach island hydrates on its own directive. A slow island does not block the others.DocsFrames load on their ownA frame with a fallback is its own request. If it fails the fallback stays.DocsOpt-in islandsWhole-app hydration unless islands mode is on. Then islands hydrate one after another in page order, from one WASM binary.DocsOne appHydrates as one WebAssembly app. The server waits for every suspense boundary unless out-of-order streaming is on.Docs
Stores and signalsWhat holds a value that changes?
Stores and signalsWhat holds a value that changes?Shared store, local stateuseStore over typed keys, with derive, transaction and optimistic. React's useState and Vue's ref and computed hold what one island owns.React stateuseState and context. Signals only through a library.Vue refsref, computed and reactive are signals.Runes$state and $derived are signals compiled into the component.Per frameworkEach island keeps its own framework's state. Nano Stores to share.Variables and update()State is plain variables. handle.update() re-renders. No signals or store.DocsFine-grained signalssignal() and memos update only the DOM that reads them.Signalsuse_signal and memos re-render the components that read them.
Streaming and boundariesWhat happens when one data source is slow or fails?
Streaming and boundariesWhat happens when one data source is slow or fails?Streams per segmentloading.tsx and error.tsx beside any route. A failing layout or slot loader degrades only its segment.GuideSuspense per segmentloading.js and error.js per route segment. Parent layouts stay up.DocsExperimental streamingA fatal server error replaces the page with error.vue. NuxtErrorBoundary catches client errors only.DocsStreamed promises+error.svelte catches load errors at the nearest route. svelte:boundary catches render errors in place. No loading file.DocsIn-order streamingServer islands load on their own. A render error on an on-demand page shows 500.astro.DocsFrame fallbacksNo error boundary component. resolveFrame decides how a failed frame shows.DocsOut-of-order by defaultSuspense and ErrorBoundary are components, not route files.DocsOpt-in out-of-orderSuspense and error boundaries are components, not route files.Docs
Parallel and intercepting routesCan a modal or side panel be its own route?
Parallel and intercepting routesCan a modal or side panel be its own route?Slots and interceptsA slot is a parallel segment with its own loader. page.<slot>.tsx opens a route over the page, applied on the server.GuideSlots and interception@slot folders and (.) intercepts that show a route as a modal.DocsNamed viewsNo interception or modal routes.DocsShallow routingModals tied to history in the browser. The server does not see them.DocsNot built inOne page at a time.DocsNamed framesA side panel can be a named frame backed by its own route. No intercepting routes.DocsNested outletsNo parallel or intercepting routes.DocsLayouts and OutletNo parallel or intercepting routes.Docs
Caching and revalidationWhat does it cache and how do you drop it?
Caching and revalidationWhat does it cache and how do you drop it?Render memo and tagged dataWith a [cache] section the host memoizes renders by their data. With [cache.data] enabled = true, service calls cache for a TTL, serve stale while they refresh and drop the tags a write names. Bundle files are named by their content and kept for a year.DocsTagged cacheuse cache, cacheTag and revalidateTag. ISR for unknown params.DocsRoute rulesswr and isr per route. Keyed data and cached functions without tags.DocsLoad invalidationinvalidate re-runs loads. ISR only through the Vercel adapter.DocsRoute cache with tagsEntries purge by tag or path. Needs a cache provider, with an in-memory one built in.DocsHeaders onlyCache-Control, ETags and Vary per response. No revalidation API.DocsStatic routesPrerendered or incremental pages. No tagged data cache.DocsIncremental rendererPages cached in memory and on disk with an optional expiry. Invalidation is per route, with no tags.Docs
Built inImages, fonts, uploads and validation?
Built inImages, fonts, uploads and validation?All built inPicture writes resized variants and fonts are self-hosted. Actions take uploads and validate their input.GuideImages and fontsnext/image and next/font ship with Next. Actions get FormData and the docs point to Zod.DocsOfficial modules@nuxt/image and @nuxt/fonts. h3 reads multipart bodies and validates against a schema.DocsImages and formsenhanced:img for images. Remote form functions take files and any Standard Schema. No font helper.DocsAll built inastro:assets for images and a fonts API. Actions validate form data with Zod, files included.DocsUploads and schemasform-data-parser streams uploads and data-schema validates FormData. No image or font package.DocsUploads onlyserver_fn has a multipart codec for uploads. Images, fonts and validation come from crates.DocsImages and uploadsasset! resizes and converts images at build. Uploads stream in. Validation comes from crates.Docs
Sign-inSessions, passkeys, SSO, two-factor?
Sign-inSessions, passkeys, SSO, two-factor?Built inSessions in a store or sealed in the cookie. Passkeys, OpenID Connect with Google, Microsoft and Apple presets and a second factor.GuideLibrariesNo built-in sessions or sign-in. The docs point to Auth.js, Better Auth and Clerk.Docsnuxt-auth-utilsThe docs recipe uses it for cookie sessions, OAuth and passkeys. No two-factor.DocsLibrariesNo built-in auth. The CLI can add Better Auth and the docs link a sessions guide.DocsSessions onlyA built-in sessions API. No official sign-in; the docs point to Better Auth and Clerk.DocsSessions and OAuthSession and auth packages cover OAuth and OpenID Connect sign-in. No passkeys or two-factor.DocsCratesNo sessions or auth of its own. Its example uses axum_session_auth.DocsCratesNo built-in auth. The docs point to axum_session_auth.Docs
OfflineDoes it work offline?
OfflineDoes it work offline?Built in[pwa] serves a manifest and a worker that precaches the build. Pages read online and updateReady.Manifest onlyThe manifest is built in. Offline caching is left to Serwist.DocsCommunity module@vite-pwa/nuxt adds the manifest and a Workbox worker.DocsWorker built inSvelteKit bundles the service worker and lists the build files to precache. The manifest is yours.DocsCommunity integrationsNo official guide. @vite-pwa/astro and others add the worker.DocsNot coveredNo service worker, manifest or offline package.DocsNot coveredThe book and examples cover no service worker or manifest.DocsAn exampleAn official example has a manifest and a hand-written worker. No build precache.Docs
BackendsHow does it talk to APIs?
BackendsHow does it talk to APIs?Typed contractsOpenAPI, Protobuf and GraphQL documents become typed clients. The host attaches credentials and refreshes tokens.Guidefetch, no codegenServer Components call fetch or an ORM. Typed clients come from third-party tools.Docs$fetch and useFetchuseFetch is SSR-safe and forwards cookies. OpenAPI clients come from community modules.Docsfetch in loadLoad functions get a fetch that carries cookies and takes relative URLs. No contract codegen.DocsPlain fetchComponents call fetch at build or request time. GraphQL is a fetch POST.DocsFetch APIControllers handle Fetch requests and fetch-proxy forwards them. No typed API client.DocsServer functions#[server] functions run on the server and the browser calls them over HTTP.DocsServer functions and reqwestFullstack server functions are called over HTTP. There is no built-in HTTP client.Docs
Share cardsCan a page draw its own social image?
Share cardsCan a page draw its own social image?Drawn in Rustopengraph-image.tsx beside a page draws from the page's data. No browser or Node renders it.GuideImageResponseopengraph-image.tsx returns an ImageResponse, drawn with Satori and Resvg on the server. Cached at build unless it reads the request.DocsCommunity modulenuxt-og-image draws a Vue component with Takumi or Satori, at build for prerendered pages.DocsNot built inA +server.js endpoint draws it, usually with satori and resvg.DocsNot built inCommunity astro-og-canvas or Satori in a .png.ts endpoint.DocsNot built inA route returns any Response, so an image route with satori and sharp.DocsNot built inleptos_meta writes og:image tags. Drawing the image is up to you.DocsNot built indocument::Meta writes og:image. Drawing the image is up to you.Docs
TailwindHow does Tailwind get in?
TailwindHow does Tailwind get in?Compiled in RustTailwind v4 ported to Rust, fed the classes the build found. No Node and no content globs.GuidePostCSS plugin from npmtailwindcss and @tailwindcss/postcss from npm. create-next-app sets it up by default.DocsVite plugin from npmtailwindcss and @tailwindcss/vite from npm, added to vite.plugins.Docssv add tailwindcssInstalls Tailwind's Vite plugin from npm and edits the stylesheet.Docsastro add tailwindInstalls @tailwindcss/vite from npm and writes the stylesheet.DocsNot built inRun Tailwind's CLI and serve its output. The asset server has no Tailwind step.DocsStandalone CLIcargo-leptos downloads Tailwind's standalone binary when tailwind-input-file is set. No npm.DocsAutomatic, no npmdx starts Tailwind's standalone binary when tailwind.css sits beside Cargo.toml.Docs
Light and darkWho picks light or dark before first paint?
Light and darkWho picks light or dark before first paint?Chosen on the servertheme.ts picks the scheme per request and the host writes it on <html>. No script runs before paint.DocsInline scriptNo theme API. The docs have an inline script in the head set data-theme before paint.DocsModule's inline script@nuxtjs/color-mode puts a script in the head that sets the class before paint.DocsNot built inmode-watcher sets the scheme from a head script. A handle hook can write it from a cookie.DocsYour own inline scriptThe tutorial reads localStorage in an is:inline script and sets a class on <html>.DocsNot built inA demo reads a cookie in middleware and renders data-theme on <html>.Docsleptos-useuse_color_mode reads a client hint or a cookie on the server. Without one the first visit can flash.DocsNot built inAn inline script in a custom index.html sets it before the WebAssembly loads.Docs
Sitemap and robotsAre robots.txt and a sitemap built in?
Sitemap and robotsAre robots.txt and a sitemap built in?Built in[crawl] serves robots.txt and a sitemap of every page an anonymous visitor is served, from the routes and paths exports.DocsFile conventionsapp/sitemap.ts and app/robots.ts return typed data. Static files work too.DocsTwo community modules@nuxtjs/sitemap and @nuxtjs/robots from Nuxt SEO.DocsNot built inThe docs show a sitemap as a +server.js endpoint. robots.txt goes in static/.DocsOfficial sitemap integration@astrojs/sitemap writes the sitemap. robots.txt is yours to write.DocsNot built inRoutes that return text or XML, built with the route map's href helpers.DocsNot built inAn Axum handler over generate_route_list builds the sitemap.DocsNot built inNo sitemap is written. A robots.txt in public/ is copied as it is.Docs
MDXCan pages be written in MDX?
MDXCan pages be written in MDX?Built in, a Cargo featurepage.mdx and imports lower like any component, with frontmatter, collections and code highlighted at build.Docs@next/mdxMDX pages and imports with mdx-components.tsx. Frontmatter needs a remark plugin.DocsMDC, not MDXNuxt Content places Vue components in Markdown with its own MDC syntax.Docsmdsvex, not MDXsv add mdsvex mixes Svelte components into Markdown.DocsOfficial integration@astrojs/mdx makes .mdx pages and content collection entries.DocsNot built inNo MDX compiler. Render Markdown with a library of your own.DocsNot built inClosed as not planned. Community crates render Markdown to views.DocsNot built inCommunity crates such as dioxus-mdx. None is official.Docs
View transitionsDo page changes animate?
View transitionsDo page changes animate?One optionenableNavigation({ transitions: true }) swaps pages inside a view transition.GuideReact ViewTransitionRoutes animate inside <ViewTransition> from React 19.3, with no configuration.DocsExperimental flagexperimental.viewTransition turns on the View Transitions API.DocsonNavigate, by handCall document.startViewTransition inside onNavigate in the root layout.DocsClientRouter<ClientRouter /> animates page changes, with transition:name and transition:persist.DocsNot by defaultSoft navigations skip view transitions. Wrap navigate() in startViewTransition yourself.DocsOpt-in prop<Routes transition=true> uses the View Transition API.DocsNot built inThe router has no view transitions. The community dioxus-motion crate adds animated outlets.Docs
Keeping a pageDoes going back keep what the visitor typed?
Keeping a pageDoes going back keep what the visitor typed?One optionenableNavigation({ activity: true }) keeps the last ten pages' DOM. React 19.2 islands keep their state.GuideWith cacheComponentsThe last three routes are hidden under React's <Activity> instead of unmounted.DocsKeepAlive, opt-inkeepalive on <NuxtPage> or in definePageMeta keeps a page's state.DocsSnapshots, by handDOM state is discarded unless a page exports a snapshot that captures and restores it.DocsPer elementtransition:persist carries an element or island to the next page when it appears there too.DocsRefetched on backBack and forward reload the page from the server. data-rmx-preserve-dom keeps marked elements.DocsNot built inThe router replaces the old route's view and has no keep-alive or snapshot API.DocsNot built inThe Outlet renders only the active route, so leaving a page drops its state.Docs
i18nLocales, translations and formatting?
i18nLocales, translations and formatting?Built in, routing to formattingLocale from prefix, cookie or header. Message catalogs and number and date formatting that match on server and browser.Do it yourselfProxy plus a [lang] segment and your own dictionaries.Community moduleRouting and messages through @nuxtjs/i18n.CLI add-onsv add paraglide sets up routing and messages.Routing built inPrefixes, fallbacks and domains. Translations from libraries.Not built inThe official demo uses i18next in middleware with Intl for formatting.DocsCommunity crateleptos_i18n for messages and formatting. leptos_i18n_router adds locale routing.Community cratedioxus-i18n for Fluent messages. No locale routing.
Content-Security-PolicyDoes a strict CSP just work?
Content-Security-PolicyDoes a strict CSP just work?CSP built inThe host adds a hash or a nonce for every script and literal style it emits. New apps start report-only and fsr dev names the fix for each violation.GuideCSP by handNonces set in proxy, which forces dynamic rendering. Experimental SRI hashes keep pages static.DocsThrough a moduleThe third-party nuxt-security module adds headers and a CSP with nonces or hashes.DocsCSP built inThe csp config adds hashes or nonces for its own inline scripts and styles.DocsCSP hashesThe security.csp config hashes its scripts and styles. It does not work with ClientRouter.DocsNo nonce yetInline import map and styles carry no nonce. Nonce support is an open pull request.DocsNonce featureWith the nonce feature on, its inline scripts carry a nonce. The policy is yours to set.DocsNo nonce supportServer rendering writes inline hydration scripts with no nonce. The header is yours to set.Docs
Server Attack SurfaceWhat runs on the server when a request comes in?
Server Attack SurfaceWhat runs on the server when a request comes in?No JS runtimeThe Rust host evaluates the IR the build wrote. With no Node and no npm code, deserialization, prototype pollution, eval injection and npm install scripts have nothing to reach.GuideNode and the RSC decodernpm packages run in the server process and their install scripts run on the machine that installs them. React2Shell (CVE-2025-55182) was unauthenticated code execution through the RSC decoder until patched. The Brotli decoder bug (CVE-2026-111497) hit Node's bundled Brotli.DocsNode or Bunnpm packages run in the server process and their install scripts run on the machine that installs them. Not affected by React2Shell. The Brotli decoder bug (CVE-2026-111497) hit a server that decompresses Brotli until Node or Bun was patched.DocsNode or Bunnpm packages run in the server process and their install scripts run on the machine that installs them. Not affected by React2Shell. The Brotli decoder bug (CVE-2026-111497) hit a server that decompresses Brotli until Node or Bun was patched.DocsNode or Bunnpm packages run in the server process and their install scripts run on the machine that installs them. Not affected by React2Shell. The Brotli decoder bug (CVE-2026-111497) hit a server that decompresses Brotli until Node or Bun was patched.DocsA Fetch runtimenpm packages run in the server process and their install scripts run on the machine that installs them. Not affected by React2Shell. On Node or Bun, the Brotli decoder bug (CVE-2026-111497) hit a server that decompresses Brotli until patched.DocsRust, no JS runtimeServer functions decode their arguments in the Rust server. No Node on the server.Rust, no JS runtimeServer functions decode their arguments in the Rust server. No Node on the server.
DeploymentWhere can it run?
DeploymentWhere can it run?One binaryCopy it and a directory to any server. No Node. The arena storefront is 25.7 MiB to deploy. The same app opens in a desktop window too.Vercel firstRuns on any Node server. The arena storefront is 151.8 MiB to deploy with Node.Many runtimesNode, workers and static hosts. The arena storefront is 109.7 MiB to deploy with Node.AdaptersNode, static, serverless and edge. The arena storefront is 108.8 MiB to deploy with Node.Static or SSRAdapters for most hosts.Any Fetch runtimeA Request to Response handler for Node, Bun, Deno or Workers. The starter needs Node 24.DocsRust binaryAxum or Actix server plus a WASM bundle. The arena storefront is 13.3 MiB to deploy.Rust binaryServer, WASM, desktop or mobile. The arena storefront is 8.6 MiB to deploy.
DesktopCan it ship as a desktop app?
DesktopCan it ship as a desktop app?Built in, experimentalfsr serve --desktop opens the app in the OS webview with the host in the same process. Tried on macOS only.Through TauriNo desktop target. Tauri's guide needs a static export, so server code does not carry over.DocsThrough TauriNo desktop target. Tauri's guide needs ssr: false.DocsThrough TauriNo desktop target. Tauri's guide uses adapter-static in SPA mode.DocsWrap it yourselfNo desktop target and no official recipe. Community templates exist.DocsNo documented pathNo desktop target. The supported runtimes are servers.DocsThrough TauriNo desktop target. Tauri's guide builds Leptos with Trunk as a static site.DocsBuilt inDesktop is a first-party target over the system webview. A native renderer is experimental.Docs
TerminalCan it draw a terminal UI?
TerminalCan it draw a terminal UI?Ink, with no Node, experimentalThe root page is written against FSR's Ink, lowered to IR and drawn by fsr, with no Node or React.NoWeb only. Ink is a separate React renderer.DocsNoWeb only. Vue TermUI is a separate Vue renderer.DocsNoWeb only. Small community projects render Svelte in a terminal.DocsNoHTML sites only.NoIts terminal package styles CLI output and renders no components.DocsNoRenders to the DOM and to server HTML.DocsNot anymoredioxus-tui is deprecated until Blitz is stable.Docs
EcosystemWhat can I bring with me?
EcosystemWhat can I bring with me?NewSmall so far. fsr add vendors npm packages as ES modules, with no node_modules. fsr migrate brings in Next.js and Ink apps.LargestIntegrations, hosting and hiring.LargeA module for most needs.GrowingSmaller than React's and well liked.Growing fastCMS and content integrations.npm, minus ReactBrowser npm packages and web components work. React libraries do not.DocsSmallRust crates, few UI libraries.SmallRust crates, few UI libraries.
Migrating inCan I bring an existing app?
Migrating inCan I bring an existing app?fsr migrateRewrites a Next.js app, App or Pages Router, into an FSR project. Many of Next.js's own examples build after it. Ink apps too.Codemods and guides@next/codemod rewrites code for upgrades and from Create React App. Vite has a written guide.DocsCodemods for Nuxt 4Codemods automate many Nuxt 4 steps. Nuxt 2 to 3 is a written guide.Docssv migrateRewrites Svelte and SvelteKit apps between major versions. Sapper has a written guide.DocsWritten guidesGuides for Next.js, Gatsby, Nuxt and others, many of them stubs. No conversion tool.DocsNone yetNot a drop-in upgrade. Remix 2 apps are pointed at React Router 7.DocsRelease notesUpgrades are breaking-change lists in the release notes. No tool.DocsHTML to RSXdx translate turns HTML into RSX. Upgrades have written guides.Docs
DifficultyHow hard is it to start?
DifficultyHow hard is it to start?MediumRoutes, loaders and actions in TypeScript. Islands and the shared store are new ideas. fsr migrate does the first pass on a Next.js app.MediumThe App Router has a lot to learn.Low to mediumConventions do most of the wiring.LowSyntax close to HTML.Low to mediumA simple core.New modelOne dependency to start. Components, frames and routing are all new APIs.DocsHighRust, lifetimes and signals.Medium to highRust with React-like components.

Performance and deploy size: the same storefront built in six of these frameworks and served on one machine, from the benchmarks page and the full arena results. The other cells summarise each project's own documentation, with a link where a row's argument depends on the claim, checked in October 2026.

Build your first page

The first tutorial starts from an empty directory and ends with a page served by Rust.