RemitAid Tech Blog
🔄

SQLBoiler から sqlc への移行 —— 選定基準と導入までの実践記録

に公開

こんにちは!ソフトウェアエンジニアの inari111 です。
先日 Go Conference 2025 に行ってきました!2 日間参加してきましたが、どのセッションも面白く勉強になりました。次回の Go Conference が今から楽しみです!

それでは、本題に移ります。

背景:SQLBoiler のメンテナンスモード突入

RemitAid のバックエンドには SQLBoiler を使っています。
SQLBoiler は DB のスキーマから Go のコードを生成する ORM です。スキーマファーストのライブラリで、型安全なコードを生成します。
SQLBoiler が v4.17.1 からメンテナンスモードになっており、移行先を探すことになりました。

選定基準

代替のライブラリを選ぶにあたりいくつか条件がありました。

  • 学習コストが低いこと
  • 開発効率を上げるためにコード生成を利用することができること
  • 生成されるコードが型安全であること

移行先の候補

乗り換え先の候補として以下のライブラリを検討しました。
簡単にですが、各ライブラリの紹介をします。

  • sqlc
    • SQL ファーストのライブラリ
    • ORM ではなく生の SQL を書き、それに対する型安全なコードを生成する
    • SQLBoiler の README でも代替案として紹介されている
  • ent
    • コードファーストのライブラリ
    • Go でスキーマを定義 → コード生成 → DB マイグレーション
  • dbtpl
    • 2025 年 5 月 6 日に「xo」から「dbtpl」へ変更
    • DB スキーマ/クエリ → テンプレート経由でコード生成
    • テンプレートをカスタマイズすることで柔軟なコード生成に対応

sqlc 採用の決め手

各ライブラリの PoC を行い検討した結果、sqlc を採用することにしました。

学習コストが低い

  • 生 SQL を書けるため、既存の SQL 知識がそのまま活かせる
  • ORM のクエリビルダーを新たに学ぶ必要がない
  • ドキュメントが充実しており、すぐに使い始められた

漸進的な移行が可能

  • 既存の SQLBoiler コードと共存できる
  • 新規機能から段階的に導入できる
  • リスクを抑えた移行が可能

今回は十分な検証時間を取れなかったという事情もあり、社内管理画面の API の新規実装から使い始めています。

導入まで

  • mysqldump でスキーマ情報のみを dump
  • コードを生成するための SQL を用意
-- 例: merchant.sql
-- name: ListAllMerchants :many
SELECT
    id,
    company_name
FROM
    merchants
ORDER BY
    id ASC;
  • sqlc.yaml を用意
    • DB の型と Go の型のマッピング
# sqlc.yaml の例
version: "2"
sql:
  - engine: "mysql"
    queries: "../queries"
    schema: "../schema/schema.sql"
    gen:
      go:
        package: "generated"
        out: "../generated"
        emit_empty_slices: true # クエリ結果が空の場合、nilではなく空のsliceを返す
        sql_package: "database/sql"
        overrides:
          - db_type: "varchar"
            nullable: true
            go_type:
              import: "database/sql"
              type: "Null[string]"
# (省略)
  • コード生成 (sqlc generate) を行うコマンドを Makefile に追加
  • 生成されたコードを使って処理を実装
# ディレクトリ構造
 .
 ├── generated/            # sqlc が自動生成するコード
 │   ├── db.go             # データベース接続用のコード
 │   ├── models.go         # テーブルの構造体定義
 │   └── merchant.sql.go   # merchant.sql から生成されたコード
 └── queries/              # SQL クエリファイル(手動で記述)
     └── merchant.sql      # merchant テーブル用のクエリ

ざっくりとですが、導入に関して行ったことをご紹介しました。
新規実装から導入するのは容易で、すぐに実装に入ることができました。

query ファイルの設計方針

導入中に1つだけ悩ましい問題がありました。

query ファイルをどの単位で分割するかという問題です。
1 ファイルに全部の SQL を書くと見通しが悪く、保守性も下がります。

私のチームでは Repository の interface を定義する単位で SQL のファイルも分割することにしました。

例:

  • MerchantRepositorymerchant.sql
  • TransactionRepositorytransaction.sql

このルールにより、SQL ファイルとコードの対応が明確になり、保守性が向上しました。

個人的には、SQL 駆動の開発は体験がいいと思っています。

今後の展開

今後は社内管理画面以外の API でも導入を進めていけたらと考えています。
SQLBoiler からの移行は急ぎではないですが、全体の方針は統一していきたいので、新規実装から sqlc を使い、既存の実装も徐々に移行していけたらと思います。

RemitAid では一緒に働く仲間を募集しています。
興味がある方はこちらからどうぞ!

https://youtrust.jp/recruitment_posts/ad655de82471df86af4f19469fe4c0de

https://youtrust.jp/recruitment_posts/7141d690aaa5ed348de45757da069e81

Podcast 「RemiTalk」を最近始めましたので、もし良ければ聴いてみてください!

https://podcasts.apple.com/jp/podcast/remitalk/id1826516525

Podcast 文字起こしはこちら

https://note.com/remitaid

RemitAid Tech Blog
RemitAid Tech Blog

Discussion