How I Moved My iCloud Photos to Cloudflare R2 (And Stopped Worrying About Egress Fees)
Transfer iCloud Photos to Cloudflare R2 with zero egress fees. 3 methods: browser upload, CLI tools, and direct cloud-to-cloud transfer via CloudsLinker.
Introduction
I hit a wall the first time I tried to serve old photos from S3 on a side project — the egress bill for a few hundred gigabytes of image assets made the whole thing impractical. Cloudflare R2 changed the math entirely: S3-compatible object storage with zero egress fees. Once I realized R2 could hold my entire iCloud Photos library and serve it to any app, CDN edge, or backup pipeline without per-gigabyte transfer charges, the decision was obvious. iCloud is great for viewing photos on Apple devices, but it doesn't give you an API, doesn't integrate with developer tooling, and charges you monthly for storage you can't programmatically access. This guide covers three ways to move your iCloud Photos into R2: a manual browser workflow, a CLI-based approach for developers, and a direct cloud-to-cloud transfer that skips your local machine entirely.
iCloud Photos keeps your entire photo library synchronized across every Apple device — iPhone, iPad, and Mac — automatically and quietly in the background. It's one of the most seamless photo experiences available, as long as you stay inside Apple's ecosystem.
- 5 GB free shared across backups, mail, files, and photos.
- iCloud+ plans scale from 50 GB up to 12 TB.
- Original quality storage with device optimization options.
- Apple ecosystem only — no API, no programmatic access.
iCloud Photos is built for consumers on Apple hardware. It has no public API, no S3-compatible interface, and no way to pipe photos into a developer workflow, a CDN, or an automated backup pipeline.
Cloudflare R2 is S3-compatible object storage designed to eliminate egress fees — the per-gigabyte charges that other cloud storage providers bill every time data leaves their network.
- Zero egress fees — read data as often as you want without transfer charges.
- S3-compatible API — works with existing S3 tools, SDKs, and CLI clients.
- 10 GB free tier with 10 million Class B (read) operations per month.
- Cloudflare edge integration — serve objects through Cloudflare's CDN natively.
R2 stores objects in buckets, organized by key prefixes (similar to folder paths). Photos land as individual objects inside the bucket and prefix you specify — accessible via the S3 API, Workers, or a public custom domain.
The tipping point for me was a weekend project: I wanted to build a photo gallery site backed by my own image archive. The photos were in iCloud. Getting them into anything programmable meant downloading every file manually, uploading to S3-compatible storage, and then paying egress every time anyone viewed a page. R2 removed the egress cost from the equation entirely — and suddenly a personal photo archive became a viable backend, not a billing liability.
- Zero egress fees change the economics of photo storage: With traditional S3 providers, every time you or your app reads a photo from storage, you pay per gigabyte transferred out. R2 charges nothing for egress — which means you can serve, share, or sync your photo archive without watching a bandwidth meter.
- S3-compatible API unlocks developer workflows: Once your photos live in R2, any tool that speaks S3 — rclone, boto3, the AWS CLI, Terraform — can read, list, and manage your archive. iCloud Photos has no API at all. R2 turns a locked photo library into programmable storage.
- Native Cloudflare edge integration: Connect a custom domain or a Cloudflare Worker to your R2 bucket and your photo archive is instantly served through Cloudflare's global CDN — no separate CDN configuration, no origin pull costs.
- Pay only for what you store: R2 pricing is storage plus operations — no minimum commitment, no lock-in period, no surprise bandwidth surcharges. For a photo archive that gets read often but written rarely, the cost profile is significantly lower than traditional object storage.
- Platform-independent access: R2 doesn't care which device or OS you use. Any S3 client on any platform can reach your photos — no Apple ID required, no iCloud app dependency, no ecosystem lock-in.
Getting photos out of iCloud and into an R2 bucket takes a few deliberate steps. Here are three approaches that work in practice.
Method 1: Download from iCloud Photos, Then Upload via R2 Dashboard
The most accessible approach — no CLI tools required. Best suited for small batches or a quick test before committing to a larger migration.
Step 1: Export from iCloud Photos
Open iCloud Photos on the web and sign in with your Apple ID.
Select the photos or albums you want to export. Click the download icon and choose your preferred format:
- Original Format — preserves HEIC, Live Photos, and RAW files at full quality.
- Most Compatible — converts HEIC to JPEG. Useful if downstream tools don't handle HEIC.
Step 2: Upload to Cloudflare R2 via Dashboard
Log into the Cloudflare Dashboard , navigate to R2 Object Storage, and open the target bucket (or create a new one).
- Click Upload inside the bucket view.
- Drag and drop the extracted photo files, or click to browse.
- Optionally specify a prefix path (e.g.,
icloud-photos/2024/) to organize objects. - Wait for the upload to complete.
Method 2: Download from iCloud, Then Upload via CLI (rclone / aws cli)
The developer-friendly path. Download your photos from iCloud locally, then push them to R2 using S3-compatible CLI tools. This gives you full control over key prefixes, parallel uploads, and automation.
Step 1: Download from iCloud Photos
Use the same iCloud web export from Method 1, or download via the Photos app on macOS (Photos → Select All → File → Export Unmodified Originals) to a local folder.
Step 2: Configure CLI access to R2
Generate an R2 API token in the Cloudflare Dashboard:
- Go to R2 Object Storage → Manage R2 API Tokens.
- Click Create API Token.
- Choose the permission scope (Object Read & Write) and select the target bucket.
- Copy the Access Key ID, Secret Access Key, and note your Account ID (visible in the R2 overview page).
Your R2 S3-compatible endpoint is:
https://<ACCOUNT_ID>.r2.cloudflarestorage.com
Step 3: Upload with rclone (recommended)
Configure rclone with your R2 credentials:
rclone config
# Choose: New remote
# Name: r2
# Type: Amazon S3 Compliant (s3)
# Provider: Cloudflare
# Access Key ID: <your access key>
# Secret Access Key: <your secret key>
# Endpoint: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
Then sync the local photos folder to your R2 bucket:
rclone sync /path/to/icloud-photos r2:my-photo-bucket/icloud-archive/ --progress
rclone handles parallel uploads, retries on failure, and can resume interrupted transfers. For large libraries, this is significantly faster than any browser-based upload.
Method 3: Move iCloud Photos to Cloudflare R2 Directly in the Cloud (No Local Downloads)
When Your Photo Library Is Too Large to Route Through Your Machine
Once your iCloud library crosses a few hundred gigabytes, downloading locally to upload again is no longer practical — it ties up your machine, eats your bandwidth twice, and risks incomplete transfers on flaky connections. CloudsLinker connects iCloud Photos and Cloudflare R2 directly. Photos move cloud-to-cloud without touching your computer, without consuming your home internet connection, and without your hard drive getting involved at all.
Step 1: Connect iCloud Photos
In CloudsLinker, click Add Cloud and select iCloud Photos. Enter your Apple ID and password. If two-factor authentication is enabled, enter the verification code from your trusted Apple device when prompted.
Once connected, your iCloud albums appear in the CloudsLinker dashboard. You can transfer your entire library or select specific albums.
Step 2: Connect Cloudflare R2 (S3-Compatible Credentials)
Cloudflare R2 uses S3-compatible credentials for access. You need an Access Key ID, a Secret Access Key, and your account-specific endpoint.
Where to find your credentials:
In the Cloudflare Dashboard, go to R2 Object Storage →
Manage R2 API Tokens → Create API Token. Copy the Access Key ID
and Secret Access Key. Your endpoint is
https://<ACCOUNT_ID>.r2.cloudflarestorage.com
(the Account ID is shown on the R2 overview page).
Add Cloudflare R2 in CloudsLinker:
- Click Add Cloud and select Cloudflare R2.
- Fill in the Access Key ID, Secret Access Key, and endpoint.
- Confirm the connection.
Once connected, your R2 buckets appear in the CloudsLinker file browser.
Step 3: Configure the Transfer
Go to the Transfer section. Set iCloud Photos as the source and Cloudflare R2 as the destination.
For the destination, select the target bucket and specify an optional key
prefix to organize your photos — for example,
icloud-photos/ or archive/2024/. Photos arrive
as individual objects inside that prefix path, named by their original
filenames.
If you want to preserve your iCloud album organization, transfer one album
at a time: select a specific iCloud album as the source, use a matching
prefix in R2 as the destination (e.g., icloud-photos/italy-2024/),
and run each album as a separate task.
Step 4: Start and Monitor the Transfer
Click Transfer Now. The task appears in your Task List, where you can monitor progress in real time. Because the transfer runs entirely in the cloud, your computer does not need to stay on.
For large libraries, this is the key advantage: photos move directly from iCloud's infrastructure to Cloudflare's network using CloudsLinker's servers — not your home internet connection. Once transferred, the objects are immediately accessible via the S3 API, Workers, or any tool connected to your R2 bucket.
Comparing the 3 Ways to Move Photos from iCloud Photos to Cloudflare R2
| Method | Ease of Use | Speed | Best For | Uses Local Bandwidth | Skill Level |
|---|---|---|---|---|---|
| R2 Dashboard (Download → Upload) | ★★★★★ | ★★☆☆☆ | Small batches, quick tests | Yes (download + upload) | Beginner |
| CLI (rclone / aws cli) | ★★★☆☆ | ★★★★☆ | Developers, automation, structured prefixes | Yes (download + upload) | Intermediate |
| CloudsLinker (Cloud-to-Cloud) | ★★★★☆ | ★★★★★ | Large libraries, full migration | No | Beginner |
-
Plan your key prefix structure before starting:
R2 is flat object storage — there are no real folders, only key prefixes.
Decide on a naming convention before the first upload
(e.g.,
photos/2024/oricloud-archive/album-name/) so you don't end up reorganizing thousands of objects later. - R2 stores files as-is — HEIC included: R2 stores whatever you upload without conversion. If your iCloud library is mostly HEIC files and you need JPEG for downstream use, convert before uploading (via "Most Compatible" export from iCloud.com) or handle conversion in a Worker or pipeline after transfer.
- Check your R2 free tier limits for large libraries: The R2 free tier includes 10 GB of storage and 1 million Class A (write) operations per month. A large iCloud library will exceed the free tier. Check your estimated storage size and review R2 pricing before starting a full migration.
- iCloud 2FA: have your Apple device nearby: When connecting iCloud Photos in CloudsLinker, you'll need to complete two-factor authentication. Have your trusted iPhone or iPad on hand to receive and enter the verification code. Confirm that "Access iCloud Data on the Web" is enabled in your Apple ID settings before starting.
- R2 API tokens should be scoped narrowly: When creating an R2 API token for CloudsLinker or CLI use, restrict it to the specific bucket you're using for this migration. Avoid using account-wide tokens with broader permissions than necessary.
- Verify before removing anything from iCloud: After the transfer completes, spot-check a few albums worth of objects in R2 — verify file counts and open a few photos — before cancelling your iCloud+ plan or deleting originals. CloudsLinker's Task List shows a transfer summary when each task finishes.
Frequently Asked Questions
my-bucket/icloud-photos/IMG_1234.HEIC).
There is no automatic folder or album hierarchy. If you want to mirror your iCloud album structure, create matching key prefixes in R2 and transfer one album at a time.
To preserve your album structure, transfer one album at a time: in CloudsLinker, set a specific iCloud album as the source, then use a matching prefix in R2 as the destination (e.g.,
icloud-archive/italy-2024/). Repeat for each album.
R2 itself does not render or preview photos. How you display or process the files depends on your downstream tooling — a Cloudflare Worker, a web app, or an image processing pipeline. If you need JPEG for compatibility, convert before uploading or handle conversion downstream.
Before connecting, confirm that "Access iCloud Data on the Web" is enabled in your Apple ID settings at appleid.apple.com. Once connected, your iCloud albums and full library appear in the CloudsLinker dashboard.
Before starting a large migration, estimate your iCloud library size (check in Settings → Apple ID → iCloud → Manage Storage on your iPhone) and confirm your R2 billing is set up to handle the volume. The free tier is good for testing; a full library migration will need a paid account.
On iPhone, if "Optimize iPhone Storage" is enabled, full-resolution originals for older photos may only exist on iCloud's servers — not on the device. Any tool that reads from the phone (including the Files app or AirDrop) will only get the compressed local thumbnails, not the originals.
Cloud-to-cloud transfer via CloudsLinker reads directly from iCloud's servers, so every original file is transferred at full resolution regardless of what's cached locally.
Selective transfer also makes sense if you only need certain albums in R2 for a specific project (e.g., product photos for a website) while keeping personal photos in iCloud.
Conclusion
A handful of photos for a quick test? Download from iCloud and upload through the R2 dashboard. A structured migration with folder prefixes and automation potential? Use the CLI with rclone or the AWS S3-compatible tools. A full iCloud library — hundreds of gigabytes or more — without tying up your local bandwidth or hard drive? CloudsLinker moves everything cloud-to-cloud, directly from iCloud's servers to your R2 bucket. Set up takes ten minutes. Start with one album to verify the bucket structure before migrating everything.
Online Storage Services Supported by CloudsLinker
Transfer data between over 48 cloud services with CloudsLinker
Didn' t find your cloud service? Be free to contact: [email protected]
Further Reading
Effortless FTP connect to google drive: Transfer Files in 3 Easy Ways
Learn More >
Google Photos to OneDrive: 3 Innovative Transfer Strategies
Learn More >
Google Photos to Proton Drive: 3 Effective Transfer Techniques
Learn More >