byElvinas Predkelis
March 17, 2025
Over the years, there are more and more alternatives for cloud storage popping up. Luckily, most of them have an S3-compatible API which makes it very easy to switch between them. And that's exactly what we'll be doing throughout this article.
Our team has been gradually migrating all sorts of projects to Cloudflare R2 over the last year. We decided to migrate for a couple of reasons. Firstly, Cloudflare offers a friendlier pricing scheme which is always attractive. Secondly, it's just so much nicer to use - I personally try to avoid logging in to an AWS dashboard at all costs.
Even though this particular article covers migration to Cloudflare R2, it will work with any storage provider that has an API that's compatible with S3. For example, you could also opt-in for Digital Ocean Spaces, Hetzner Object Storage or Vultr Object Storage
I'll assume you have already set up your account on Cloudflare. Also, if you're reading this - you have probably already used Active Storage for your Ruby on Rails project.
First of all, you'll need to create a new bucket on Cloudflare R2. Fortunately, it's very easy to do so.
After you're done, you'll need to also generate the credentials to access the newly created bucket. In order to do so, you'll need to create an API token. To do so, follow these steps:
After you're done, you'll be presented with the Token value, Access Key ID, Secret Access Key. Copy these over as we'll be using these credentials setting up Active Storage and during the file migration.
There's this tool that Cloudflare Super Slurper and it helps migrating the files over from a supported provider.
Using is pretty simple, so you can just follow these steps.
Now, all the files will be transferred over to the new bucket you've just created.
Similarly, you can also use Sippy which migrates files as they're requested. However, we haven't used it and it won't be covered in this article.
Similarly to any other cloud storage provider, we'll add the newly created credentials to the credential file. Feel free to add the credentials as environment variable if that's prefered.
# bin/rails credentials:edit
cloudflare:
r2:
api_key: xxxxxxxxxxxx
access_key_id: xxxxxxxxxxxx
secret_access_key: xxxxxxxxxxxx
endpoint: https://xxxxxxxxxxxx.r2.cloudflarestorage.com
Now, we'll add the Active Storage configuration.
# config/stroage.yml
cloudflare:
service: S3
region: auto
endpoint: <%= Rails.application.credentials.dig(:cloudflare, :r2, :endpoint) %>
access_key_id: <%= Rails.application.credentials.dig(:cloudflare, :r2, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:cloudflare, :r2, :secret_access_key) %>
bucket: application-bucket-<%= Rails.env %>
And finally, we can update the Rails application to use Cloudflare as the Active Storage provider. In this article, we'll only set it for the production environment. However, setting up a bucket for the development environment could make the workflow nice and consistent.
# config/environments/production.rb
config.active_storage.service = :cloudflare
And that is pretty much it!
After you're done with setting up R2 as service, the last thing you should do is to update the Active Storage records in the database. Every record references the service_name
, so we need to make sure the attachments are pointing to the right location. To do so, you might want to run this simple script to do the needed changes.
ActiveStorage::Blob.find_each do |blob|
blob.update_column(:service_name, "cloudflare")
end
Please keep in mind that you might have multiple cloud storage services in your project. If so, filter out the blob records so you're only updating the relevant ones.
This is how we approached the migration to R2 for all of the projects we maintain. Hopefully, this will give a good idea on how to migrate between cloud storage providers while using Active Storage.
Reach out to us and let's build something great together
Schedule an exploration call