Rust Webフレームワークでフルスタックのアプリを組もうとすると、たいてい途中で編成の話になる。テンプレートエンジンは何にするか、フロントはwasmで動かすのか、静的ファイルの配信とキャッシュはどう組むか、TailwindのためにNodeを入れるのか。Topcoatは、その一式をあらかじめ決めて同梱してしまおうという方向のフレームワークだ。

Topcoattokio-rs/topcoat)は、Rustの非同期エコシステムの中心にあるtokio-rs organizationが公開している、MITライセンスのフルスタックWebフレームワークである。READMEの見出しは「The full full-stack framework for Rust」。2026年4月3日にリポジトリが作られ、2026年7月29日時点でGitHubスターは約3,636、最新版はv0.5.0だ。本記事では、この「全部入り」が実際に何を肩代わりするのか、そして最大の特徴である「wasmを配らずにブラウザを動かす仕組み」を、公式リポジトリとドキュメントの記述に沿って読み解く。

Topcoatのモジュール構成とURLの対応表。app.rsが/、app/about.rsが/about、_marketing.rsはURLセグメントを持たないレイアウト専用、app/posts/id.rsが/posts/{post_id}、app/api/health.rsがGET /api/healthに対応する
Topcoatのモジュールベースルーティング。ファイルシステムを走査するのではなく、Rustの mod 宣言をリンク時に集めてルート表を導出する(出典:module_router.md・2026-07-29 時点)
30秒でわかる Topcoat(2026年7月29日時点・v0.5.0)
  • 正体:tokio-rs が公開するMITライセンスのフルスタックRust Webフレームワークcrates/ 直下に17個のディレクトリを持つCargoワークスペースで、アプリが依存するのは topcoat という1つのファサードクレートだけ。
  • いちばんの特徴:マークアップはすべてサーバーで描画する。それでいて $(...) と書いた式はRustとして型チェックされたうえでJavaScriptにも翻訳され、ブラウザで再実行される。wasmバンドルもクライアント側のビルド工程も無い
  • 「全部入り」の中身view! テンプレート/モジュールベースのルーティング/内容ハッシュ付きアセット配信/Tailwind連携(Node不要)/編集可能なUIコンポーネント集/Cookie・セッション・メール。
  • 成熟度:READMEが「Early-stage and experimental. Expect breaking changes.」と明記。スター約3,636に対し crates.io の累計ダウンロードは2,148で、関心の大きさに実利用が追いついていない。
  • AI機能は無い:LLM連携やエージェント機能は一切含まない、純粋なWebアプリ用フレームワークである。

なお、当サイトで扱う開発者向けツール・自動化ツール全般のカバレッジは AI自動化ツール|ノーコードからコードまで2026年版の比較と選び方 にまとめている。

Topcoatとは——tokio-rs発の「全部入り」Rust Webフレームワーク

Topcoatを理解するうえでまず押さえたいのは、tokio-rs organizationの下にあるという事実だ。tokio-rsはRustの非同期ランタイムTokioを擁するorganizationで、Rustでサーバーを書く人間にとっては最も見慣れた名前のひとつである。そこから「Webアプリのフルスタックフレームワーク」が出てきた、という位置づけになる。

ただし、organizationの名前から受ける印象と、実際の開発体制は分けて見ておいたほうがいい。GitHub APIで取得したコントリビュータの内訳を見ると、参加者は16人だが、コミット数は pikaju(Julien Scholz)が790と圧倒的で、次点が10、Tokioの作者である carllerche は6にとどまる。つまり実態としては、tokio-rsという看板の下で、ほぼ1人の開発者が主導して書いているプロジェクトだ。これは品質の話ではなく、バス係数(担当者が抜けたときの継続性)とレビュー体制を見積もるうえでの前提である。

17クレートのワークスペースと、1つのファサード

リポジトリは crates/ 直下に17個のディレクトリを持つCargoワークスペースとして構成されている(後述のとおり手続きマクロを持つものは内部でさらに分かれるため、実際のワークスペースメンバー数はこれより多い)。ここで重要なのは、アプリケーション側が依存するのは topcoat というファサードクレート1つだけだという設計方針だ。リポジトリ同梱の開発者向け文書には、ファサードがすべてをfeature単位のモジュールとして再エクスポートしており、その下にあるクレートは「ファサード経由で到達する実装詳細」だと明記されている。

