SolidJSとQwikは、どちらもcomponentとJSXを使えるfrontend frameworkですが、解決しようとする中心課題が異なります。SolidJSはstateの依存関係を細かく追跡して必要な箇所を更新し、Qwikはserverで作った状態をserializeしてbrowserでresumeする設計を採ります。
比較の前提
記事情報: 2026年4月19日初出。SolidJSとQwikの公式資料を2026年7月25日に再確認しています。
この記事では条件不明のLighthouse値、bundle size、GitHub Stars、npm download数を優劣の根拠にしません。性能はapplication構成、SSR、hosting、network、third-party scriptによって変わります。
まず、2つの考え方を分けます。
- Fine-grained reactivity: どのstateをどの計算・DOMが読んだかを記録し、変更時に依存先だけを更新する
- Resumability: serverで得たcomponent境界、listener、stateをHTMLへserializeし、browserで同じ処理を最初から再実行せず再開する
SolidJSは主に更新時のreactivity、QwikはSSRからclientへ渡す起動モデルに特徴があります。「どちらが速いか」ではなく、どの段階のcostと制約を受け入れるかで判断します。

SolidJSのFine-grained Reactivity
SolidJSではcreateSignalがgetterとsetterを返します。tracking scope内でgetterを読むと依存関係が登録され、値が変わったときにsubscriberが再評価されます。
import { createMemo, createSignal } from "solid-js";
function Counter() {
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
return (
<section>
<p>count: {count()}</p>
<p>doubled: {doubled()}</p>
<button onClick={() => setCount((value) => value + 1)}>
increment
</button>
</section>
);
}
count()をJSX内で読む部分とcreateMemoがsubscriberになります。更新時にcomponent function全体を再実行することを基本にせず、依存する式・DOMを更新します。
Reactに似たJSXでも実行モデルが違う
Solid componentは基本的に初期化時に一度実行されます。component function内でsignalを通常の変数として読み出して保存すると、その値は自動では更新されません。
function Example() {
const [count, setCount] = createSignal(0);
const snapshot = count();
return (
<>
<p>snapshot: {snapshot}</p>
<p>reactive: {count()}</p>
<button onClick={() => setCount(count() + 1)}>update</button>
</>
);
}
React Hookの経験だけで同じmental modelを当てはめると、propsのdestructuringやsignalの読み取り位置でreactivityを失うことがあります。Solidのtracking scope、memo、effect、storeを理解する必要があります。
effectの役割
createEffectはsignalの変更を外部処理へ同期するときに使います。派生値を作るだけならcreateMemoや単純なderived functionを優先し、effect内で別stateを書き換える連鎖を増やさないほうが依存を追いやすくなります。
createEffect(() => {
document.title = `Count: ${count()}`;
});
SSR、routing、data loadingを含むapplicationではSolidStartなど周辺frameworkの仕様も確認します。Solid coreのreactivityだけでdeploymentやserver renderingが完結するわけではありません。
QwikのResumability
一般的なSSR applicationは、serverがHTMLを返した後、browser側でcomponent treeを再構築しevent listenerを結び直すhydrationを行います。Qwikはserver render時にcomponent境界、listener、application stateをHTMLへserializeし、必要になったcodeを後から読み込んで処理をresumeします。
import { component$, useSignal } from "@builder.io/qwik";
export default component$(() => {
const count = useSignal(0);
return (
<button onClick$={() => count.value++}>
count: {count.value}
</button>
);
});
component$やonClick$の$は、optimizerがlazy-load可能な境界を作るための手がかりです。通常のclosureをどこでも自由に渡すmodelとは異なり、codeとstateを分割・serializeできる形で書く必要があります。
Serializationの制約
Qwikのresumabilityでは、serverからbrowserへ引き継ぐstateをserializeできることが重要です。Date、URL、Map、Setなど対応する型はありますが、任意のclass instanceやstreamはそのままserializeできません。
browser専用libraryのinstanceなどにはnoSerialize()を使えます。ただし、その値はserverからclientへのserializationを越えて保持されず、client側で再初期化する必要があります。
import {
component$,
noSerialize,
useSignal,
useVisibleTask$,
type NoSerialize,
} from "@builder.io/qwik";
export default component$(() => {
const widget = useSignal<NoSerialize<{ destroy(): void }>>();
useVisibleTask$(() => {
widget.value = noSerialize(createBrowserWidget());
return () => widget.value?.destroy();
});
return <div id="widget" />;
});
useVisibleTask$はclientで実行されるため、増やしすぎるとresumabilityの利点を弱める可能性があります。browser-only APIが多いapplicationでは、どの処理をserverでserializeし、どれをclientで初期化するかを設計します。
更新モデルと起動モデルの違い
| 観点 | SolidJS | Qwik |
|---|---|---|
| 中心概念 | signal依存の細粒度更新 | server状態からのresume |
| state | getter/setterとtracking scope | signal/storeとserialize可能性 |
| event | 通常のhandler | $境界でlazy-load可能にする |
| SSR後 | 選んだrenderer/frameworkのhydration方式 | serialized情報からresume |
| 主な注意 | signalを読む場所とtracking | closure・stateのserialization |
両者にはsignalがあり、JSXも似ていますが、codeをそのまま移植できるとは限りません。Solidではreactive graphを正しく作ること、Qwikではlazy境界とserializationを保つことが重要です。
どちらを検討するか
SolidJSは、client側で更新頻度の高いUIを作り、signalによる明示的な依存追跡を採用したい場合に検討できます。表計算的なUI、dashboard、editorなどでも候補になりますが、実際のdata量で測定します。
Qwikは、SSRで初期HTMLを返し、最初に実行するJavaScriptを遅らせたいcontent中心・commerce系のapplicationで設計が合う可能性があります。一方、serializeできないbrowser objectを多数扱う高度なeditorやvisualizationでは、client専用初期化が増える影響を確認します。
既存のReactやVueを置き換える理由がなければ、移行しない判断も妥当です。component library、accessibility、test tool、monitoring、採用・学習cost、hosting adapterまで含めると、runtimeの特性だけで結論は出ません。
検証用の小さな課題
Todo appだけではarchitectureの差が見えにくいため、実際の要件に近い画面を1つ作ります。
- SSRした一覧とfilter UIを作る
- form送信とvalidation errorを実装する
- third-party browser libraryを1つ接続する
- route遷移とdata再取得を確認する
- slow networkで最初の操作を記録する
- build outputとsource map、error monitoringを確認する
Solidでは不要なeffectやreactivityを失った値がないか、Qwikではserialization warningや過剰なclient taskがないかをreviewします。Lighthouseの1回の点数ではなく、実機の複数回測定とuser interactionを確認してください。
Version表記への注意
この記事の旧版は「SolidJS 2.0 / Qwik 2.0」を前提にしていましたが、将来versionの機能を確定事項として扱うのは適切ではありません。導入時にはpackageのstable release、migration guide、使用するmetaframeworkとadapterの対応版を公式情報で確認してください。
architectureの考え方はversionを越えて役立ちますが、API名やrelease状態は変わります。本記事は特定の未公開major versionの予告ではなく、現在の公式documentで確認できる設計差を説明しています。
参考リソース
- SolidJS公式ドキュメント
- SolidJS: Intro to reactivity
- SolidJS: Fine-grained reactivity
- Qwik公式ドキュメント
- Qwik: Resumable
- Qwik: State