1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflare R2を使ってファイルを保存する【Cloudflare運用記録 #6】

1
Posted at

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へデプロイするまでをまとめる予定です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?