Topcoatの17クレート構成。core、view、router、runtime、asset、ui、cookie、session、mail、cliの各クレートが並ぶ
Topcoatのワークスペース構成。アプリが依存するのはファサードの topcoat クレートのみで、残りはfeatureで出し入れする(ほかに font / icon / tailwind / htmx / alpine-ajax / datastar)

手続きマクロを持つクレートは3点セットで構成される、という規約も明文化されている。ベースのクレートが生成コードの呼び出し先となる実行時の型を持ち、grammar/ クレートがマクロ本体をパースしてコードを生成し(コンパイル時のみ使用)、macro/ クレートが grammar/ への薄い入口になる。さらに、マクロ本体が整形可能なものについては grammar/pretty フィーチャがプリティプリンタを提供し、これが後述する topcoat fmt の実体になる。この「文法をライブラリとして切り出しておき、コンパイラとフォーマッタで共有する」構造は、独自マクロ構文を持つフレームワークとしては筋の良い作りだ。

もうひとつ、リポジトリの規約として明記されているのがunsafeの全面禁止である。開発者向け文書の末尾には、このプロジェクトは安全なコードのみを使い、unsafeは許可しないと1行で書かれている。MSRV(サポートする最小Rustバージョン)はcrates.ioのメタデータ上 1.95 に設定されている。

何を解決しようとしているのか

READMEの主張を機能に還元すると、Topcoatが引き受けようとしているのは大きく3つだ。第一に、サーバーとクライアントの間にAPIレイヤを立てる手間。コンポーネントが async 関数なので、データベースを直接引いてそのまま描画できる。第二に、クライアント側のビルドパイプライン。wasmもバンドラも使わないため、Rustのビルドだけで完結する。第三に、Webアプリに毎回必要になる周辺部品——静的アセットのハッシュ付与と配信、Webフォント、アイコン、Tailwind、UIコンポーネント、Cookie、セッション、メール送信。これらを個別に選定して繋ぐ作業を、フレームワーク側の既定として畳み込んでいる。

wasmなしで動く仕組み——ランタイム式とシグナル、そしてシャード

Topcoatで最も設計的に踏み込んでいるのが、クライアント側の対話性をどう実現するかという部分だ。ここは同時に、最も実験的な部分でもある。

前提として、Topcoatはマークアップをすべてサーバーで描画する。その上で、$(...) と書かれたブロックは「ランタイム式(runtime expression)」として特別扱いされる。公式ガイドの説明を要約すると、この式は通常のRustとして型チェックを受けたうえで二度コンパイルされる。一度目はサーバー側で、初期HTMLを生成するために評価される。二度目はJavaScriptへの翻訳で、等価なJavaScriptがページと一緒に配られ、ブラウザ側でもう一度実行できるようになる。

Topcoatのランタイム式の流れ。Rustで$(...)を書き、サーバーで1回評価して初期HTMLを生成し、JavaScriptへ翻訳してページに同梱し、ブラウザで再実行する。従来のRustフロントとの比較つき
ランタイム式が二重にコンパイルされる流れ。この「同じ式が両方の言語で同一に振る舞わなければならない」という制約が、そのまま式に使える語彙の制限になっている

ブラウザ側に持つ状態はシグナル(signal)と呼ばれ、view! の本体で signal 文として宣言し、ランタイム式の中から .get() で読む。イベントは @click のように @ 接頭辞の属性で、DOM属性へのバインドは :hidden のように : 接頭辞で書く。READMEに載っている開閉トグルの例では、ボタンのクリックで open シグナルを反転させ、段落の :hidden 属性がその値を見る、という書き方をしている。サーバーへの往復は発生しない

この方式が引き受けているトレードオフ

ここは記事として率直に書いておきたい部分だ。公式のランタイムガイドは冒頭で、このランタイムが 「highly experimental」であり、今日のところかなり限定的であると明言している。具体的には、式がサポートする型とメソッドの語彙が小さいこと、そして多くのパターンにまだ書きやすい答えが用意されていないこと、が挙げられている。将来のリリースで改善する見込みだが、追加と破壊的変更の両方を見込んでほしい、とも書かれている。

これは実装上の必然でもある。同じ式がRustとJavaScriptの両方で同一に振る舞うことを保証しなければならない以上、使える語彙は両言語で意味を揃えられる範囲に絞らざるを得ない。逃げ道として、手書きのJavaScriptへ抜ける raw! というエスケープハッチが用意されている。

