SolidJS Core: The React-Shaped Framework That Disappears at Runtime
A deep dive into how Solid keeps JSX and components, swaps out the virtual DOM, and updates the real DOM through fine-grained reactivity.
- Solid preserves the JSX and component feel of React while removing the repeated component rerender cycle underneath it.
- Its real update engine is a fine-grained reactive graph that targets only the DOM nodes that depend on a change.
- Lists are the stress test that proves Solid is not just signals, because it still has to reconcile inserts, moves, and deletes with care.
- The repo is organized around runtime, compiler, store, and SSR pieces that all serve the same goal, which is to make rendering feel invisible.
Solid is easiest to understand as a trick of subtraction. It gives you JSX, components, and a familiar way to structure UI, then quietly removes the part most frameworks spend their time on: repeated tree rerenders and virtual DOM diffing.
That is why the project is so interesting. It does not ask you to learn a totally new syntax. It asks you to notice that the syntax you already know can be compiled into a very different execution model.
The Framework That Compiles Its Own Shadow
Solid’s core move is simple to say and hard to internalize. Components are setup functions, not rerender functions. They run once, establish subscriptions, and get out of the way while the reactive graph takes over.
Why Components Run Once
The implementation in `createComponent` is the giveaway. Solid executes the component under `untrack`, which means the component is used to wire up reactive dependencies, not to serve as the recurring unit of rendering.
function createComponent(Comp, props) {
return untrack(() => Comp(props));
}
const [count, setCount] = createSignal(0);
function Counter() {
return <button onClick={() => setCount(count() + 1)}>{count()}</button>;
}
That code is not doing the thing React developers expect. The `Counter` function does not rerun every time `count` changes. Instead, reading `count()` inside the JSX creates a dependency that points directly at the text node that needs to change.
This is the first mental shift Solid asks for. A component is not a repaint boundary. It is a subscription factory.
It’s the process of running the components on the client for the first time in the browser to get them set up for future updates. We don’t render anything but it generally follows the same top-down execution.
That quote captures the oddness well. Solid still feels top-down when you read the code, but the runtime effect is bottom-up precision.
Signals, Dependencies, and the Tiny Graph Underneath
The engine lives in the reactive core, where signals act as producers and computations act as consumers. When a signal is read, Solid records the current listener. When that signal changes, it marks the relevant observers stale, then reruns only what is needed.
The important detail is not that this is reactive. Lots of systems are reactive. The important detail is that the graph is fine-grained enough to route a single update to a single leaf node without waking up an entire component tree.
That is why Solid can feel almost invisible when it is doing its job. You notice the DOM update, not the framework logic around it.
The List Problem Is Where Frameworks Reveal Themselves
Lists force a framework to prove its claims. A button counter is easy. Inserts, deletes, and moves are where the update model stops being theoretical.
Solid’s `mapArray` logic and the `
| Question | React | Solid |
|---|---|---|
| What reruns? | The component function reruns. | Only the dependent computation reruns. |
| How updates flow | Through reconciliation and a virtual DOM. | Through direct subscriptions to DOM-relevant effects. |
| What tracks dependencies? | Hooks and rerender boundaries. | Signals and computations. |
| What is the runtime job? | Compare trees and patch the result. | Patch exact nodes that changed. |
| How lists behave? | Reconcile against a rendered tree. | Reuse and move only the affected items. |
This is where Solid stops looking like a niche performance experiment and starts looking like a serious rendering system. It can still handle the hard parts, but it does so with a different topology.
The Compiler Is the Secret Sauce
Solid’s Babel preset is what turns the idea into machinery. JSX is not just syntax sugar here. It becomes instructions that wire templates, signals, and insertions directly to the real DOM.
// Conceptual output, simplified
const _tmpl$ = template(`<button></button>`);
function Counter() {
const el = _tmpl$.cloneNode(true);
insert(el, count);
return el;
}
That is the hidden bargain. The compiler does more work up front so the runtime can do less forever after. The result is not merely a faster framework. It is a smaller runtime role for the framework itself.
A virtual DOM library asks JavaScript to keep comparing trees. Solid asks JavaScript to set up a graph once, then get out of the way.
Why Solid Looks Familiar to React Users and Still Isn’t React
| Framework | Execution model | Update mechanism | Mental model |
|---|---|---|---|
| Solid | Components run once | Fine-grained signals to DOM nodes | Setup code that builds subscriptions |
| React | Components rerun on state change | Virtual DOM diffing and reconciliation | Render as a repeatable calculation |
| Svelte | Compilation-first | Generated DOM operations | Compile away the framework work |
| Vue | Reactive primitives plus VDOM | Proxy-driven tracking and patching | Reactive state feeding a renderer |
| Angular | Signals plus framework orchestration | Change detection and signal-driven updates | Framework-managed application structure |
Solid sits in a useful middle ground. It gives React users a familiar surface, borrows the compiled feel of Svelte, and speaks the same reactive language that Angular and Vue now emphasize. But its core bet remains distinct: the renderer should disappear into the graph.
That distinction matters because it changes where complexity lives. In Solid, the hard part moves from rerender orchestration into dependency precision.
What the Repo Tells You About the Project’s Priorities
The repository layout makes the philosophy hard to miss. The core reactive engine, browser bindings, store layer, SSR package, and Babel preset are separate packages in one monorepo. That is not accidental modularity. It is a map of the system’s priorities.
The TypeScript-heavy core, the benchmarking focus, and the tight coupling between compiler and runtime all point to the same thesis. Solid is not trying to be a generic UI toolkit with a small fast path. It is trying to make a different rendering model feel ordinary.
That is the real story. Solid does not just optimize the familiar. It changes what the familiar is doing in the first place.





