# Cloudflare R2 for Beginners: Complete Getting Started Tutorial > **Published**: 24 August 2026 | **Reading Time**: 9 min read | **Author**: Mohammad Shadikur Rahman > **Tags**: Cloudflare, Cloudflare R2, Object Storage, AWS S3, Cloud, Tutorial > **Canonical Article**: https://shadikur.com/blog/cloudflare-r2-beginners-getting-started-tutorial --- ## Abstract / Excerpt Learn how Cloudflare R2 object storage works and create your first bucket, upload files, configure S3 API credentials, and connect with the AWS CLI. --- ## Article Content Cloudflare R2 is an object storage service for files such as images, videos, backups, logs, documents, and AI datasets. It offers an **Amazon S3-compatible API**, integrates directly with Cloudflare Workers, and - its most interesting feature-does **not charge egress bandwidth fees** when your data is downloaded from R2. This beginner-friendly tutorial will take you from an empty Cloudflare account to your first working R2 bucket. You will also learn how to upload files, connect through the AWS CLI, and decide whether your data should be public or private. > **Quick summary:** If you have used Amazon S3, R2 will feel familiar. If you have never used object storage, think of a bucket as a large online container and every uploaded file as an object with a unique name, called a key. ## Why Cloudflare R2 is interesting Traditional object storage pricing often includes a data-transfer or egress charge when users or applications download your files. That cost can become significant for media, backups, datasets, or a popular application. Cloudflare R2 separates itself in several useful ways: - **No egress bandwidth charge:** R2 does not charge for transferring stored data to the Internet. - **S3-compatible API:** Many existing S3 tools and SDKs can work with R2 by changing the endpoint and credentials. - **Cloudflare Workers integration:** A Worker can read and write objects through a native R2 binding without embedding S3 credentials in the code. - **Private by default:** New buckets are not publicly accessible unless you deliberately enable public access. - **Multiple access methods:** Beginners can use the dashboard, while developers can choose Wrangler, the S3 API, Workers, or tools such as rclone. The important detail is that **zero egress fees does not mean every part of R2 is free**. Storage capacity and operations can still be billable. ## R2 pricing in simple terms At the time of writing, Cloudflare’s monthly Standard Storage free tier includes: - 10 GB-month of storage - 1 million Class A operations - 10 million Class B operations - Free egress bandwidth Beyond the free tier, Standard Storage is listed at **$0.015 per GB-month**, with Class A and Class B requests priced separately. Class A generally covers operations that change or list data, while Class B generally covers reads. Infrequent Access has a lower storage price but higher operation fees and a data-retrieval charge. Pricing can change, so check the [official R2 pricing page](https://developers.cloudflare.com/r2/pricing/) before estimating a production workload. ## Step 1: Create or sign in to your Cloudflare account Go to the [Cloudflare dashboard](https://dash.cloudflare.com/) and sign in. From the dashboard: 1. Open **Storage & databases**. 2. Select **R2** and then **Overview**. 3. If R2 is not active yet, complete the subscription or checkout flow shown by Cloudflare. Cloudflare includes free monthly usage, but you may still be asked to activate an R2 subscription. Usage above the included allowance is billed monthly. ## Step 2: Create your first R2 bucket In the R2 Overview page, choose **Create bucket**. Use a clear bucket name, for example: ```text my-first-r2-bucket ``` Bucket names must be 3–63 characters long and may contain lowercase letters, numbers, and hyphens. A name cannot begin or end with a hyphen. For a first test, keep the default storage settings unless you have a specific data-location or storage-class requirement. After creating it, select the bucket to open it. You have now created private object storage. The bucket itself and its contents are **not public by default**. ### Optional: create a bucket with Wrangler Wrangler is Cloudflare’s command-line tool. After installing and authenticating it, a bucket can be created with: ```bash npx wrangler r2 bucket create my-first-r2-bucket ``` List your account’s buckets with: ```bash npx wrangler r2 bucket list ``` The dashboard is easier for your first experiment; Wrangler becomes convenient when you automate development and deployments. ## Step 3: Upload your first file from the dashboard Open the new bucket and select **Upload**. Drag a small image or text file into the upload area, or choose a file from your computer. After the upload succeeds, the object appears in the bucket. Its object key will normally be its filename, such as: ```text hello-r2.txt ``` You can organize objects with prefixes that look like folders: ```text images/profile.jpg backups/2026/database.sql.gz documents/invoice.pdf ``` Object storage does not work exactly like a normal disk. These “folders” are primarily prefixes in object keys, although the dashboard presents them in a familiar folder-style interface. For small and medium files, a normal single upload is sufficient. Cloudflare recommends multipart uploads for large files or when resumability and parallel uploads matter. The [official upload guide](https://developers.cloudflare.com/r2/objects/upload-objects/) explains the available methods. ## Step 4: Decide whether the bucket should be private or public This choice is important. ### Keep it private when storing - Backups - Customer documents - Internal application data - Private photos or recordings - AI datasets that should not be openly downloadable Private objects should be delivered through authenticated application logic or time-limited presigned URLs. ### Use public access when storing - Public website images - Public downloads - Static assets - Open datasets For production public content, Cloudflare recommends connecting a **custom domain** to the bucket. R2 also offers an `r2.dev` address for non-production use, but it is rate-limited and is not intended to be your main production delivery method. Follow Cloudflare’s [public bucket documentation](https://developers.cloudflare.com/r2/buckets/public-buckets/) to enable an `r2.dev` URL or attach a custom domain. Do not turn on public access for a bucket containing sensitive files. ## Step 5: Create S3-compatible API credentials To use the AWS CLI, an S3 SDK, or another compatible tool, create an R2 API token. In the Cloudflare dashboard: 1. Go to **R2 Overview**. 2. Open **Manage R2 API Tokens**. 3. Select **Create API token**. 4. Give it the minimum permissions required. 5. If possible, restrict it to the specific bucket you created. 6. Save the generated **Access Key ID** and **Secret Access Key** securely. The secret is normally shown only once. Never place it in Git, frontend JavaScript, a public screenshot, or a blog post. If it is exposed, revoke or rotate it immediately. You will also need your Cloudflare **Account ID**. The S3 endpoint follows this pattern: ```text https://ACCOUNT_ID.r2.cloudflarestorage.com ``` Read Cloudflare’s [R2 authentication documentation](https://developers.cloudflare.com/r2/api/tokens/) for the current token options and permissions. ## Step 6: Connect with the AWS CLI Install the AWS CLI, then create a separate profile so your R2 credentials do not overwrite any AWS credentials you already use: ```bash aws configure --profile cloudflare-r2 ``` Enter the R2 Access Key ID and Secret Access Key. For the default region, you can use `auto`. The output format can be `json`. Set your endpoint in a shell variable for convenience: ```bash export R2_ENDPOINT="https://ACCOUNT_ID.r2.cloudflarestorage.com" ``` On Windows PowerShell, use: ```powershell $env:R2_ENDPOINT = "https://ACCOUNT_ID.r2.cloudflarestorage.com" ``` ### List your buckets ```bash aws s3 ls \ --profile cloudflare-r2 \ --endpoint-url "$R2_ENDPOINT" ``` ### Upload a file ```bash aws s3 cp hello-r2.txt s3://my-first-r2-bucket/hello-r2.txt \ --profile cloudflare-r2 \ --endpoint-url "$R2_ENDPOINT" ``` ### List objects in the bucket ```bash aws s3 ls s3://my-first-r2-bucket/ \ --profile cloudflare-r2 \ --endpoint-url "$R2_ENDPOINT" ``` ### Download the file ```bash aws s3 cp s3://my-first-r2-bucket/hello-r2.txt downloaded-hello.txt \ --profile cloudflare-r2 \ --endpoint-url "$R2_ENDPOINT" ``` If these commands work, your S3-compatible connection is ready. Cloudflare provides additional examples in its [AWS CLI guide](https://developers.cloudflare.com/r2/examples/aws/aws-cli/). ## Step 7: Use R2 from an application Once the basic test works, choose the access method that fits your application: | Method | Best use | |---|---| | Cloudflare dashboard | Manual uploads and quick bucket management | | Wrangler CLI | Developer workflows and simple automation | | S3-compatible API | Existing Node.js, Python, PHP, Java, backup, or media workflows | | Workers API | Applications running on Cloudflare Workers | | Presigned URLs | Temporary client upload or download permission | For a Worker, you normally create an R2 binding and access the bucket through `env`. This avoids distributing long-lived S3 secrets inside your Worker code. For an existing backend, use an S3-compatible SDK and configure the R2 endpoint. Keep all permanent credentials on the server, never in browser code. ## Common beginner mistakes ### 1. Assuming every bucket is public R2 buckets are private by default. Uploading a file does not automatically create a public URL. ### 2. Publishing secret credentials Store secrets in environment variables or a secret manager. Do not commit a `.env` file containing real credentials. ### 3. Giving a token access to every bucket Use least privilege. A token for one application should normally access only the bucket and operations that application requires. ### 4. Saying “R2 is completely free” Egress bandwidth is free, and a monthly free tier is included, but storage and operations beyond that allowance are billable. Infrequent Access also has retrieval fees. ### 5. Using the development URL for production The public `r2.dev` URL is useful for testing. For production public assets, attach a custom domain and configure caching appropriately. ### 6. Uploading very large files as one request Use a compatible tool that supports multipart uploads for videos, backups, and datasets. Multipart uploads can be resumed and transferred in parallel. ## A practical first project A good first R2 project is a private backup bucket: 1. Create a private bucket named something like `project-backups`. 2. Create a token limited to that bucket. 3. Configure an AWS CLI profile. 4. Upload a test archive. 5. Download it and verify that it opens correctly. 6. Add lifecycle or retention rules only after understanding how long the data must be kept. 7. Monitor storage and request metrics in the dashboard. For public website assets, use a separate bucket. Keeping public files and private backups in different buckets makes permissions easier to understand and reduces accidental exposure. ## Final thoughts Cloudflare R2 combines familiar S3-style object storage with free egress bandwidth and tight integration across Cloudflare’s developer platform. New users can start entirely from the dashboard, then move to the AWS CLI, SDKs, Workers, presigned URLs, or automated backup tools as their needs grow. The safest learning path is simple: **create one private bucket, upload a small test file, create a bucket-scoped token, and verify access from the CLI**. Once that works, you have the foundation for media storage, application uploads, backups, AI datasets, and much more. For the latest product details, always refer to the [Cloudflare R2 product page](https://www.cloudflare.com/products/r2/) and [official R2 documentation](https://developers.cloudflare.com/r2/). --- ## Author Biography Mohammad Shadikur Rahman is a Senior Infrastructure Architect and Full Stack Engineer based in Hamburg, Germany. Specializing in AWS CDK, Cloudflare R2, DevOps, microservices, and VoIP platforms. - **Blog Index**: https://shadikur.com/blog.txt - **LLM Index**: https://shadikur.com/llms.txt