Cloudflare R2を使ってファイルを保存する【Cloudflare運用記録 #6】
はじめに
こんにちは。
なかのひとカンパニーの archer です。
前回は、Cloudflare D1を個人開発で使ったときの構成や注意点について書きました。
D1はデータベースなので、
- タイトル
- URL
- 日時
- ステータス
- ファイル名
のようなデータを保存するのに向いています。
一方で、
- 画像
- JSONファイル
- CSV
- バックアップ
- その他の大きなファイル
までD1へ入れるのは少し違います。
そこで使えるのが、
Cloudflare R2
です。
今回は、R2の基本的な使い方と、D1との使い分け、無料枠についてまとめます。
R2はファイルを保存する場所
R2はCloudflareのオブジェクトストレージです。
簡単に言えば、
ファイルを置いておくためのストレージ
です。
たとえば、
R2
├─ images/movie-001.jpg
├─ images/movie-002.jpg
├─ data/movies.json
└─ backup/2026-09-09.json
のようにデータを保存できます。
「フォルダ」のように見えますが、実際にはObject Keyによって管理されています。
Amazon S3を使ったことがある人なら、かなり近い感覚で扱えます。
R2にはS3互換APIも用意されているため、既存のS3向けツールやSDKを使うこともできます。
D1とR2をどう分けるか
最初は、
「D1にもデータを保存できるなら、全部D1でいいのでは」
と思うこともあります。
自分の場合は、ざっくり、
D1
→ 検索・更新したい情報
R2
→ ファイルそのもの
と分けています。
たとえば画像を扱う場合、
D1には、
id
title
image_key
created_at
を保存します。
R2には、
images/12345.jpg
という実際の画像を保存します。
つまり、
D1
↓
R2のファイルを特定
↓
R2から取得
という形です。
D1は「このファイルは何なのか」を管理する。
R2は「ファイル本体」を持つ。
この分け方が分かりやすいと感じています。
Bucketを作る
R2では、ファイルを保存する単位としてBucketを作ります。
Wranglerを使う場合は、
npx wrangler r2 bucket create my-bucket
で作成できます。
確認する場合は、
npx wrangler r2 bucket list
です。
Cloudflareの管理画面から作ることもできます。
WorkersからR2を使う
WorkersからR2を使う場合はBindingを設定します。
Wranglerの設定に、
{
"r2_buckets": [
{
"binding": "MY_BUCKET",
"bucket_name": "my-bucket"
}
]
}
のように追加します。
これでWorkerから、
env.MY_BUCKET
としてR2へアクセスできます。
ファイルを保存する
Workers APIでは put() を使って保存できます。
たとえば、
await env.MY_BUCKET.put(
"images/sample.jpg",
file
);
とすると、
images/sample.jpg
というKeyでObjectが保存されます。
JSONなら、
await env.MY_BUCKET.put(
"data/sample.json",
JSON.stringify(data)
);
のような使い方もできます。
ファイルを取得する
取得するときは get() を使います。
const object = await env.MY_BUCKET.get(
"images/sample.jpg"
);
存在しなければ null になります。
そのため、
if (!object) {
return new Response("Not Found", {
status: 404
});
}
のように確認します。
R2自体は単純ですが、
どういうKeyでファイルを管理するか
は最初に考えておいた方がいいと思います。
たとえば、
images/{id}.jpg
なのか、
movies/{movieId}/poster.jpg
なのか。
ファイルが増えた後に変更するのは面倒なので、ある程度ルールを決めています。
ローカル開発では本番R2を触らない
D1と同じように、R2もローカル開発できます。
Wranglerの通常のローカル開発では、R2への書き込みもローカルストレージへ保存されます。
つまり、
ローカル開発
↓
ローカルR2
本番
↓
本番R2
と分けられます。
開発中のテスト画像を、本番Bucketへ大量に入れてしまうことを避けられます。
これはかなり重要です。
特に削除処理や上書き処理を作るときは、
まずローカルで試す
ようにしています。
R2をそのまま公開するか
R2へファイルを置いたからといって、必ずしも全世界へ公開する必要はありません。
R2は、
非公開
のままWorkers経由で取得することもできます。
一方、画像などを直接配信したい場合は、Custom DomainをBucketへ設定することもできます。
開発時には r2.dev のURLを使うこともできますが、Cloudflare公式では r2.dev は開発・テスト用途として案内されています。
本番でファイルを配信する場合は、
assets.example.com
のようなCustom Domainを使う方がよさそうです。
R2の大きな特徴はEgress無料
R2について調べると、よく出てくるのが、
Egress無料
という言葉です。
Egressは、
Cloudflare
↓
インターネット
へデータを出す通信です。
一般的なクラウドストレージでは、
ファイルを保存する
+
ファイルを外へ配信する
それぞれに料金を考える場合があります。
R2では、インターネットへのEgress料金がありません。
たとえば画像を保存して、
利用者
↓
画像をダウンロード
されても、そのデータ転送料自体にはEgress料金がかかりません。
個人開発では料金を予測しやすくなるので、これはかなり分かりやすいです。
ただし、全部無料ではない
Egress無料という言葉だけを見ると、
「R2はほとんど無料なのでは」
と思ってしまいます。
もちろん違います。
R2では主に、
Storage
Class A Operations
Class B Operations
に料金があります。
Storage
ファイルを保存している容量です。
Standard StorageではFree枠として、
10 GB-month / 月
があります。
Class A Operations
主にデータを変更する操作です。
たとえば、
- Objectの作成
- Objectの書き込み
- 一部の一覧取得
などです。
Free枠は、
100万回 / 月
です。
Class B Operations
主に既存データを読み取る操作です。
Free枠は、
1,000万回 / 月
です。
つまり、
Egressは無料でも、保存容量と操作回数は見る必要がある
ということです。
10GBならどのくらい使えるのか
単純な例ですが、
1枚500KB程度の画像なら、
10GB
÷
500KB
≒ 約20,000枚
です。
もちろん実際にはファイルサイズが違うので、単純計算ではあります。
ただ、個人開発で画像やJSONを保存する用途なら、
10GBでもかなり試せる
と感じます。
動画や大きなバックアップファイルを保存し始めると話は変わってきます。
何を保存するかによって、R2の無料枠の余裕はかなり変わります。
無料枠を超えるとどうなるか
ここはD1との違いとして重要です。
R2は無料枠を超えた利用量について、料金が発生します。
2026年9月時点のStandard Storageでは、
Storage
$0.015 / GB-month
Class A
$4.50 / 100万回
Class B
$0.36 / 100万回
Egress
無料
となっています。
つまり、
10GBを少し超えた
↓
突然サービス停止
という考え方ではなく、
無料利用分を超えた部分が課金対象になる
仕組みです。
D1 Freeの1日上限とは少し性格が違います。
操作回数は意外と大事
個人開発なら容量だけ見ればいいと思っていました。
ただ、用途によっては操作回数の方が大きくなります。
たとえば、
画像を100枚保存
程度なら大したことはありません。
しかし、
毎ページで大量のObjectを取得
するサービスではClass Bが増えます。
Cloudflareの料金例でも、保存容量自体は無料枠内なのに、大量の読み取りによって料金が発生するケースが示されています。
そのため、
R2は容量だけ見ればいいわけではない
という点は覚えておいた方がよさそうです。
Infrequent Accessには注意
R2にはStandard Storage以外に、
Infrequent Access
というストレージクラスもあります。
名前の通り、あまりアクセスしないデータ向けです。
保存単価はStandardより安くなります。
ただし、
- Data Retrieval料金がある
- 操作料金が異なる
- 最低保存期間がある
- Standardと同じFree枠は適用されない
といった違いがあります。
個人開発で、
「とりあえず無料枠で使ってみたい」
という場合は、まずStandard Storageから考えるのが分かりやすいと思います。
大きなファイルも保存できる
R2では1Objectあたり最大約5TiBまで扱えます。
ただし、一度の通常アップロードでは約5GiBまでなので、それ以上はMultipart Uploadを使います。
画像やJSON程度なら、まず気にすることはありません。
動画など大きなファイルを扱うようになったら意識する制限です。
今回使ったサービスの料金
2026年9月時点のR2 Standard StorageのFree枠は以下です。
| 項目 | Free |
|---|---|
| Storage | 10 GB-month / 月 |
| Class A | 100万回 / 月 |
| Class B | 1,000万回 / 月 |
| Egress | 無料 |
Free枠を超えた場合は、
| 項目 | 料金 |
|---|---|
| Storage | $0.015 / GB-month |
| Class A | $4.50 / 100万回 |
| Class B | $0.36 / 100万回 |
| Egress | 無料 |
となっています。
自分のような小規模な個人サービスでは、
まずStandardで開始
↓
無料枠で運用
↓
容量・Operationsを確認
↓
必要になったら料金を考える
という使い方が分かりやすそうです。
※料金・無料枠・制限は2026年9月時点のCloudflare公式情報をもとにしています。
最新情報はCloudflare公式ドキュメントを確認してください。
まとめ
今回はCloudflare R2についてまとめました。
自分の中では、
D1
→ 情報を管理する
R2
→ ファイルを保存する
という役割で分けています。
R2を使って便利だと感じているのは、
- WorkersからBindingで使える
- S3互換APIがある
- 画像やJSONなどを保存できる
- 10GBまで無料枠がある
- Egress料金が無料
- サーバー上のディスクを自分で管理しなくていい
というところです。
一方で、
- Storage
- Class A
- Class B
という利用量は確認する必要があります。
特に、
Egress無料 = R2が完全無料
ではないことは覚えておいた方がよさそうです。
D1とR2を使うようになって、
アプリ
↓
Workers
├─ D1
└─ R2
という構成がかなり作りやすくなりました。
DBサーバーもいらない。
ファイルサーバーもいらない。
個人開発で管理するものを減らしたい自分には、かなり相性のいい構成だと感じています。
次回は、
GitHub ActionsからCloudflareへ自動デプロイする
というテーマで書きます。
GitHubへpushしてから、CIを通してWorkersへデプロイするまでをまとめる予定です。