サーバーに戻る必要があるとき——シャードとプロシージャ

検索結果の更新のように、どうしてもサーバー側の処理が要る場合のために、Topcoatは2つの仕組みを持つ。ひとつが #[shard]、もうひとつが #[procedure] だ。

#[shard] を付けたコンポーネントは、引数として渡されたランタイム式の値が変わるたびにサーバーで再描画され、新しいHTMLがその場で差し替えられる。READMEの検索の例では、入力欄の @input でシグナル query を更新し、search_results(query: $(query.get())) と渡すことで、ユーザーが打つたびにサーバー側のデータベース検索が走って結果部分だけが更新される。#[procedure] のほうは、ブラウザのランタイム式から呼び出せる非同期のサーバー関数である。

sequenceDiagram participant B as ブラウザ participant S as Topcoatサーバー participant D as データベース B->>B: @input で signal query を更新 Note over B: $(...) はJSとして
ブラウザ内で即再実行 B->>S: shard の引数が変化 → 再描画を要求 S->>D: コンポーネント内で直接クエリ D-->>S: 結果 S-->>B: 該当部分のHTMLだけ返す B->>B: 受け取ったHTMLを差し替え

整理すると、Topcoatの対話性は3段構えになっている。往復不要のものは $(...) とシグナルでブラウザ内に閉じる。サーバー側の描画が要るものは #[shard] で部分再描画する。任意のサーバー処理を呼びたいときは #[procedure] を使う。どの段でも書いているのはRustであり、別プロジェクトのフロントエンドを立てる必要はない。

モジュール構成がそのままURLになるルーティング

ルーティングは2通り書ける。Router::builder() にハンドラを手で登録していく明示的な方法と、Rustのモジュール構成からルート表を導出する方法だ。後者が module_router! マクロである。

記事冒頭の図に示したとおり、app.rs/ に対応し、app/about.rs/about になる。_ 始まりのモジュール(_marketing.rs)はURLセグメントを持たないレイアウト専用の階層として扱われ、その配下の pricing.rs/pricing として登録される。app/posts/id.rs/posts/{post_id} というパスパラメータ付きのルートに、app/api/health.rsGET /api/health というAPIルートになる。

ここで技術的に押さえておきたいのは、このマクロはファイルシステムを走査していないという点だ。公式ドキュメントは明確に「マクロはファイルシステムをスキャンしない。Rustが mod 宣言を通じて各ルートモジュールをコンパイルしなければならない」と書いている。つまり src/app/settings.rs を置いただけでは登録されず、app.rsmod settings; がある必要がある。仕組みとしてはリンク時の探索(link-time discovery)を使っており、discover フィーチャを必要とする(topcoat クレートでは既定で有効)。

この違いは実務上そこそこ効く。Next.jsのApp Routerのようなファイル規約型のルーティングと見た目は似ているが、Topcoat側はRustのモジュールツリーが正であり、ビルドステップを挟まない。ルートが増えたときにコンパイラが mod の欠落を教えてくれる一方、「ファイルを置けば勝手に生える」挙動を期待すると噛み合わない。

登録されるのは、module_router!() を呼んだモジュール配下にある、モジュール由来の #[page] / #[layout] / #[layer] / #[route] である。明示的なパス文字列を持つハンドラや、フォント、プロシージャ、シャード、アセットバンドル、アプリケーションコンテキストは、マクロが返すビルダー側に登録する。.discover() はリンク時に収集したものをまとめて追加するもので、登録は加算的なので module_router!() と組み合わせられる。

インストールと使い方——topcoat devで動かすまで

ここからは実際に打つコマンドの話に移る。公式のGetting startedが示す手順は、空のCargoバイナリプロジェクトから始めるという素朴なものだ。

cargo new hello-world
cd hello-world

cargo add topcoat
cargo add tokio --features rt-multi-thread,macros

注意点として、雛形を生成する topcoat new コマンドはロードマップ上まだ未実装である(READMEのRoadmapで未チェックのまま残っている)。したがって最初の1回は、上のように手でプロジェクトを組み立てることになる。「バッテリー同梱」を掲げるフレームワークとしては、ここは現時点で明確に手薄な部分だ。

