単一バイナリ配布の CLI に Go を選ぶ理由

一言まとめ

`go build` が静的リンクの単一バイナリを全プラットフォームに吐き、goreleaser で Homebrew / Scoop / APT まで一括配布できる。標準 `regexp` は RE2 で線形時間が保証される。Rust は libssl / libc の動的リンクで配布事故を起こした前例があり、Zig は 2026 年時点でエコシステムが若い。

作成 · 更新 · #go#cli#distribution#rust
目次 6 sections
  1. 01 要件
  2. 02 Go を選ぶ理由
  3. 03 トレードオフ
  4. 04 採らなかった選択肢
  5. 05 関連
  6. 06 更新履歴

調査時点: 2026-04。公開 OSS の mask-pipe(標準出力の秘密情報をリアルタイムでマスクする CLI。github.com/c12o-dev/mask-pipe)の ADR から。

要件#

  • macOS / Linux / Windows × amd64 / arm64 で動く、ランタイム依存ゼロの単一バイナリ
  • ホットパスは stdin に対する正規表現マッチ(ストリーミング)
  • 秘密情報を扱うので、メモリ安全であること

Go を選ぶ理由#

観点内容
配布go build が静的リンクの単一バイナリを生成。goreleaser がクロスコンパイルと Homebrew / Scoop / APT のアセット公開を 1 コマンドで行う
正規表現標準 regexp は RE2 ベースで O(n) の線形時間が保証される。ストリーミングの遅延を予測可能にする
エコシステムPTY ライブラリ(creack/pty)など、シェル統合の拡張に要るものが揃っている
貢献者CLI ツール作者に馴染みが深く、貢献者の母数が大きい

トレードオフ#

  • バイナリサイズは 5〜8MB(未 strip)。Rust の積極的最適化なら 2MB 程度。必要なら UPX で圧縮する。
  • Go の regexp は複雑なパターンでは Rust の regex クレートより遅い。CPU バウンドでない用途なら許容し、ベンチマークで問題が出てから再評価する。

採らなかった選択肢#

  • Rust: 性能と regex クレートは一級だが、クロスコンパイルで OpenSSL / libc のリンク問題を踏みやすい。Teller(Rust 製の秘密情報ツール)が libssl.so.1.1 の動的リンクで Ubuntu 22.04 以降に起動しなくなった前例がある。ビルド時間も長く、小規模チームの反復を遅くする。
  • Zig: 小さな静的バイナリを作れるが、本番システムで動かすツールにはエコシステムが若い。
  • Python / Node.js: ランタイムが要る時点で「入れて忘れる」体験が成立しない。
  • C: 秘密情報を扱うツールでメモリ安全性を手放す理由がない。

関連#

更新履歴#

  • 2026-04-16: 初版(mask-pipe ADR-0001)
  • 2026-10-17: Wiki へ移植、概念ページとして再構成

出典

  1. https://github.com/tellerops/teller/issues/290

同じトピック — CLI