I Tried SolidJs in 2026 - Here Is What I Actually Think
Nitesh Babu
08 May 2026Every year or so, something in the JavaScript ecosystem earns the description “what React should have been from the start.” Most of the time that framing is marketing. Occasionally it is worth taking seriously.
SolidJs is one of those occasions.
I had been aware of Solid for a while, bookmarking articles and filing it under “look at this properly someday.” Last week I finally sat down with it seriously, built a couple of real things, benchmarked them, and tried to understand what is genuinely different and what is just a different colour of the same ideas. This post is what I found.
Why SolidJs Is Not Just “React But Faster”
The easy pitch for SolidJs is that it is fast. It consistently tops the JS Framework Benchmark, it has no virtual DOM, and its author Ryan Carniato has written extensively about why fine-grained reactivity beats reconciliation. All of that is true. But if you go in expecting a drop-in React alternative that just renders quicker, you will misunderstand what you are dealing with.
Solid is not a better implementation of the same model. It is a different model that happens to use JSX.
React’s core idea is: when state changes, re-run the component function. React manages what to actually update in the DOM by comparing the new output against the previous output (the virtual DOM reconciliation step). This means component functions run frequently on every state change that affects them, and sometimes on state changes that do not.
Solid’s core idea is: when state changes, update only the exact DOM node that depends on that state. There is no re-running component functions. There is no diffing. Component functions in Solid run once, during setup. What they return is not a description of the DOM,, it is the DOM setup instructions. After that, reactive primitives take over and surgically update just what changed.
That distinction matters more than any benchmark number.
The Core API
Solid’s surface area is deliberately small. If you know React hooks you can read Solid code within minutes, but the semantics are meaningfully different.
createSignal - Reactive State
import { createSignal } from 'solid-js'
function Counter() {
const [count, setCount] = createSignal(0)
return (
<button onClick={() => setCount(count() + 1)}>
Count: {count()}
</button>
)
}
The first thing you notice: count is a function you call, not a plain value. That is not an accident. When Solid tracks which pieces of the DOM depend on which state, it does so by watching which signals get called during execution. If you pass count (the function reference) somewhere without calling it, Solid cannot track that dependency. Calling count() is what creates the reactive bond.
This feels strange for about ten minutes, then it clicks, and you start to appreciate how explicit the dependency tracking is.
Comparison with React useState:
// React -> count is a plain value, setCount triggers a full re-render
const [count, setCount] = useState(0)
// Solid -> count() is a getter, calling it subscribes the current context
const [count, setCount] = createSignal(0)
createMemo - Derived State
import { createSignal, createMemo } from 'solid-js'
function PriceCalculator() {
const [quantity, setQuantity] = createSignal(1)
const [unitPrice] = createSignal(49.99)
const total = createMemo(() => (quantity() * unitPrice()).toFixed(2))
return (
<div>
<input
type="number"
value={quantity()}
onInput={(e) => setQuantity(Number(e.target.value))}
/>
<p>Total: ${total()}</p>
</div>
)
}
createMemo is Solid’s equivalent of useMemo, but without the dependency array. Solid figures out the dependencies automatically because it tracks which signals were called inside the memo function. You cannot accidentally forget a dependency. This alone eliminates an entire category of stale-closure bugs that React developers spend time chasing.
createEffect - Side Effects
import { createSignal, createEffect } from 'solid-js'
function SearchBox() {
const [query, setQuery] = createSignal('')
createEffect(() => {
if (query().length > 2) {
console.log('Searching for:', query())
// fetch results, update store, etc.
}
})
return (
<input
value={query()}
onInput={(e) => setQuery(e.target.value)}
/>
)
}
Again, no dependency array. Solid re-runs the effect whenever any signal called inside it changes. If you add a second signal call to the effect later, it automatically becomes a dependency. This is not magic, it is a consequence of the synchronous tracking model. Solid wraps the effect execution in a tracking context and records every signal that fires during it.
createStore - Nested Reactive State
For complex state trees, Solid has createStore, which provides fine grained reactivity all the way down nested objects:
import { createStore } from 'solid-js/store'
function UserProfile() {
const [user, setUser] = createStore({
name: 'Nitesh',
preferences: {
theme: 'dark',
notifications: true,
},
})
return (
<div>
<p>{user.name}</p>
<button
onClick={() =>
setUser('preferences', 'theme', (t) => (t === 'dark' ? 'light' : 'dark'))
}
>
Toggle theme: {user.preferences.theme}
</button>
</div>
)
}
The key behaviour here: when user.preferences.theme changes, only the DOM node displaying it updates. Not user.name. Not anything else on the page. Solid’s store tracks property access at the path level, not the object level. In React with useState, updating a nested property requires spreading the whole object, which can trigger updates across anything that touches that state, even through memoization.
Components Work Very Differently
This is the part that surprises React developers most.
In React, a component function is your render function. It runs on every update. You can put hooks inside it, conditionals around logic, early returns, whatever, React will call that function again whenever it needs a new description of your component.
In Solid, a component function is a setup function. It runs exactly once. The return value is not re-evaluated; it is used to construct the actual DOM nodes and wire up the reactive bindings. After that, component functions are done.
This has a practical consequence: you cannot use JavaScript control flow for conditional rendering inside JSX. If you write:
// This does NOT work in Solid the way you expect
function Status({ isLoggedIn }) {
return <div>{isLoggedIn ? <UserPanel /> : <LoginForm />}</div>
}
The ternary runs once at setup time. After that, isLoggedIn changing will not swap the components because the component function will not re-run.
Instead, Solid ships control flow as components:
import { Show, For, Switch, Match } from 'solid-js'
function Status(props) {
return (
<div>
<Show when={props.isLoggedIn} fallback={<LoginForm />}>
<UserPanel />
</Show>
</div>
)
}
function List(props) {
return (
<ul>
<For each={props.items}>
{(item) => <li>{item.name}</li>}
</For>
</ul>
)
}
Show subscribes to props.isLoggedIn reactively and swaps the rendered content when it changes. For creates minimal DOM patches when items are added, removed, or reordered. Both are more efficient than their React equivalents because they do not re-render a parent to accomplish their job.
The adjustment period for this pattern is real, probably few days of occasional “why is this not updating” before it becomes second nature.
Props Are Not Destructured - And That Is Intentional
One of the most common Solid gotchas coming from React:
// React -> fine to destructure, it's just function arguments
function Card({ title, body }) {
return <div><h2>{title}</h2><p>{body}</p></div>
}
// Solid -> DO NOT destructure
function Card({ title, body }) {
// title and body are now plain strings, reactivity is broken
return <div><h2>{title}</h2><p>{body}</p></div>
}
// Solid -> correct
function Card(props) {
return <div><h2>{props.title}</h2><p>{props.body}</p></div>
}
In Solid, props is a reactive object. When a parent signal changes the value of title, Solid can update the DOM because it is tracking props.title - the property access on the reactive object. Destructuring breaks that tracking by extracting the current scalar value at setup time.
If you genuinely need a local variable, Solid gives you splitProps and the mergeProps utility to handle it safely.
The Ecosystem in 2026
Solid has matured considerably. The rough areas are largely smoothed out.
SolidStart - the meta-framework, is stable and opinionated in the right ways. File based routing, server functions, SSR with streaming, and island architecture all work well. The API surface has settled enough that tutorials written six months ago are still accurate. The use server / use client directive model will feel immediately familiar to anyone who has used Next.js App Router.
SolidUI - a Tailwind-based component library in the spirit of shadcn/ui, is the go-to starting point for UI primitives. You copy components into your project rather than importing a library, which keeps bundle size tight and gives you full control.
TanStack Router has first-class SolidJs support. If you have used TanStack Router on React, the Solid version is almost identical. This matters because router quality is often what holds a framework back on real projects.
State management: for most apps, createSignal and createStore are sufficient. For global state, createContext with a store works cleanly. Libraries like @nanostores/solid are available if you want something more structured across a large codebase.
Where Solid still lags React is in the broader package ecosystem. If you need a complex date picker, a virtualized data grid, or a specific third-party integration that ships a React component, your options narrow fast. The community is growing, but React’s decade long headstart in component libraries is not closed yet.
Benchmark Comparison With React
Let’s look at numbers. The JS Framework Benchmark maintained by Stefan Krause is the most rigorous public comparison. It tests a standardised set of DOM operations across every major framework.
All figures are a geometric mean overhead ratio versus vanilla JavaScript. Lower is better. 1.00 = same speed as vanilla JS.
| Operation | SolidJs | React 19 |
|---|---|---|
| Create 1,000 rows | 1.04× | 1.38× |
| Replace 1,000 rows | 1.05× | 1.42× |
| Partial update (every 10th row) | 1.06× | 1.41× |
| Select a row | 1.02× | 1.44× |
| Swap 2 rows | 1.08× | 1.51× |
| Remove a row | 1.03× | 1.34× |
| Create 10,000 rows | 1.07× | 1.44× |
| Append 1,000 to 10,000 rows | 1.05× | 1.49× |
| Clear 10,000 rows | 1.03× | 1.37× |
| Geometric mean | 1.05× | 1.42× |
React 19 with the new compiler is meaningfully faster than React 18. But Solid’s model places it structurally closer to vanilla JavaScript in ways that compiler optimisations alone cannot bridge for React.
Memory Allocation (overhead ratio vs vanilla JS)
All figures are a memory overhead ratio versus vanilla JavaScript. Lower is better. 1.00 = same memory as vanilla JS.
| Scenario | SolidJs v1.9.3 | React 19 |
|---|---|---|
| Ready memory - usage after page load | 1.17× | 2.46× |
| Run memory - after adding 1,000 rows | 1.45× | 2.49× |
| Create/clear 1k rows × 5 - after 5 cycles | 1.19× | 3.16× |
| Geometric mean | 1.26× | 2.68× |
The virtual DOM representation and the component fibre tree carry a real memory cost. Solid’s geometric mean overhead is 1.26× vanilla React’s is more than 2× that at 2.68×.
Transferred Size & First Paint (overhead ratio vs vanilla JS)
All figures are an overhead ratio versus vanilla JavaScript. Lower is better. 1.00 = same as vanilla JS.
| Scenario | SolidJs v1.9.3 | React 19 |
|---|---|---|
| Uncompressed size all implementation files | 1.02× | 16.34× |
| Compressed size brotli compressed | 1.80× | 20.08× |
| First paint initial page render | 1.10× | 6.30× |
| Geometric mean | 1.27× | 12.76× |
Solid ships roughly 1.27× vanilla JS in bundle overhead. React’s virtual DOM and runtime push that to 12.76×, an order of magnitude heavier, which directly affects first paint on slow connections or low-end devices.
Does This Matter For Your App?
Honestly, for most CRUD apps, dashboards, and content sites: not measurably. React 19 with the compiler is plenty fast for the vast majority of real-world use cases. The benchmark gap becomes tangible when you are:
- Rendering large, frequently updating lists (data grids, real-time feeds)
- Running on low-end hardware or mobile with a poor CPU
- Building something where every millisecond of interaction latency affects the product quality (collaborative tools, canvas editors, audio/video timelines)
For those categories, the performance difference is real and felt by users, not just by benchmarks.
Side-by-Side: The Same Feature in React and Solid
Here is a live search list filter, a realistic component that shows the reactivity model differences clearly.
React:
import { useState, useMemo } from 'react'
const items = ['Astro', 'SolidJs', 'React', 'Svelte', 'Vue', 'Angular', 'Qwik']
export function SearchList() {
const [query, setQuery] = useState('')
const filtered = useMemo(
() => items.filter((i) => i.toLowerCase().includes(query.toLowerCase())),
[query]
)
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search frameworks..."
/>
<ul>
{filtered.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
)
}
SolidJs:
import { createSignal, createMemo, For } from 'solid-js'
const items = ['Astro', 'SolidJs', 'React', 'Svelte', 'Vue', 'Angular', 'Qwik']
export function SearchList() {
const [query, setQuery] = createSignal('')
const filtered = createMemo(() =>
items.filter((i) => i.toLowerCase().includes(query().toLowerCase()))
)
return (
<div>
<input
value={query()}
onInput={(e) => setQuery(e.target.value)}
placeholder="Search frameworks..."
/>
<ul>
<For each={filtered()}>{(item) => <li>{item}</li>}</For>
</ul>
</div>
)
}
Both are readable. Both are about the same length. The differences are:
- Solid’s
createMemoneeds no dependency array,queryis tracked automatically - The
Forcomponent in Solid performs keyed reconciliation internally without you specifying keys - The
onInputvsonChangenaming reflects that Solid maps more directly to browser event names query()must be called (not just referenced) everywhere it is used reactively
What I Liked
No stale closures. The most common React bug I chase in other people’s codebases, a useEffect capturing a stale value from a previous render - simply does not exist in Solid. The reactive system tracks live dependencies, not closed-over values from setup time.
Smaller bundles. A minimal SolidJs app ships roughly 7 KB of framework code. A minimal React + ReactDOM setup is around 45 KB. When you are building something with Astro or a content-heavy site, that difference matters.
Props are always current. In React, if a parent re-renders and passes a new prop value, you sometimes need useRef tricks to get the latest value inside a useEffect. In Solid, props.value is always the current value because it is a live reactive reference.
Mental model is more honest. Solid’s model says: “this is DOM setup code, and these are the reactive bindings.” React’s model says “this is a description of what the DOM should look like.” The Solid model maps more directly to how browsers actually work.
What Was Rough
The props destructuring footgun catches everyone at least once, and there is no compiler error to help you, the code just does not update and you have to know why.
Server-side rendering edge cases. SolidStart’s SSR works well for the common path, but when you get into edge cases with async data loading, resource ownership, and hydration timing, the error messages are less helpful than Next.js. The surface is still maturing.
Third-party component ecosystem. This is the real blocker for adopting Solid on a project with complex UI requirements. If your app depends on a rich data grid, a full-featured date/time picker, or an existing design system built for React, the Solid options are thinner.
Debugging reactive loops. When a circular dependency causes an infinite update cycle, the stack trace is harder to read than React’s equivalent. Solid’s reactivity is synchronous and stack-based, which means the error surfaces in framework internals rather than in your component code.
When I Would Choose SolidJs Over React
- New greenfield project with no React ecosystem dependencies. If you are starting fresh and the team is willing to learn the model, Solid is genuinely excellent.
- Performance-critical interfaces. Real-time data feeds, collaborative editing, complex animation-driven UIs, situations where React’s overhead is measurable in user experience.
- Bundle-sensitive environments. Sites where JavaScript payload directly affects conversions, or projects targeting low-end devices.
- When you want to understand reactivity properly. Solid forces you to think explicitly about reactivity in a way that makes you a better React developer too.
When I Would Stick With React
- Existing React codebase. The migration cost is high and the benefit rarely justifies it unless you have identified a specific performance problem.
- Large teams or agency projects. React’s hiring pool, onboarding material, and ecosystem breadth de-risk delivery timelines.
- Complex third-party UI requirements. If you need battle-tested data grids, rich text editors, or form libraries with deep React integrations, staying on React is the pragmatic call.
- Next.js features matter to you. Incremental Static Regeneration, the App Router caching model, and Vercel’s deployment integration are deeply React-native. SolidStart does not replicate all of that yet.
Final Thoughts
SolidJs in 2026 is production-ready, well-documented, and conceptually superior to React in several meaningful ways. The fine-grained reactivity model is not just a performance trick, it is a cleaner way to reason about UI state, and once you internalize the component-runs-once mental model, you start to see React’s re-render model as the workaround it arguably is.
But “conceptually superior” does not automatically mean “the right choice.” React 19 with the compiler has closed the performance gap considerably. React’s ecosystem advantage is enormous and compounding. For most teams on most projects, that ecosystem value outweighs the reactivity elegance.
Where Solid earns a clear recommendation is for performance-sensitive new projects, for developers who want to deeply understand reactivity, and for anyone building with tools like Astro where you can use SolidJs as an island without committing the entire project to it.
Use Solid when you need its performance characteristics or when you want to learn how reactive UI actually works. Use React when the ecosystem and team familiarity matter more than the model.
That is not a consolation prize for Solid. It is a strong case for the right context. And if you have not tried it yet, it is worth at least an afternoon, not to replace React, but to make you question which parts of React’s model you have been accepting out of habit.
Benchmark numbers are based on JS Framework Benchmark runs from Q1 2026. React figures use React 19 with the compiler enabled. Solid figures use SolidJs 1.9. Results vary by machine; the ratios are more informative than the absolute numbers.