NOTICE: I've summarized the perspectives of Octane's and Solid's creators here, for anyone short on time: https://gist.github.com/aleclarson/829c10aa7d287944ef75e1c2a90bef06
I'm a React/Preact/Astro developer with an interest in other renderers. The two that have most caught my eye recently are Octane (from Dominic Gannaway of React Hooks / Svelte / Inferno fame) and Solid 2.
I asked ChatGPT to compare them with its own "Renderer DX Pillars", which I've shared below. This is its gut instinct, with very little hedging:
| Pillar | Winner | Why |
|---|---|---|
| State architecture freedom | Solid 2 | Reactivity is independent of components. Much less component gravity. |
| Reactive reasoning | Solid 2 | The dependency graph is explicit and causal. Easier to answer “why did this update?” |
| Derived state & synchronization | Solid 2 | Fine-grained derivation is the native model; less need to coordinate state manually. |
| Async/data flow | Solid 2 | This is basically Solid 2's flagship idea. Async being part of reactivity feels deeper than improving Suspense/hooks ergonomics. |
| Component authoring | Octane | Normal values, normal functions, familiar TSX, fewer Solid-specific semantic gotchas. |
| Escape hatches | Solid 2, narrowly | Solid's primitives compose very directly with imperative JS without pretending everything is a component concern. |
| Ecosystem interoperability | Octane | If its React-ecosystem compatibility ambitions work, this could be a huge advantage. |
| Tooling & debuggability | Solid 2 today | More mature and battle-tested. Octane's compiler creates more invisible machinery that tooling has to explain well. |
| Architectural scaling | Solid 2 | Its reactive model naturally lets domain/application architecture exist independently of rendering. |
So my gut scoreboard is:
Solid 2: 7 Octane: 2
But the two Octane wins are meaningful ones.
Its pitch seems particularly strong around:
“I want React's authoring experience without React's runtime/design baggage.”
You get something like:
function Counter() {
const [count, setCount] = useState(0);
const doubled = count * 2;
return <button onClick={() => setCount(count + 1)}>
{doubled}
</button>;
}That's extremely approachable.
Solid asks you to internalize:
const [count, setCount] = createSignal(0);
const doubled = () => count() * 2;which isn't hard, but it is a different programming model.
So for day-one DX, I wouldn't be surprised if Octane feels better.
Solid's advantages seem to accumulate as the application becomes less like:
some components with state
and more like:
a complex reactive application that happens to have a UI.
That's where signals outside components, ownership, fine-grained derivation, async graph semantics, stores, and independent domain state all start reinforcing each other.
My gut says the trajectory looks something like:
small app
Octane ██████████
Solid █████████
↓ complexity
large/stateful app
Octane ████████
Solid ████████████
Not because Octane necessarily scales poorly, but because Solid's abstraction seems closer to the actual problem being modeled once state relationships get complicated.
Escape hatches.
Octane could easily end up winning there if its compiler makes effects, refs, subscriptions and integration code extraordinarily pleasant.
And ecosystem interoperability could become an overwhelming Octane win if their compatibility layer is genuinely broad and reliable rather than “we have adapters for the popular demos.”
If I had to assign confidence rather than points:
- Solid strongly wins: state architecture, derived state, async, architectural scaling.
- Solid probably wins: reactive reasoning, escape hatches.
- Octane strongly wins: initial component authoring.
- Octane probably wins: ecosystem interoperability.
- Solid wins for now: tooling/maturity.
The biggest question I'd personally want answered before choosing between them is therefore not performance.
It's:
Does Octane's compiler actually eliminate the architectural drawbacks of component-centric reactivity, or does it mostly make that model much nicer to write?
If it's the latter, I'd expect Solid 2 to remain the stronger foundation for complex applications.
Yeah, fair correction on the timeline. I was referring to the async work and discussions around Svelte, not claiming Solid’s colourless design came from me. I worded that badly, but I think you know what I meant anyway – actually you definitely do, we spoke about this on our podcast or Discord etc.
I also understand what you mean about every reactive read having the same contract. Being able to replace a synchronous source with an async one without rewriting everything downstream is valuable. I’m not suggesting you should put
Promise<T>everywhere and bring that problem back. TBH my design for Svelte was not this, Rich changed it around originally, I literally pitched the same idea you had with$derivedor I think at the time when I was on Svelte team it was$async. It was like a year ago now, who knows.The distinction I was trying to get at is slightly different though. In ordinary JS,
const value = readValue()gives me a value from that execution. A getter or a tracked derivation preserves a different relationship. Moving a read, passing its result instead of the getter, or calling it outside the right tracking scope can change the behaviour. The runtime might know exactly what happened, but that doesn't mean the distinction is obvious from the code or its value types. Async adds another question about where a read can prevent execution from continuing. I still think theres a real trade-off there, even when the reactive graph handles it correctly.In the React "shaped" component model, the default is that calculations inside render run again.
const total = price * quantitystays ordinary code. You then remove unnecessary work through memoisation, whether written manually or performed by the compiler. That doesn't make React free of snapshots or stale closures, obviously. But it is a different starting contract, and one I think is worth keeping.You're right that I was too loose with the point about the compiler knowing. I don't mean it can see through arbitrary JS or predict every runtime branch. I mean we can define a language with stronger rules, establish more from those rules, and keep runtime behaviour or reject a pattern where the analysis ends. I want those semantics to be specified, rather than depending on whatever an optimisation happened to manage.
The Rust comparison is actually quite close to what I meant with
"use strong". Yes, it asks people to learn some new rules. I don't think that makes their React knowledge stop transferring, though. Components, props, state, composition, and a lot of existing application structure still make sense. Strong mode is opt-in today, and ordinary code and dependencies can keep their existing behaviour. Familiarity can be useful without being a promise to preserve every habit forever. TBH it doesn't really matter at all to agents, as asking them to adhere to new rules is hardly going to cause anyone to complain, and that goes back to my point in the prior comment.You’re right about debugging, to some extent (unless I have got you wrong). If an agent is looking at a broken app, it needs evidence from what actually ran, a compiler error only gets you so far. Octane already exposes source-linked render causes, hook state, and transition/Suspense state, but it doesn’t yet give you the same view of causality as your graph. The missing part is connecting the compiler’s choices to what you can inspect at runtime. I think we can do that without making a fine-grained graph the model for everything. Plus we already have
octane-doctor, devtools support is on the way. However, in real world practice, I think this area is going to be completely changed as agents become even more capable. I've already had a big issue debugged in realtime, in the compiled output of Octane debugged by an agent insertingconsole.logand it working, it fixed it. It didn't care for the compiled output being completely different from the user-code, it just worked great – thank you Codex and ChatGPT 5.6 Sol, which gets Octane so well in a very large codebase.I suspect we agree on more than the earlier comments suggested. Agents make a new model easier to pick up, but they also make vague semantics easier to paper over, which isn’t good. Octane still has to prove that its extra constraints are worth it – which it will, I'm confident of that. The only useful answer to that is going to be in the implementation, not another round of analogies. Using
tsrxhas yielded so many benefits you wouldn't believe too, I can't really get into those details just yet, but believe me it's been transformative.My push back is mostly – Solid 2.0 has been an exceptional launch, but don't use that as a reason to denounce Octane. I've got a strong hunch, a spider-sense almost that that I'm onto something equally as special Solid 2.0, except Octane might actually be the next big-thing (fucking finally). So that's why I never rained down on your celebration, because Solid is epic – you know me personally and I love your work Ryan. I never went on any of your threads on X, Reddit or whatever telling people to use Octane over Solid. So don't take what I say personally, we're just learning from one another, and that's healthy.