src/main.rs を置き換えると、最小構成はこうなる。view! マクロの雰囲気がいちばん伝わるのがこの部分なので、構文そのものを見ておきたい。

use topcoat::{
    Result,
    router::{Router, RouterBuilderDiscoverExt, page},
    view::{component, view},
};

#[tokio::main]
async fn main() {
    topcoat::start(Router::builder().discover().build()).await.unwrap();
}

#[page("/")]
async fn home() -> Result {
    view! {
        <!DOCTYPE html>
        <html>
            <body>
                hello(name: "World")
            </body>
        </html>
    }
}

#[component]
async fn hello(name: &str) -> Result {
    view! { <h1>"Hello, " (name) "!"</h1> }
}

読み方のポイントは3つある。第一に、文字列リテラルは明示的にクォートする"Hello, ")。第二に、丸括弧が値の埋め込みを意味する((name))。第三に、コンポーネントの呼び出しが hello(name: "World") という名前付き引数の形で、HTMLタグと同じ階層に書ける。テンプレートとしてはHTMLに寄せつつ、Rustの式と制御構文をそのまま持ち込める設計になっている。

制御構文まわりでは、for ループや if をテンプレート内に直接書ける。特徴的なのは if属性の集合に対しても使えることで、READMEのナビゲーション例では、現在のパスと一致するリンクにだけ aria-current="page"class="active" をまとめて付与している。

cargo run だけでも既定で http://127.0.0.1:3000 に配信されるが、日常的な開発ではCLIを使う。

cargo install topcoat-cli
topcoat dev

topcoat dev はアプリのビルド、アセットのバンドル、サーバー起動をまとめて行い、ソースディレクトリを監視して変更のたびに再ビルド・再バンドル・再起動する。ページに topcoat::dev::script() を含めておけば、新しいビルドが通った時点で自動リロードされる。ターミナルで r を押せば手動での再ビルドも可能だ。CLIは単一の topcoat 実行ファイルとしてインストールされ、cargo topcoat ... というCargoサブコマンドとしても呼べる。

Topcoatの導入4ステップ。cargo new、cargo add topcoat、cargo install topcoat-cli、topcoat devの順に実行する
空のCargoプロジェクトから開発サーバーが立つまで。雛形生成コマンド topcoat new はロードマップ上まだ未実装のため、最初の1回は手で組む

もうひとつ覚えておきたいCLIサブコマンドが topcoat fmt だ。view! のような独自マクロの本体は通常の rustfmt では整形されないが、topcoat fmt はマクロ本体を rustfmt と併せて整形する。前述の grammar/ クレートのプリティプリンタがこの実体である。独自構文を持つフレームワークで整形手段が最初から用意されているのは、チーム開発では地味に効く。

「全部入り」の中身——UIコンポーネント・アセット・リクエスト設計

「batteries-included」という表現が具体的に何を指すのかを、機能単位で見ていく。

自分で組む場合とTopcoatに含まれるものの比較。テンプレートエンジン選定、静的ファイルのハッシュ付与、Webフォント、Tailwind用のNode、UIコンポーネント、Cookieの署名がTopcoat側で提供される
「全部入り」が肩代わりする範囲。UIコンポーネントはライブラリとして隠すのではなく、ソースをプロジェクトへコピーして編集させる方針を採る

Topcoat UI——ソースごと取り込んで編集する

Topcoat UIは、Tailwindベースのコンポーネント集である。公式ドキュメントは、shadcn/uiに影響を受けたと明示している。特徴は配布方式で、不透明なライブラリ依存として消費するのではなく、topcoat ui add がコンポーネントのソースをプロジェクトへ直接コピーする。コピーされた後は自分のコードなので、デザインも挙動も自由に書き換えられる。

topcoat ui init
topcoat ui add button
topcoat ui list

topcoat ui init は2つのことをする。パッケージ直下に components.toml(どのコンポーネントを、どのレジストリから、どのバージョンで入れたかを記録する導入状態のファイル。バージョン管理にコミットする)を作り、テーマのCSSを styles.css として書き出す。コンポーネントの既定の導入先は src/components で、--components-dir で変更できる。ワークスペースでは --package <name> で対象パッケージを選ぶ。

