「Go で API を作る。Echo と Gin、どっち?」——Go を始めると必ずぶつかる問いです。ネット上の比較記事の多くはベンチマークの数字で勝敗を付けますが、それは実務ではほぼ意味がありません。実アプリのボトルネックはルーターではなく DB と外部 I/Oだからです。
この記事は、Go Echo 本番運用ガイドの選定編です。性能以外の本当に効く違い——エラー処理の思想、ミドルウェアの一貫性、エコシステムの成熟度——を公平に比較し、「あなたのプロジェクトでどれを選ぶべきか」を軸で答えます。Echo に肩入れせず、Gin が向く場面も明記します。
この記事のルール:各フレームワークの事実は 公式ドキュメント / リポジトリ(2026年6月時点。Echo v5・Gin v1.12 系) に基づきます。バージョンは進むため、採用前に各公式で最新を確認してください。
1. まず性能の話を片付ける:ここは決め手にならない
率直に言います。Echo と Gin の性能差は、実アプリでは観測できません。
- Echo・Gin はともに radix-tree(基数木)ベースのルーターで、パラメータ付きルートでもゼロアロケーション級。GitHub API 相当の全ルートを約10マイクロ秒で解決します。
- この差(数マイクロ秒)は、1回の DB クエリ(数ミリ秒=1000倍以上)や外部 API 呼び出しに完全に埋もれます。
つまり「どちらが速いか」でフレームワークを選ぶのは、家を選ぶのに玄関マットの厚さで決めるようなものです。性能が本当に最優先なら検討対象は Fiber(fasthttp)ですが、それには後述の大きな代償があります。性能はこの比較から外し、設計と運用の軸で見ます。
2. 最大の違い:エラー処理の思想
ここが Echo と Gin を分ける、最も実務的な差です。
Echo:handler が error を返し、集中ハンドラで一元処理
// Echo:エラーは return するだけ。変換は集中 HTTPErrorHandler に集約
func getUser(c *echo.Context) error {
user, err := repo.Find(c.Request().Context(), c.Param("id"))
if err != nil {
return err // ← 1箇所の HTTPErrorHandler が HTTP に変換・ログ・通知
}
return c.JSON(http.StatusOK, user)
}
Gin:handler は error を返さず、その場でレスポンスを書く
// Gin:各ハンドラで c.JSON / c.AbortWithStatusJSON を書く(中央集権の標準なし)
func getUser(c *gin.Context) {
user, err := repo.Find(c.Request.Context(), c.Param("id"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) // 都度
return
}
c.JSON(http.StatusOK, user)
}
Gin にも c.Error() でエラーを蓄積する仕組みはありますが、「return すれば集中ハンドラが整形する」という Echo の規約のような標準形が無く、エラー処理が各ハンドラに散らばりがちです。エラー処理・ログ・機微情報の遮断を一箇所に集約したいなら Echo、素朴に都度書くのが好みなら Gin。これは優劣ではなく思想の違いで、集中エラー設計を重視する私は Echo を好みます。
3. 各軸の比較表
| 軸 | Echo v5 | Gin v1.12 | 標準 net/http(Go 1.22+) |
|---|---|---|---|
| 基盤 | net/http | net/http | — |
| ルーター | radix tree(静→param→*) | radix tree(httprouter 系) | パターンマッチ(メソッド対応) |
| ハンドラ署名 | func(c *echo.Context) error | func(c *gin.Context) | func(w, r) |
| エラー処理 | 集中 HTTPErrorHandler | 各所で c.JSON/c.Error | 自前 |
| ミドルウェア | 内蔵が充実・API 一貫 | 内蔵 + 三者が最多 | 自前(http.Handler) |
| バインド/検証 | c.Bind+Validator 差込 | ShouldBindJSON+validator 内蔵 | 自前 |
| ロギング | log/slog 標準(v5) | 独自 + 三者 | 自前 |
| 成熟度・事例 | 多い | 最多(スター・採用数) | 標準=無限 |
| 学習コスト | 低〜中 | 低 | 中(手書き多い) |
ざっくり言うと——Gin は「最も成熟・最大エコシステム」、Echo は「APIが一貫・内蔵が充実・v5 で近代化(slog/ジェネリクス/StartConfig)」、net/http は「依存ゼロ」。
4. ミドルウェアとエコシステム:Gin の強み
公平に書きます。サードパーティ・ミドルウェアの数と情報量は Gin が最大です。CORS・レート制限・キャッシュ・認証など、よくある課題の「枯れた解」が見つかりやすく、採用事例も最多。チームに Gin 経験者が多いなら、その慣れは性能差より遥かに価値があります。
一方 Echo は、CORS・CSRF・Secure・RateLimiter・RequestLogger などをフレームワーク内蔵で持ち、設定構造体(XxxWithConfig)の作法が全ミドルウェアで一貫しています。三者依存を増やさずに本番要件を満たしやすいのが Echo の強みです(ミドルウェア完全ガイド)。
判断軸:**「枯れた三者解と最大の事例」が欲しいなら Gin。「内蔵で一貫、依存を絞る」**なら Echo。
5. Fiber と net/http という選択肢
- Fiber:
fasthttp上に作られ、生のスループットは最速級。ただし**net/http非互換**——context.Contextの流儀やhttp.Handler資産、標準ミドルウェアがそのまま使えません。Go の標準エコシステムから外れる代償は、長期保守では重くのしかかります。極限の生スループットが要件で、その代償を受け入れられる場合のみ。 - 標準 net/http(Go 1.22+):強化された
ServeMuxがメソッド付きパターン(GET /users/{id})に対応し、小〜中規模ならフレームワークなしで十分になりました。依存を増やしたくない・ライブラリの寿命に縛られたくないなら、まず標準で組めないか検討する価値があります。
// Go 1.22+ の標準 net/http(依存ゼロ)
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
// ...
})
ただし、エラー集約・バインド・検証・豊富なミドルウェアを自前で書くコストは残ります。それが増えてきたら Echo/Gin の出番です。
6. 移行:Gin ↔ Echo は段階的にできる
「Gin で始めたが Echo に寄せたい(逆も)」は現実的に可能です。両者とも net/http 互換なので、http.Handler 境界で共存させながら段階移行できます。
移行時に書き換わる主なポイント:
| 項目 | Gin | Echo v5 |
|---|---|---|
| ハンドラ | func(c *gin.Context) | func(c *echo.Context) error |
| ルート | r.GET("/u/:id", h) | e.GET("/u/:id", h) |
| パラメータ | c.Param("id") | c.Param("id") |
| JSON 応答 | c.JSON(200, obj) | return c.JSON(200, obj) |
| バインド | c.ShouldBindJSON(&x) | c.Bind(&x) |
| エラー | 各所で c.JSON | return err(集中ハンドラ) |
| グループ | r.Group("/api") | e.Group("/api") |
最大の作業は**「都度レスポンスを書く Gin 流」から「error を return する Echo 流」への発想転換**です。逆方向(Echo→Gin)では、集中エラーハンドラの責務を各ハンドラ or 共通ミドルウェアに散らす必要があります。いずれもクリーンアーキテクチャで Controller を薄く保っていれば、影響範囲は Controller 層に局所化できます——これが層分割の実利です。
7. 選定フレームワーク:あなたはどれを選ぶべきか
依存をほぼ増やしたくない / 小〜中規模 / ライブラリ寿命に縛られたくない
└─→ 標準 net/http(Go 1.22+)。足りなくなったら Echo/Gin へ
最大の事例・三者ミドルウェア・チームが Gin 慣れ
└─→ Gin
集中エラー処理 / 内蔵ミドルウェアの一貫性 / 依存を絞る / v5 の近代化(slog)
└─→ Echo
生スループットが最優先 & net/http 非互換を許容できる
└─→ Fiber(少数派の選択。代償を理解した上で)
正直な結論:REST/JSON の業務 API を本番品質で素早く作るなら、Echo と Gin はどちらも正解です。性能で迷う必要はありません。決め手は「エラー処理の思想(集中 vs 都度)」「チームの慣れ」「既存資産」。私自身は、集中エラー処理と内蔵ミドルウェアの一貫性、v5 での近代化を評価して Echo を採用していますが、これは思想の選択です。
まとめ:フレームワーク選定の7原則
- 性能で選ばない。Echo/Gin の差は実アプリで観測不能。ボトルネックは DB と I/O。
- 最大の違いはエラー処理。集中(Echo)か都度(Gin)か、思想で選ぶ。
- エコシステム最大は Gin、内蔵の一貫性は Echo。
- 依存を絞るなら Go 1.22+ の net/http をまず検討。
- Fiber は net/http 非互換が代償。生スループット最優先のときだけ。
- チームの慣れ・既存資産は性能差より重い判断材料。
- 移行は両者 net/http 互換で段階的に可能。Controller を薄く保てば影響は局所化。
技術選定に「唯一の正解」はありません。あるのは「あなたの制約に対する最適解」です。選定やアーキテクチャの相談は、B2B SaaS のアーキテクチャ設計やレガシー産業の技術選定フレームワークの考え方も合わせてどうぞ。Echo を選んだ後の作り込みは本番運用ガイドへ。