Cloudflare R2 vs AWS S3:なぜR2を選ぶのか
English · 繁中 · Español · 日本語 · Português (BR)
著者: Danko Peng(@dankopeng)
更新: 2026年3月
読了時間: 約7分
ファイルストレージは必ずいつか必要になる
Webアプリを作っていると、必ずファイルを保存したい場面が来る。
- ユーザーのプロフィール画像
- 商品の写真
- ユーザーがアップロードするドキュメント
- アプリが生成するレポートやエクスポートファイル
これらはデータベース(D1)には入れない。データベースは構造化されたデータのためにあり、大きなバイナリファイルには向いていない。画像やファイルはオブジェクトストレージに保存する。
AWS S3とは何か?
AWS S3(Simple Storage Service) は現在最も広く使われているオブジェクトストレージだ。業界標準として確立されており、ほぼすべてのクラウドサービスがS3との互換性を持つか、S3のAPIを参考にしている。
しかし、S3にはある有名な「落とし穴」がある。
S3の転送料金問題
S3はファイルのアップロードは安い(またはほぼ無料)が、ダウンロード(転送)は有料だ。
AWSの転送料金:
- 最初の10TB/月:$0.09/GB
- 次の40TB/月:$0.085/GB
計算してみよう。もしあなたのアプリが1日100万回の画像表示をするとして、各画像が100KBなら:
1,000,000 × 100KB = 100GB/日
100GB × $0.085 = $8.5/日
月額コスト ≈ $255アプリが成功すれば成功するほど、転送コストが増えていく。これはインディー開発者にとって予想外のコストになりやすい。
Cloudflare R2とは何か?
R2 はCloudflareが提供するオブジェクトストレージだ。AWS S3と完全に互換性のあるAPIを持ちながら、最大の違いは1つ:
転送料金がゼロだ。
R2のコスト構造:
- ストレージ:$0.015/GB/月(無料枠:10GB/月)
- クラス A オペレーション(書き込み):$4.50/百万回(無料枠:1,000,000/月)
- クラス B オペレーション(読み取り):$0.36/百万回(無料枠:10,000,000/月)
- 転送料金:$0.00
アプリが成功して画像が何百万回ダウンロードされても、転送コストは一切かからない。
S3 API互換性の意味
R2はS3と互換性のあるAPIを持つ。これが意味することは:
S3用に書かれたコードを、エンドポイントのURLを変えるだけでR2で動かせる。
例えば aws-sdk を使ったコード:
// S3用
const s3 = new S3Client({
region: 'us-east-1',
credentials: {
accessKeyId: 'xxx',
secretAccessKey: 'xxx'
}
})
// R2用(エンドポイントを変えるだけ)
const s3 = new S3Client({
region: 'auto',
endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: R2_ACCESS_KEY_ID,
secretAccessKey: R2_SECRET_ACCESS_KEY
}
})既存のS3のコードをR2に移行するコストが非常に低い。
WorkersからR2を操作する(ネイティブバインディング)
vibefast.appのようにCloudflare Workers上でアプリを動かしている場合、S3 API互換の方法よりさらに簡単な方法がある。WorkersのネイティブR2バインディングだ:
// ファイルのアップロード
async function uploadFile(env: Env, key: string, file: ArrayBuffer, contentType: string) {
await env.R2.put(key, file, {
httpMetadata: { contentType }
})
return key
}
// ファイルの取得
async function getFile(env: Env, key: string) {
const object = await env.R2.get(key)
if (!object) return null
return object.body
}
// ファイルの削除
async function deleteFile(env: Env, key: string) {
await env.R2.delete(key)
}HTTPリクエストもAPIキーも必要ない。R2はWorkersの環境変数として直接使える。
vibefast.appでのR2の使い方
vibefast.appにはメディアライブラリ機能が内蔵されている。
管理画面からファイルをアップロードすると、自動的にR2に保存される。画像のURLを取得してデータベースに保存し、フロントエンドで表示する——このフローがすでに実装済みだ。
自分で実装する必要があるのは、そのURLを商品レコードや記事レコードに紐付ける部分だけだ:
// 商品作成時にR2の画像URLを保存
await env.DB.prepare(`
INSERT INTO products (name, price, image_url)
VALUES (?, ?, ?)
`).bind(name, price, imageUrl).run()R2の制限も知っておく
R2は万能ではない。知っておくべき制限:
オブジェクトサイズの上限
1オブジェクトあたり最大5TB。通常のWebアプリでは問題にならない。
一貫性モデル
R2はグローバルに整合性のある読み取りを提供するが、大量の同時書き込みがある場合の一貫性に注意が必要(通常は問題ない)。
ディレクトリ概念なし
S3と同様、R2もフラットなキースペースだ。images/products/item-1.jpgのようにスラッシュを含むキーを使えばディレクトリのように見せることはできるが、実際にはフォルダ構造は存在しない。
どちらを選ぶか:シンプルな判断基準
Cloudflare Workers上でアプリを動かしているなら、R2一択だ。
理由:
- 転送料金ゼロで長期的なコストが読みやすい
- WorkersネイティブバインディングでSDKが不要
- 同じCloudflareダッシュボードで管理できる
- Workersとのデータやりとりに余計なネットワーク往復が不要
AWS上でアプリを動かしているなら、S3は自然な選択だ。しかしVibe CodingでCloudflareを選んだなら、R2で統一するのが最も効率的だ。
Danko Peng
X · YouTube · Threads
完全なCloudflareフルスタックテンプレートを今すぐ使い始めたい方へ:
👉 vibefast.app — アーリーバード $99、2026年8月1日より $199 に値上がり。