topcoat ui add は名前を指定してコンポーネントを追加する。このときソースを src/components/button.rs のようにコピーするだけでなく、モジュール宣言まで面倒を見る——src/components.rs(あるいは src/components/mod.rs)に pub mod button; の行を追加する。両方のファイルが存在する場合は推測せずエラーにする、と明記されている点が律儀だ。依存する他のコンポーネントがあれば併せて導入し、components.toml に記録する。何が用意されているかは topcoat ui list で一覧でき、--installed を付けると導入済みのものに絞られる。

各コンポーネントは普通の #[component] 関数で、view! の上にTailwindのユーティリティクラスで組まれている。参照するテーマトークンは topcoat ui init が入れるスタイルシートが定義する。なお、この styles.css がTailwindの入力ファイルになり、@import "tailwindcss"@sourcesrc/**/*.rs を走査してクラスを収集する指定)を含む。

Tailwind——Nodeを立てずに使う

Tailwindまわりは、tailwind フィーチャを有効にすると使える。実装としてはTailwindが配布しているスタンドアロンCLIをbuild.rsから叩くビルドスクリプトのラッパーで、生成されたCSSはTopcoatのアセットとして配信される。Node.jsのツールチェーンを別途用意しなくてよいのは、Rust一本で完結させたい構成では素直に利点になる。

アセット・フォント・アイコン

アセットの扱いは、asset! マクロで宣言する方式だ。バンドラはコンパイル済みバイナリを走査して asset! の呼び出しを見つけ、対象ファイルをローカルのアセットディレクトリへコピー(場合によってはダウンロード)し、内容ハッシュ付きのURLで強いキャッシュを効かせながら配信する。「ソースツリーを走査する」のではなく「コンパイル済みバイナリを走査する」という点が、前述のルーティングと同じくリンク時収集の思想で揃っている。

同じ仕組みの上に、Webフォント(font! / font_face!、Fontsource=Google Fonts連携)とアイコン(Iconifyのアイコンセットをビルド時に取り込む)が乗る。ほかに、mail! マクロでメールを宣言し、SMTP・ファイル・インメモリの各トランスポートで送る仕組みも同梱されている。

「ミドルウェアではなく関数」というリクエスト設計

設計思想として明文化されているものに、functions_not_middlewares というドキュメントがある。要旨はこうだ。他のフレームワークから来た開発者は、認証などのガードをミドルウェアやエクストラクタで書きがちだが、Topcoatでは cx: &Cx を取る短い合成可能な関数を推奨する。

理由として挙げられているのが、ミドルウェア方式は認証を「それを必要とするコードから引き離す」という点だ。ミドルウェアがリクエストを認証してユーザーをどこかへ格納し、ページ側は「ミドルウェアが既に走ったはず」と仮定して取り出す。この構造だと、ミドルウェアが無い、あるいは順序が違うだけでハンドラがパニックしうるし、保護対象のルートをミドルウェア無しで追加すればデータが露出しうる。エクストラクタはハンドラのシグネチャに要件が現れる分ミドルウェアより堅いが、今度は配下のコンポーネント全部にユーザーを明示的に渡して回る羽目になる、という整理だ。

代わりに使うのが、リクエストコンテキスト Cx を受け取る普通の関数と、#[memoize] である。#[memoize] は引数をキーにしてリクエスト内で結果をキャッシュし、同じ処理の重複呼び出しを畳み込む。コンポーネントツリーのどこからでも認証関数を呼んでよく、実際のコストは1回分に収まる、という設計になっている。長寿命の値(DBプール、HTTPクライアント、起動時に読む設定)はアプリコンテキストとして .app_context(value) でルータに登録し、app_context::<T>(cx) で型をキーに引く。同じ型を2つ登録するとパニックするため、必要ならニュータイプで包む。

Cookieは署名付き・暗号化・プレフィックス付きに対応し、セッションはストレージ持ち込み方式(トークンとハッシュのモデル、ログイン/ログアウトのライフサイクル、スライディング有効期限、トークンローテーション)で提供される。クライアントライブラリとの連携としては、htmx、Alpine AJAX、Datastarのためのリクエスト/レスポンスヘッダのヘルパーが用意されている。

Leptos・Next.jsとの設計比較——Rust Webフレームワークの選択肢と同梱ベンチの読み方

Rustでフルスタックを組む選択肢としては、wasmでブラウザ側もRustを動かすLeptosが既に定着している。また、Topcoat自身がリポジトリ内で比較対象に据えているのがNext.jsと、フレームワーク層を挟まない手書きベースラインとしてのAxum + Maudだ。設計上の違いを整理すると次のようになる。

