bucketpilot
For teams bringing objects back into AWS from Cloudflare R2

Move a Cloudflare R2 bucket into Amazon S3

Copy a Cloudflare R2 bucket into Amazon S3 on a schedule — incremental reruns, per-file logs, and a destination that can keep every version once it lands.

The migration form with a Cloudflare R2 source bucket and an Amazon S3 destination

Why the return trip is its own problem

Going back into AWS is not the S3-to-R2 job with the ends swapped, because the two sides are not symmetrical.

R2 is a single global namespace with no regions to choose and no Inventory to read, so the source has to be listed the long way. S3 has regions, storage classes and versioning, so the destination has decisions the source never had: which region, which class objects land in, and whether the bucket keeps versions. Most teams making this move are consolidating back into an AWS account that already has conventions — and the copy has to fit them rather than dump a flat bucket in the middle.

How the migration runs

  1. 1.Connect Cloudflare R2 with your account ID and an S3-compatible token. BucketPilot lists the buckets that token can see.
  2. 2.Connect the AWS account — the one-click least-privilege role, or a key. This side needs write access, so it is the side to scope carefully.
  3. 3.Choose or create the destination bucket, in the region you want. If you want the destination to keep every version, turn versioning on before the first run; S3 supports it and R2 never did.
  4. 4.Run the first pass, then re-run. Later runs compare both sides and carry only what changed.
  5. 5.Cut over when a run copies nothing, which is the signal that the two sides agree.

What is different about R2 as a source

  • Listing is the only way in. There is no Inventory on the R2 side, so a very large bucket is walked by listing it. That is fine, and it is why the first pass on a big bucket is the slow one and every pass after is not.
  • There are no versions to bring. R2 holds one copy of each object, so the migration carries current objects and nothing else. Whatever version history you want starts at the destination, from the first run onwards.
  • Storage class is decided on arrival. R2's two classes do not map onto the S3 ladder, so objects land in the destination's default class. Moving them colder afterwards is a lifecycle rule in AWS.
  • Tags BucketPilot holds for R2 objects stay with BucketPilot. They were never in R2 to copy.
  • Cloudflare does not charge egress, which is the one part of this route that is cheaper than the other direction. What AWS charges to receive and store is between you and AWS.

What you get while it runs

  • Incremental reruns, so the cutover pass is short.
  • Per-file logs naming anything that failed and why.
  • Retries and resume on transient failures and on a worker that dies mid-run.
  • Scheduled runs — hourly, daily, weekly or monthly.
  • Versioning at the destination, if you turn it on, so a later overwrite or delete in S3 is recoverable. R2 could not offer that.

Credentials and where the bytes go

The AWS side is the side with write access: use the one-click CloudFormation role so there is no long-lived key, and delete the stack to revoke. The R2 token can be scoped and rolled in Cloudflare.

Objects stream from source to destination and nothing of their contents is kept here. Credentials are stored encrypted, and every run appears in the activity log. Full detail: Security & privacy.

When this is the right move

  • You trialled R2, and the workload is going back into the AWS account where everything else lives.
  • You need features the destination has and the source does not — versioning, storage classes, Inventory on very large buckets.
  • You want a copy inside AWS for a process that can only read from S3.

When it is not. If both copies should stay live and in step permanently, a migration run on a schedule is a blunt instrument for that; consider whether what you want is a backup with restore, or a mirror inside AWS. And if the objects are only being moved to be searched, you do not need to move them at all — index both buckets and search them where they are.

Questions

Can BucketPilot see my R2 buckets automatically?
It lists the buckets the S3-compatible token you gave it can see, so scope the token to what you want visible.
Which region should the destination be in?
R2 has no regions to match, so pick the region your applications read from. The destination region is a choice you make once, in the form.
Do the objects arrive in the same storage class?
They arrive in the destination bucket's default class. R2's two classes do not map onto the S3 ladder, so tiering afterwards is a lifecycle rule in AWS.
Is there any version history to migrate?
No. R2 does not keep versions, so there is one copy of each object to bring. Version history at the destination begins with the first run.
Does Cloudflare charge me for the read?
Cloudflare does not charge egress on R2. What AWS charges to receive and store the objects is a separate matter and not something BucketPilot measures.
Can I run this on the free trial?
The AWS side and the jobs are Pro, which the 14-day trial includes. Connecting R2 is a Business feature and is not part of the trial.

Go deeper

Start my R2-to-S3 migration

Connecting Cloudflare R2 or Google Cloud Storage needs the Business plan — it is not part of the Pro trial. Everything else on this page is.