Does Flask Work With Cloudflare R2?
Flask works seamlessly with Cloudflare R2 via the boto3 S3-compatible client, enabling straightforward file uploads and management in your Python web application.
Quick Facts
How Flask Works With Cloudflare R2
Flask has no built-in R2 support, but Cloudflare R2's S3-compatible API means you can use boto3, the standard AWS SDK for Python, without modification. This creates a clean integration where you configure boto3 with R2 credentials and endpoint, then interact with R2 like you would S3. The developer experience is straightforward: initialize a boto3 S3 client in your Flask app, handle file uploads in route handlers, and manage object operations through standard boto3 methods. Most developers wrap the boto3 client in a Flask extension or utility module for cleaner code. The main architectural consideration is managing credentials securely—store R2 API tokens in environment variables, never in source code. R2's zero egress fees make it ideal for Flask apps serving downloadable content or handling user uploads without bandwidth surprises.
Best Use Cases
Quick Setup
pip install flask boto3from flask import Flask, request, jsonify
import boto3
import os
app = Flask(__name__)
s3_client = boto3.client(
's3',
endpoint_url='https://' + os.getenv('R2_ACCOUNT_ID') + '.r2.cloudflarestorage.com',
aws_access_key_id=os.getenv('R2_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('R2_SECRET_ACCESS_KEY'),
region_name='auto'
)
@app.route('/upload', methods=['POST'])
def upload_file():
file = request.files['file']
s3_client.upload_fileobj(
file.stream,
os.getenv('R2_BUCKET_NAME'),
file.filename
)
return jsonify({'status': 'uploaded', 'filename': file.filename})
@app.route('/download/<filename>')
def download_file(filename):
url = s3_client.generate_presigned_url(
'get_object',
Params={'Bucket': os.getenv('R2_BUCKET_NAME'), 'Key': filename},
ExpiresIn=3600
)
return jsonify({'download_url': url})
if __name__ == '__main__':
app.run(debug=True)Known Issues & Gotchas
Signed URL expiration defaults to 1 hour; long-lived URLs require explicit configuration
Fix: Use boto3's generate_presigned_url() with Expiration parameter set to desired seconds (e.g., 86400 for 24 hours)
R2 has object name limitations; slashes and special characters can cause unexpected behavior
Fix: Sanitize filenames or use uuid library to generate safe object keys before uploading
Large file uploads timeout with Flask's default request timeout
Fix: Implement multipart upload via boto3's s3_client.upload_file() with AWS_S3_MAX_MEMORY_SIZE config, or use Werkzeug streams
CORS errors when serving files directly from R2 to browser clients
Fix: Configure R2 bucket CORS rules in Cloudflare dashboard to allow your Flask domain, or serve files through Flask routes instead
Alternatives
- •Django + boto3: Full-featured web framework with same R2 integration approach
- •FastAPI + aioboto3: Modern async Python framework with async S3 operations for higher concurrency
- •Node.js + Express + AWS SDK: JavaScript alternative with similar S3-compatible workflow
Resources
Related Compatibility Guides
Explore more compatibility guides