Use AWS S3 for attachment storage
In this tutorial, we will show you how to replace Supabase Storage with AWS S3 for handling attachments in the React Native To-Do List demo app.
Introduction
The AWS credentials should never be exposed directly on the client - it could expose access to the entire S3 bucket to the user. For this tutorial we have therefore decided to use the following workflow:
- Client makes an API call to the app backend, using the client credentials (a Supabase Edge Function).
- The backend API has the S3 credentials. It signs a S3 upload/download URL, and returns that to the client.
- The client uploads/downloads using the pre-signed S3 URL.
The following updates to the React Native To-Do List demo app are therefore required:
- Create Supabase Edge Functions, and
- Update the demo app to use the AWS S3 storage adapter
The following pre-requisites are required to complete this tutorial:
- Clone the To-Do List demo app repo
- Follow the instructions in the README and ensure that the app runs locally
- A running PowerSync Service (can be self-hosted)
Steps
Step 1: AWS S3 Setup
Step 1: AWS S3 Setup
This tutorial assumes that you have an AWS account. If you do not have an AWS account, you can create one here.
To enable attachment storage using AWS S3, set up an S3 bucket by following these steps:
Create an S3 Bucket
- Go to the S3 Console and click
Create bucket
. - Enter a unique bucket name and select your preferred region.
- Under
Object Ownership
, set ACLs disabled and ensure the bucket is private. - Enable Bucket Versioning if you need to track changes to files (optional).
Configure Permissions
Go to the Permissions tab and set up the following:
- A bucket policy for access control
- Click Bucket policy and enter a policy allowing the necessary actions (e.g., s3:PutObject, s3:GetObject) for the specific users or roles.
- (Optional) Configure CORS (Cross-Origin Resource Sharing) if your app requires it
Create an IAM User
- Go to the IAM Console and create a new user with programmatic access.
- Attach an AmazonS3FullAccess policy to this user, or create a custom policy with specific permissions for the bucket.
- Save the Access Key ID and Secret Access Key.
Step 2: Create Supabase Edge Functions
Step 2: Create Supabase Edge Functions
We need to create 3 Supabase Edge Functions to handle the S3 operations:
- Upload,
- Download, and
- Delete
Before we create the Edge Functions, we need to set up the environment variables for the AWS S3 credentials. Create an .env
file in the root of your Supabase project, add and update
the values with your AWS S3 configuration created in Step 1:
For more information on getting started with a Supabase Edge Function, see the Supabase Getting Started Guide.
Security Note
The filename specified in each edge function request can pose security risks, such as enabling a user to overwrite another user’s files by using the same filename. To mitigate this, a common approach is to generate a random prefix or directory for each file. While it’s likely fine to omit this safeguard in the demo — since users can already read and delete any file — this should be addressed in a production environment.
Upload Edge Function
Upload Edge Function
Create the s3-upload
Edge Function by running the following in your Supabase project:
Download Edge Function
Download Edge Function
Create the s3-download
Edge Function by running the following in your Supabase project:
Delete Edge Function
Delete Edge Function
Create the s3-delete
Edge Function by running the following in your Supabase project:
Step 3: Add AWS Storage Adapter
Step 3: Add AWS Storage Adapter
Create a AWSStorageAdapter.ts
file in the demos/react-native-supabase-todolist/library/storage
directory and add the following contents:
Code
Code
Explanation
Explanation
The AWSStorageAdapter
class implements a storage adapter for AWS S3, allowing file operations (upload, download, delete) with an S3 bucket.
uploadFile
uploadFile
- Invokes the
s3-upload
Edge Function to get a pre-signed URL to upload the file - Converts the input ArrayBuffer to an Uint8Array for S3 compatibility
- Uploads the file with metadata (content type) to the pre-signed upload URL
downloadFile
downloadFile
- Invokes the
s3-download
Edge Function to get a pre-signed URL to download the file
- Fetch the file from S3 using the pre-signed URL and converts the response to a Blob for client-side usage
deleteFile
deleteFile
Two-step deletion process:
- Delete local file if it exists (using Expo’s FileSystem)
- Delete remote file from S3 by invoking the
s3-delete
Edge Function
Step 4: Use AWS Storage Adapter
Step 4: Use AWS Storage Adapter
Update the system.ts
file in the demos/react-native-supabase-todolist/library/config
directory to use the new AWSStorageAdapter
class (the highlighted lines are the only changes needed):
Step 5: Run the app
Step 5: Run the app
Ensure that all references toAppConfig.supabaseBucket
is replaced with the S3 bucket name in the React Native To-Do List demo app.
Obtaining the S3 bucket name in the client can be done by creating another Supabsae Edge Function that returns the bucket name. This ensures that all S3 information are kept on the server.
You can now run the app and test the attachment upload and download functionality.