観点 Topcoat Leptos Next.js (App Router) Axum + Maud
言語 Rust Rust TypeScript / JavaScript Rust
マークアップ描画 すべてサーバー サーバー+wasmハイドレーション(islandsモードあり) サーバー+RSC すべてサーバー
クライアントへ配るもの 翻訳されたJavaScript(wasmなし) wasmローダー+wasm RSCペイロード+スクリプト 何も配らない
クライアント側ビルド工程 不要 必要(cargo leptos / wasmターゲット) 必要(next build 不要
対話性の書き方 $(...) 式・シグナル・#[shard] Rustのシグナル(wasm上で実行) Reactのクライアントコンポーネント 自前(フレームワーク層なし)
ルーティング モジュール構成から導出/明示登録 ルータコンポーネント ファイルシステム規約 axumのルータに手で登録
UIコンポーネント同梱 あり(ソースをコピーして編集) なし(サードパーティ) なし(サードパーティ) なし
Tailwind 同梱(Node不要・スタンドアロンCLI) 別途(cargo-leptos経由等) Node前提 別途
成熟度 v0.5.0・実験的と明記 0.8系 安定・エコシステム最大 ライブラリ組合せ次第

比較表のうちLeptosとNext.jsの挙動については、Topcoat側のベンチマーク文書における記述(Leptosはislandsモードで動かしており対話的なislandが無いためwasmローダーのみを配る、Next.jsはRSCペイロードとスクリプトタグを埋め込む)に基づくTopcoat側の説明であることを付記しておく。

同梱ベンチマークは「測り方」であって「測った結果」ではない

ここは誤解されやすいので明確にしておきたい。リポジトリの benchmarks/ には、同一の店舗アプリを4回実装したものtopcoat/ nextjs/ leptos/ axum-maud/)と、計測ハーネスが入っている。しかし性能の数値は公開されていない。結果の出力先である results/benchmarks/.gitignore でGitの管理外にされており、READMEにも数値表は無い。したがって「TopcoatはNext.jsより何倍速い」といった話は、2026年7月29日時点の公開情報からは導けない。数値が欲しければ、oha・pnpm・cargo-leptos・wasmターゲットを揃えて自分で回す必要がある。

とはいえ、公開されている「測り方」のほうは、公開3か月あまりのプロジェクトとしてはかなり厳格だ。4実装は同一のコンポーネントツリー(ナビ、フッター、商品カード、評価の星、ページネーション、仕様表、レビュー一覧、パンくず)を同一のTailwindユーティリティクラスで描画し、同一のデータセット(500件のシード済み商品)を読み、ページのクランプや4種のソート順、カテゴリ絞り込みといったクエリ意味論と、価格・評価の整数演算やISO日付の扱いといった整形規則まで揃えている。それを担保するのが verify_parity.sh で、4フレームワークで5つのルートを描画し、HTMLを可視テキストへ還元して差分を取る。

フェアネスに関する断り書きも具体的だ。圧縮は全サーバーで無効にしている(理由として「これらのサーバーはどんなコーデックが圧縮するより速くページを描画するので、圧縮を有効にすると比較の大半がコーデックの計測になる」と説明し、同時に「実運用では圧縮は有効にすべき」とも書いている)。レスポンスサイズが異なるのは意図的で、それぞれの本番出力の実態だとして bytes/resp 列で可視化する。Next.js側は全ページに export const dynamic = "force-dynamic" を置き、本当に毎リクエスト・サーバー描画していることを verify_parity.sh で表明させる。既定ではRust側が全コアを使う一方 next start は単一Nodeプロセスなので、1コア同士で比べたい場合は SINGLE_THREAD=1TOKIO_WORKER_THREADS=1 に揃える。負荷生成器がサーバーと同居しているため絶対値は悲観的で、意味があるのは相対比較だけだ、とも明記されている。

これは「サーバー描画のベンチマークであってブラウザのベンチマークではない」とも書かれている。測っているのは完全なHTML文書が返るまでの時間であり、対話可能になるまでの時間ではない。読み手として押さえるべきはこの線引きで、Topcoatの主張(wasmを配らない・JSが小さい)が実際のユーザー体験にどう効くかは、この計測の外側にある。

