Uploading Files to Cloudflare R2 Storage: A Simple Guide

Matthew Araujo
4 min readApr 17, 2024

--

In the realm of cloud storage solutions, Cloudflare’s R2 Storage offers a powerful yet straightforward platform for storing files securely.

While exploring Cloudflare R2 Storage, I found that documentation on uploading files using Go was a bit scarce. It took some digging to piece together the process, so I decided to compile this guide to make it easier for others.

In this article, we’ll walk through the steps of uploading files to Cloudflare R2 Storage using Go, combining explanatory text with code snippets for a comprehensive understanding.

the full code is at the end

Step 1: Setting Up the Environment

First things first, let’s set up our Go environment and ensure we have the necessary packages installed. In our Go code, we’ll be using the AWS SDK for Go, so make sure to have it installed:

go get -u github.com/aws/aws-sdk-go-v2

Step 2: Defining the S3Service Struct

Before we dive into the implementation details, let’s define the S3Service struct, which will encapsulate our S3 client and bucket information. This struct will help us organize our code and manage interactions with Cloudflare R2 Storage effectively.

type S3Service struct {
s3Client *s3.Client // The AWS S3 client for interacting with the service
bucket string // The name of the bucket in Cloudflare R2 Storage
}

Step 3: Initializing the Cloudflare R2 Service

Now, let’s dive into the implementation of the NewR2Service function. This function is responsible for initializing our Cloudflare R2 service by setting up the AWS SDK configuration with our credentials and endpoint.

// Function to initialize Cloudflare R2 service
func NewR2Service() (*S3Service, error) {
// Replace these values with your Cloudflare R2 Storage credentials
account := "YOUR_ACCOUNT_ID"
accessKey := "YOUR_ACCESS_KEY_ID"
secretKey := "YOUR_SECRET_ACCESS_KEY"
bucket := "YOUR_BUCKET_NAME"

// Create custom resolver for R2 endpoint
r2Resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
return aws.Endpoint{
URL: fmt.Sprintf("https://%s.r2.cloudflarestorage.com", account),
}, nil
})

// Load AWS config with custom resolver
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithEndpointResolverWithOptions(r2Resolver),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")),
config.WithRegion("apac"),
)
if err != nil {
return nil,err
}

// Create a new S3 client
s3Client := s3.NewFromConfig(cfg)

// Return a new S3Service instance initialized with the S3 client and bucket name
return &S3Service{
s3Client: s3Client,
bucket: bucket,
}, nil
}

Step 4: Uploading Files to Cloudflare R2 Storage

Now, let’s explore the UploadFileToR2 method, which is responsible for uploading a file to Cloudflare R2 Storage. This method allows us to specify the file key, content, and content type before initiating the upload process.

// Function to upload file to Cloudflare R2 Storage
func (s *S3Service) UploadFileToR2(ctx context.Context, key string, file []byte) error {
// Create a PutObjectInput with the specified bucket, key, file content, and content type
input := &s3.PutObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(key),
Body: bytes.NewReader(file),
ContentType: aws.String("image/jpeg"), // Set the content type to image/jpeg (change as needed)
}

// Upload the file to Cloudflare R2 Storage
_, err := s.s3Client.PutObject(ctx, input)
if err != nil {
return err
}

return nil
}

Final Step: Uploading a Sample File

To bring everything together, let’s create a main function that initializes the Cloudflare R2 service and uploads a sample file to demonstrate the functionality.

func main() {
// Initialize the Cloudflare R2 service
s3Service, err := NewR2Service()
if err != nil {
log.Fatal(err)
}

// Upload a sample file
err = s3Service.UploadFileToR2(context.TODO(), "image.jpg", []byte("test"))
if err != nil {
log.Fatal(err)
}
}

Conclusion:

In this article, we’ve demystified the process of uploading files to Cloudflare R2 Storage using Go. By combining explanatory text with code snippets, we’ve provided a clear guide for integrating file uploads into your applications with ease. Happy coding!

all code togheter:

package main

import (
"bytes"
"context"
"fmt"
"log"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)

type S3Service struct {
s3Client *s3.Client
bucket string
}

// Function to initialize Cloudflare R2 service
func NewR2Service() (*S3Service, error) {
// Replace these values with your Cloudflare R2 Storage credentials
account := "YOUR_ACCOUNT_ID"
accessKey := "YOUR_ACCESS_KEY_ID"
secretKey := "YOUR_SECRET_ACCESS_KEY"
bucket := "YOUR_BUCKET_NAME"

// Create custom resolver for R2 endpoint
r2Resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
return aws.Endpoint{
URL: fmt.Sprintf("https://%s.r2.cloudflarestorage.com", account),
}, nil
})

// Load AWS config with custom resolver
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithEndpointResolverWithOptions(r2Resolver),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")),
config.WithRegion("apac"),
)
if err != nil {
return nil,err
}

// Create a new S3 client
s3Client := s3.NewFromConfig(cfg)

return &S3Service{
s3Client: s3Client,
bucket: bucket,
}, nil

}

// Function to upload file to Cloudflare R2 Storage
func (s *S3Service) UploadFileToR2(ctx context.Context, key string, file []byte) error {
input := &s3.PutObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(key),
Body: bytes.NewReader(file),
ContentType: aws.String("image/jpeg"),
}

// Upload the file
_, err := s.s3Client.PutObject(ctx, input)
if err != nil {
return err
}

return nil
}

func main() {
// Initialize the Cloudflare R2 service
s3Service, err := NewR2Service()
if err != nil {
log.Fatal(err)
}

// Upload a sample file
err = s3Service.UploadFileToR2(context.TODO(), "image.jpg", []byte("test"))
if err != nil {
log.Fatal(err)
}
}

--

--