2026-08-16
· Dylan YuSQLite vs PostgreSQL:次のプロジェクトに適したデータベースの選び方
SQLiteとPostgreSQLは異なる問題を解決するデータベースですが、ネット上の多くの記事はどちらかが常に優れているかのように扱っています。本記事では、並行性、スケール、デプロイといった実際のワークロードに基づいた実践的な判断フレームワークを解説します。両方を使うケースについても触れます。
「SQLiteとPostgreSQL、どちらを使うべき?」——この質問に間違った答えが返ってくるのを、もう何度も見てきました。
典型的な回答は「SQLiteはプロトタイプ用、PostgreSQLは本番環境用」というようなものです。これは単なる簡略化というより、積極的に誤解を招く回答です。その結果、1人のユーザー向けのCLIツールにPostgreSQLサーバーを立てる過剰なことをしたり、複数ライターのSaaSのメインデータベースにSQLiteを使うという問題先延ばしの選択をしてしまったりします。
正直に言うと、この2つは根本的に異なる目的に最適化されています。正しい選択は、ほとんどの比較記事が触れないワークロードの具体的な条件に依存します。それでは、実際に見ていきましょう。
ほとんどの比較記事が飛ばす「コアの違い」
SQLiteはライブラリです。アプリケーションプロセスにリンクし、ディスク上のファイルを読み書きします。サーバーもネットワークも認証ハンドシェイクもありません。アプリとデータベースは同じプロセス内に存在します。
PostgreSQLはサーバーです。独立したデーモンとして動作し、独自のメモリと接続プールを管理し、ネットワークプロトコル経由でクエリを受け付けます。アプリケーションはクライアントとして接続します。
この単一のアーキテクチャの違いが、人々が議論するほぼすべての違いを説明しています。
- 並行性 — PostgreSQLはMVCCで数百の同時接続を処理します。SQLiteは単一のグローバルロックで書き込みを直列化します(WALモードでも同様)。
- デプロイ — SQLiteは
npm install better-sqlite3で終わりです。PostgreSQLはサーバーを立ち上げ、監視し、バックアップし、稼働させ続ける必要があります。 - スケール — PostgreSQLは複数ディスクにまたがるテラバイト級を想定しています。SQLiteは1台のマシン上のギガバイト級を想定しています。
- レイテンシ — SQLiteのクエリはネットワークラウンドトリップがないためマイクロ秒単位です。PostgreSQLのクエリはミリ秒単位です(localhostでも常にネットワークホップが発生します)。
これらはどちらかを「優れている」とするものではありません。特定のワークロードに対して「適している」かどうかを決めるものです。
SQLiteが適しているケース
1. シングルプロセスのアプリケーション
アプリがシングルプロセスで動く場合——CLIツール、デスクトップアプリ、モバイルアプリ、1台のサーバーで動くwebhookハンドラー——SQLiteがほぼ常に適切なデフォルトです。クライアントが1つしかないのに別のデータベースサーバーを用意するメリットはありません。
私が迷わずSQLiteを選ぶ例:
- ローカルストレージが必要なデスクトップアプリ(BaseVolt自体も設定にSQLiteを使っています)
- 実行間の状態を追跡するCLIツール
- モバイルアプリ(SQLiteはiOSとAndroidに組み込まれています)
- スキーマがまだ固まっていないプロトタイプやMVP
- 事前計算済みの
.dbファイルをバックエンドにする読み込み中心の分析ダッシュボード
2. 組み込み・エッジワークロード
SQLiteの「サーバー不要」という特性は、エッジ環境でスーパーパワーになります。Cloudflare D1は文字通りCloudflareのエッジネットワーク上で動くSQLiteです。TursoやlibSQLは分散読み取りに最適化されたSQLiteフォークです。ユーザーに近い場所で動くもの——CDNエッジのワーカー、IoTデバイス、組み込みシステム——を構築するなら、SQLiteが唯一の合理的な選択です。PostgreSQLをRaspberry Pi Zeroで運用したいとは思わないでしょう。
3. 書き込み競合の少ない読み込み中心のワークロード
驚かれるかもしれませんが、WALモードのSQLiteは数千の同時リーダーを競合なく処理できます。リーダーはライターをブロックせず、ライターもリーダーをブロックしません。制限があるのは同時書き込みだけ——一度に書き込めるのは1つだけです。
ワークロードが99%読み込みであれば(CMS、商品カタログ、設定ストア、事前計算済みデータの分析ダッシュボード)、SQLiteは想像以上にスケールします。「SQLiteはスケールしない」というのは、書き込み中心のマルチユーザーアプリの話であって、読み込み中心のワークロードの話ではありません。
4. データベースの運用をしたくない場合
これは過小評価されています。本番環境でPostgreSQLを運用するとは、以下のことを意味します。
- コネクションプーリングの設定(PgBouncerまたは組み込みのプーラー)
shared_buffers、work_mem、max_connections、wal_levelの設定- 自動バックアップの設定とリストアのテスト
- レプリケーション遅延、vacuumの肥大化、ロック競合の監視
pg_upgradeや論理レプリケーションによるメジャーバージョンのアップグレード
ソロ開発者や専任DBAのいない小規模チームにとって、これらはすべて深夜3時に壊れる可能性のあるものです。SQLiteにはこれらが一切ありません。バックアップは文字通りcp database.db database.db.bakだけです。
PostgreSQLが適しているケース
1. マルチプロセス・マルチサーバーのワークロード
2台のアプリケーションサーバーが同じデータを読み書きする必要が生じた瞬間、SQLiteは使えなくなります。SQLiteファイルをネットワーク共有に置くことはできますが、やるべきではありません。NFS/SMB上のファイルロックは、最終的にデータベースを破損させる危険な仕組みです。
PostgreSQLはまさにこのために設計されています。複数のアプリサーバーが1つのPostgreSQLインスタンスに接続し、PostgreSQLが並行性を正しく処理します。アプリケーションのレプリカを2つ以上稼働させるなら、サーバーサイドのデータベースが必要です。
2. 高い書き込み並行性のワークロード
数十の同時ライターがいる場合——アクティブユーザーのいるSaaS、ログパイプライン、リアルタイム分析の取り込み——SQLiteの単一ライターロックがボトルネックになります。WALモードでもライターはキューに入ります。PostgreSQLはMVCCでこれを処理します。複数のライターが異なる行を同時に変更でき、競合はコミット時に解決されます。
経験則:「異なるプロセスからの同時書き込み」がワークロードの中核であるなら、PostgreSQL(またはMySQLなど、別のサーバーサイドRDBMS)が必要です。
3. 実際に必要な高度なSQL機能
PostgreSQLにはSQLiteにない機能があり、その一部は重要です。
- ウィンドウ関数 — SQLiteにもありますが、PostgreSQLの実装の方がより完全です
- マテリアライズドビュー — PostgreSQLはネイティブでサポート、SQLiteは未サポート
- 全文検索 — 両方にFTSがありますが、PostgreSQLの
tsvector/tsqueryの方が強力です - JSON/JSONB — 両方ともJSONをサポートしますが、GINインデックス付きのPostgreSQLのJSONBは別次元です
- PostGIS — 地理空間クエリが必要なら、PostGISがゴールドスタンダードです
- 論理レプリケーション、パーティショニング、LISTEN/NOTIFY — SQLiteに相当するものがないサーバーサイド機能
上記で重要なのは*「実際に必要かどうか」*です。ほとんどのアプリはこれらの大部分を使いません。しかし、地理空間アプリを構築する場合、LISTEN/NOTIFYでリアルタイムプッシュが必要な場合、ネストされたJSONを大規模にクエリする場合は、PostgreSQLが答えです。
4. データベース層での厳密なデータ整合性
SQLiteはデフォルトで有名なほど寛容です。動的型付けを採用しており、整数カラムに文字列を挿入してもSQLiteは喜んで保存します。外部キーの強制はデフォルトでオフです(接続ごとにPRAGMA foreign_keys = ONを設定する必要があります)。PostgreSQLはデフォルトで厳密です。型の不一致はエラーを投げ、外部キーは強制され、制約は交渉の余地がありません。
チームで作業しており、アプリケーションコードに頼るのではなくデータベースに整合性を強制させたい場合、PostgreSQLの厳密さはバグではなく機能です。
比較表(正直なトレードオフ付き)
| 項目 | SQLite | PostgreSQL |
|---|---|---|
| アーキテクチャ | 組み込みライブラリ | クライアント・サーバー |
| セットアップ時間 | 数秒(1ファイル) | 数分〜数時間(サーバー設定) |
| 同時リーダー | 数千(WALモード) | 数千 |
| 同時ライター | 1(直列化) | 数百(MVCC) |
| 実用的な最大サイズ | ファイルあたり約1TB | テラバイト以上 |
| ネットワークレイテンシ | なし(プロセス内) | localhostでも0.1〜2ms |
| バックアップ | ファイルをコピー | pg_dump / WALアーカイブ / スナップショット |
| 運用負荷 | ほぼゼロ | 大きい |
| コスト | 無料 | 無料(セルフホスト)または$$(マネージド) |
| 厳密な型付け | オプション(デフォルトは動的) | 強制 |
| JSONサポート | JSON1拡張 | GINインデックス付きJSONB |
| 全文検索 | FTS5 | ランキング付きtsvector |
| 地理空間 | 限定的 | PostGIS(クラス最高) |
| レプリケーション | 組み込みなし(litestream等) | ストリーミング + 論理レプリケーション組み込み |
| 最適な用途 | シングルプロセス、エッジ、読み込み中心 | マルチサーバー、書き込み中心、複雑な処理 |
実践的な判断フレームワーク
読み飛ばされるフローチャートの代わりに、実際に答えを決める4つの質問を紹介します。
1. 同時にこのデータベースに書き込むプロセスはいくつですか?
- 1つ → SQLiteで問題なし
- 複数 → PostgreSQL
2. データベースは複数のマシンにまたがりますか?
- いいえ、1台のマシン → SQLiteで問題なし
- はい、複数サーバー / レプリカ → PostgreSQL
3. PostgreSQL専用の高度な機能(PostGIS、マテリアライズドビュー、大規模なJSONB、論理レプリケーション)が必要ですか?
- いいえ → SQLiteで問題なし
- はい → PostgreSQL
4. チームのデータベースサーバー運用能力は制約になりますか?
- はい、DBAがおらず時間もない → SQLite(またはマネージドPostgreSQL)
- いいえ、PostgreSQLを運用できる → PostgreSQL
「SQLiteで問題なし」が3つ以上ならSQLiteを使いましょう。「PostgreSQL」が2つ以上ならPostgreSQLを使いましょう。エッジケースは、ネットが言うほど多くありません。
現実:多くのチームが両方を使っている
誰も教えてくれないことがあります。この選択は常に二者択一ではありません。
うまく回っているチームでよく見る本番環境のパターン:
- PostgreSQLをメインの運用データベースとして使用(マルチサーバー、高書き込み、信頼の唯一の情報源)
- SQLiteをローカルキャッシュ、エッジレプリカ、または個々のマシン上の分析スナップショットとして使用
Cloudflare D1(エッジのSQLite)とPostgreSQLのプライマリを組み合わせるのは、グローバル分散アプリの正当なアーキテクチャです。Turso + PostgreSQLも同じアイデアです。PostgreSQLに書き込み、ユーザーの近くにあるSQLiteインスタンスにレプリケートし、ローカルでゼロレイテンシで読み取ります。
この構成での摩擦はデータベースではなくツールにあります。ほとんどの管理パネルはどちらか一方向けに作られています。結局、PostgreSQLにはDBeaver、SQLiteにはDB Browserを使うことになり、それぞれワークフローが完全に異なります。
私たちがBaseVoltを両方に対応させた理由の一部はここにあります。SQLiteなら.dbファイルを指定し、PostgreSQLなら接続文字列を入力するだけで、接続先に関わらず同じ管理インターフェース——グリッドビュー、カンバンボード、ダッシュボード、リレーションシップ設定——が使えます。両方を使うチームにとって、2つのツールが1つになります。(インストール前に試したい場合はdemo.basevolt.appにライブデモがあります。)
よく見る失敗例
「シンプルだから」という理由でマルチライターSaaSにSQLiteを使う。 確かにシンプルです——2人目のユーザーが1人目と同時に書き込んでSQLITE_BUSYにぶつかるまでは。本番でこれを見たことがあります。PostgreSQLを使いましょう。
1人ユーザーのCLIツールにPostgreSQLを立てる。 1人が使うアプリのために、バックアップし、監視し、アップグレードするデータベースサーバーを持つことになります。SQLiteを使いましょう。
「スケールしないから」とSQLiteを排除する。 SQLiteは数百GB、数千の同時リーダーまでスケールします。できないのは複数プロセスからの同時書き込みだけです。それがワークロードでないなら、SQLiteは想像以上にスケールします。
PostgreSQLのデフォルトを本番対応と扱う。 そうではありません。プーリングなしのmax_connections = 100は、実負荷がかかると壊れます。PostgreSQLを運用するなら、PgBouncer、shared_buffers、wal_compressionを学ぶか、これらを代行してくれるマネージドサービス(Neon、Supabase、RDS)を使いましょう。
まとめ
SQLiteとPostgreSQLは競合ではありません。異なる仕事のためのツールです。
- SQLiteはデータベースとアプリが共存する場合:デスクトップアプリ、モバイルアプリ、エッジ関数、CLIツール、読み込み中心のシングルサーバーワークロード、プロトタイプ。
- PostgreSQLはデータベースが複数のクライアントにサービスを提供する場合:複数サーバーを持つwebアプリ、高書き込み並行性のワークロード、高度なSQL機能が必要なアプリ、DB層での厳密な整合性が重要なもの。
間違った選択は「より強力な方」を選ぶことです。ワークロードが実際に何をしているかに基づいて選びましょう。ほとんどのアプリにデータベースサーバーは必要ありません。一部のアプリには不可欠です。どちらがどちらかを見極めることこそが、本当のスキルです。
SQLiteまたはPostgreSQL(あるいは両方)を使っているなら、BaseVoltはデータをどこにも送らずに、ローカルファーストの管理パネルを提供します。 アカウント不要、クラウド不要、オフラインで動きます。
SQLiteやPostgreSQLで何かを作っていますか?何を作っているのか気になります——Xで見つけてください。