Skip to content
Search

Cloudflare:R2

lastmod 2024-05-15created 2023-03-0412 edits

With R2, you can freely build the multi-cloud architecture you want using S3-compatible object storage.

  • Global object storage
  • Dynamic functionality provided through integration with Cloudflare Workers
  • Avoid vendor lock-in with Cloudflare's S3-compatible API

R2 pricing

R2 charges based on the total volume of data stored and two classes of operations on that data. There are no egress fees.

-

Forever free

Monthly rate

Storage

10GB/month

$0.015/1GB

Class A operations: mutate state

1,000,000/month

$4.50/million

Class B operations: read existing state

10,000,000/month

$0.36/million

Egress (data transfer to the Internet)
Egress directly from R2, including through the Workers API, S3 API, and r2.dev domains, incurs no data transfer (egress) charges and is free.
If you connect other metered services to an R2 bucket, you may be charged according to those services.

Storage usage

Storage is billed using gigabyte-month (GB-month) as the billing metric. GB-month is calculated by recording the total bytes stored over the period of the month. (duration of the month)

For example:

  • Storing 1GB for 30 days is billed as 1 GB-month.
  • Storing 2GB for 15 days is billed as 1 GB-month.

The following formula seems to apply.

저장된 총 GB * (저장된 기간 / 30일)

Operation Categories

These are the operations that affect billing.

Class A operations

Class A Operations include ListBuckets, PutBucket, ListObjects, PutObject, CopyObject, CompleteMultipartUpload, CreateMultipartUpload, ListMultipartUploads, UploadPart, UploadPartCopy and PutBucketEncryption. ​​

Class B operations

Class B Operations include HeadBucket, HeadObject, GetObject, UsageSummary, GetBucketEncryption and GetBucketLocation. ​​

Free operations

Free operations include DeleteObject, DeleteBucket and AbortMultipartUpload.

Creating a bucket and an API token

Cloudflare_r2_-_overview.png

In R2, you can create a bucket, and there is a "Manage R2 API Tokens" link:

Cloudflare_r2_-_create_bucket.png

When creating a bucket, choose "Automatic" (R2 automatically places the bucket in the closest available region based on the user's location) unless you have a special case.

Cloudflare_r2_-_create_api_token.png

Click the "Manage R2 API Tokens" link to create a token.

Cloudflare_r2_-_create_api_token_result.png

Creating a token outputs several values: Access Key ID, Secret Access Key, and Endpoint URL. Then just remember the bucket name and that bucket's region (Asia: apac).

boto3 example

import boto3

s3 = boto3.client(
    service_name ="s3",
    endpoint_url = 'https://<accountid>.r2.cloudflarestorage.com',
    aws_access_key_id = '<access_key_id>',
    aws_secret_access_key = '<access_key_secret>',
    region_name="<location>", # Must be one of: wnam, enam, weur, eeur, apac, auto
)

# Get object information
object_information = s3.head_object(Bucket=<R2_BUCKET_NAME>, Key=<FILE_KEY_NAME>)

# Upload/Update single file
s3.upload_fileobj(io.BytesIO(file_content), <R2_BUCKET_NAME>, <FILE_KEY_NAME>)

# Delete object
s3.delete_object(Bucket=<R2_BUCKET_NAME>, Key=<FILE_KEY_NAME>)

aws-sdk-js-v3 example

import {
  S3Client,
  ListBucketsCommand,
  ListObjectsV2Command,
  GetObjectCommand,
  PutObjectCommand
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const S3 = new S3Client({
  region: "auto",
  endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: ACCESS_KEY_ID,
    secretAccessKey: SECRET_ACCESS_KEY,
  },
});

console.log(
  await S3.send(
    new ListBucketsCommand('')
  )
);
// {
//     '$metadata': {
//     httpStatusCode: 200,
//         requestId: undefined,
//         extendedRequestId: undefined,
//         cfId: undefined,
//         attempts: 1,
//         totalRetryDelay: 0
// },
//     Buckets: [
//     { Name: 'user-uploads', CreationDate: 2022-04-13T21:23:47.102Z },
//     { Name: 'my-bucket-name', CreationDate: 2022-05-07T02:46:49.218Z }
//     ],
//     Owner: {
//         DisplayName: '...',
//         ID: '...'
//     }
// }

console.log(
  await S3.send(
    new ListObjectsV2Command({ Bucket: 'my-bucket-name' })
  )
);
// {
//     '$metadata': {
//       httpStatusCode: 200,
//       requestId: undefined,
//       extendedRequestId: undefined,
//       cfId: undefined,
//       attempts: 1,
//       totalRetryDelay: 0
//     },
//     CommonPrefixes: undefined,
//     Contents: [
//       {
//         Key: 'cat.png',
//         LastModified: 2022-05-07T02:50:45.616Z,
//         ETag: '"c4da329b38467509049e615c11b0c48a"',
//         ChecksumAlgorithm: undefined,
//         Size: 751832,
//         StorageClass: 'STANDARD',
//         Owner: undefined
//       },
//       {
//         Key: 'todos.txt',
//         LastModified: 2022-05-07T21:37:17.150Z,
//         ETag: '"29d911f495d1ba7cb3a4d7d15e63236a"',
//         ChecksumAlgorithm: undefined,
//         Size: 279,
//         StorageClass: 'STANDARD',
//         Owner: undefined
//       }
//     ],
//     ContinuationToken: undefined,
//     Delimiter: undefined,
//     EncodingType: undefined,
//     IsTruncated: false,
//     KeyCount: 8,
//     MaxKeys: 1000,
//     Name: 'my-bucket-name',
//     NextContinuationToken: undefined,
//     Prefix: undefined,
//     StartAfter: undefined
//   }

Presigned URLs

Security-related content.

See also

Favorite site

author Zer0 sitemap