導入判断——成熟度・開発体制・リポジトリ同梱のドキュメント

最後に、採用可否を考えるための材料を数字で並べる。

Topcoatの成熟度指標。GitHubスター3636に対しcrates.io累計ダウンロード2148、コントリビュータ16人のうち1人が790コミット、最新v0.5.0、MSRV Rust 1.95、MIT、fork 109
2026年7月29日時点の実測値。関心(スター)と実利用(ダウンロード)の乖離が、このプロジェクトの現在地をいちばん端的に示している

GitHubスターは約3,636、forkは109。一方でcrates.ioの累計ダウンロードは2,148にとどまる。バージョン別に見ると、最も多いv0.4.0が1,129、次いでv0.1.3が218、v0.3.0が212、v0.3.1が154、最新のv0.5.0は135である。ここで注意したいのは、crates.ioの「直近90日ダウンロード」が2,137とほぼ累計と一致している点だが、これは勢いを示す数字ではない。実質的な公開が2026年7月15日に始まったばかりで、全期間が90日の窓に収まっているだけである。読み方としては、関心は明確に集まっているが、実利用はこれから、が妥当だ。

リリースの状況も見ておきたい。GitHub上のリリースは1件(v0.5.0、2026-07-27)、タグはv0.4.0とv0.5.0の2本のみ。一方でコミットは活発で、2026年7月28日だけでもルーティングのシグネチャ検証、リクエストボディの上限追加(破壊的変更を示す ! 付き)、ドキュメント整備などが入っている。動きは速く、同時に破壊的変更も入る局面である。

READMEは「Early-stage and experimental. Expect breaking changes.」と明記し、ランタイムのガイドはさらに強く「highly experimental」と書いている。ロードマップには topcoat new、静的エクスポート、さらなるリアクティビティ、UIコンポーネントの拡充、同じくtokio-rsのORMであるToastyとの連携改善がすべて未チェックで並ぶ。したがって現時点の妥当な使い方は、社内ツールや個人プロジェクトでの評価・試作である。長期運用が前提のプロダクトに入れるなら、破壊的変更への追随コストを織り込む必要がある。

なお、Rustエコシステムの周辺ツールという意味では、データ処理側でPolars入門:pandasの10倍速でデータ処理できるRust製DataFrameライブラリ、デスクトップ側でMD Preview解説|Electron不要・Rust製のローカルMarkdownプレビューアも併せて参考になる。作ったアプリをどこに載せるかという観点では、Openshipとは:セルフホストできるOSSデプロイ基盤(PaaS)をコードと実機で検証【2026】が選択肢の整理に使える。

リポジトリがコーディングエージェント向けの文書を同梱している

最後にひとつ、リポジトリ構成として目を引く点を事実として記録しておく。Topcoatのルートには AGENTS.md が置かれ、CLAUDE.md はそこへのシンボリックリンク(中身は ./AGENTS.md)になっている。同様に .claude.agents へのシンボリックリンクで、.agents/skills/ の下には check commit macro pr prose style という6つのディレクトリが並ぶ。

AGENTS.md の中身は、ワークスペースの構成、各クレートの責務、手続きマクロの3点セット規約、機能領域ごとのドキュメント索引、そしてunsafe禁止のポリシーで構成されている。これはフレームワークの機能ではなく、このリポジトリを開発する際の作業手引きである。同じ内容を人間の新規コントリビュータが読んでも有用な、事実上のアーキテクチャ解説になっている点は、外から仕様を把握したい読者にとっても実利がある。

これはあくまで「開発の進め方としてエージェント向けの指示書を整備している」という、リポジトリ運営側の観察にとどまる。Topcoatが提供するのはWebアプリケーションを組むための機能だけである。

参照ソース

tokio-rs/topcoat — GitHub リポジトリ(README・Roadmap・ライセンス)
Getting started — 公式ドキュメント(プロジェクト作成・CLI導入・dev サーバー)
module_router.md — モジュールベースルーティングの公式ドキュメント
ui.md — Topcoat UI の公式ドキュメント(topcoat ui init / add)
functions_not_middlewares.md — 「ミドルウェアではなく関数」の設計方針
benchmarks/README.md — ベンチマークハーネスの計測方法とフェアネス注記
topcoat — crates.io(バージョン別ダウンロード数・MSRV)