Export files to Supabase with cURL
Supabase is a powerful open-source alternative to Firebase, offering developers a robust backend-as-a-service platform. One of its standout features is cloud storage, which allows you to store and manage files effortlessly. In this DevTip, we'll explore how you can streamline your file exports to Supabase storage buckets using cURL commands, enhancing your data management and automation workflows.
Set up your Supabase account and create buckets
First, sign up for a Supabase account if you haven't already. Once logged in, navigate to the "Storage" section and create a new bucket. Ensure you set appropriate permissions for your bucket, typically allowing authenticated users to upload files.
When creating a bucket, you can choose between public and private access policies:
- Public: Files are accessible to anyone with the URL.
- Private: Files require authentication to access.
For sensitive data, always use private buckets with appropriate access controls.
Download and configure cURL
Most systems come with cURL pre-installed. The transfer examples require cURL 7.76.0 or later for
--fail-with-body. Verify your installation by running:
curl --version
If cURL isn't installed, you can easily install it:
- macOS: Use Homebrew
brew install curl
- Linux (Debian/Ubuntu):
sudo apt-get update && sudo apt-get install curl
- Windows: Use Windows Package Manager (winget) or download from the official website:
winget install --id cURL.cURL --exact
Understand cURL basics
cURL is a command-line tool for transferring data using various protocols. Basic syntax:
curl -X METHOD [options] URL
Common methods include GET, POST, and PUT. For Supabase, we'll primarily use POST for
uploading files.
Export files to Supabase using cURL
To upload files to Supabase, you'll need:
- Your Supabase project ID (found in the project URL)
- Your Supabase anon key (found in Project Settings → API)
- A JWT token for authentication (obtained after user login)
- Your bucket name
Here's the correct cURL command structure for uploading a file:
curl --fail-with-body --show-error -X POST "https://YOUR_PROJECT_ID.supabase.co/storage/v1/object/YOUR_BUCKET_NAME/file.txt" \
-H "apikey: YOUR_SUPABASE_ANON_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: text/plain" \
--data-binary "@file.txt"
Replace YOUR_PROJECT_ID, YOUR_BUCKET_NAME, YOUR_SUPABASE_ANON_KEY, and YOUR_JWT_TOKEN with
your actual values. Make sure to specify the correct Content-Type for your file. Percent-encode
each bucket/object path segment if it contains spaces or reserved URL characters, retaining /
between object folders. Upload policies must permit inserts for the authenticated user.
Handle entries: add, overwrite, and update files
The POST above creates a new object and rejects an existing path. To intentionally overwrite an
object, add -H "x-upsert: true" to that command; the user also needs select and update permissions.
See Supabase's standard upload behavior.
Use unique paths when older content must be preserved. A HEAD request can inspect existence, but a
separate existence check cannot prevent races with another writer:
curl --fail-with-body --show-error --head -o /dev/null -w '%{http_code}\n' \
"https://YOUR_PROJECT_ID.supabase.co/storage/v1/object/YOUR_BUCKET_NAME/file.txt" \
-H "apikey: YOUR_SUPABASE_ANON_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
For an accessible object, this prints 200. Missing objects or insufficient permissions produce
an error status and a nonzero curl exit code. --head correctly tells curl to expect no body.
Understand file size limits
The maximum file size depends on your plan, the project's global limit, and any stricter bucket
limit. Check the dashboard and Supabase's current file limit documentation.
For larger transfers, use Supabase's resumable tus uploads.
The --data-binary @file commands in this guide buffer the file in memory and do not resume.
Automate file export in a daily workflow
Automating file uploads can significantly streamline your workflow. Here's a complete bash script example:
#!/bin/bash
set -u
# Supply credentials through the environment, with a current user access token.
: "${PROJECT_ID:?Set PROJECT_ID}" "${ANON_KEY:?Set ANON_KEY}" "${JWT_TOKEN:?Set a current user JWT}"
BUCKET_NAME="your-bucket"
FILE_PATH="/path/to/daily-report.csv"
FILE_NAME="reports/daily-report-$(date +%Y-%m-%d).csv"
# Upload command with retry logic
if curl --fail-with-body --show-error -X POST \
"https://$PROJECT_ID.supabase.co/storage/v1/object/$BUCKET_NAME/$FILE_NAME" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "Content-Type: text/csv" \
--retry 3 --retry-delay 5 \
--data-binary "@$FILE_PATH"; then
echo "File uploaded successfully to $BUCKET_NAME/$FILE_NAME"
else
echo "Error uploading file"
exit 1
fi
For unattended runs, use a credential wrapper that obtains or refreshes the user access token and exports the required variables before invoking this script. A pasted login JWT expires and is not a permanent cron credential. Keep the user's Storage policies limited to the required bucket and prefix; do not substitute a service-role key merely to avoid token refresh.
After configuring that wrapper, schedule it with cron:
crontab -e
Add the following line to run the script daily at midnight:
0 0 * * * /path/to/your/credential-wrapper.sh
Make the scripts executable and use absolute paths. Rerunning a daily upload targets the same object name and is rejected unless you explicitly opt into upsert. A retry after a lost response can also encounter an object created by the first attempt; verify it before deciding to overwrite.
Troubleshoot common issues
Here are common errors you might encounter and how to resolve them:
Authentication errors (401 unauthorized)
{ "statusCode": "401", "error": "Unauthorized", "message": "Invalid JWT" }
Solution: Ensure your JWT token is valid and not expired. For testing purposes, you can generate a new token through the Supabase Auth API.
Duplicate file errors
{ "statusCode": "409", "error": "Duplicate", "message": "The resource already exists" }
Solution: Use a unique filename or implement logic to handle existing files.
Storage versions can report duplicate objects as 400 Asset Already Exists or 409 Duplicate;
handle both instead of treating either status as success.
File size limits (413 payload too large)
{
"statusCode": "413",
"error": "PayloadTooLarge",
"message": "The file size exceeds the maximum limit"
}
Solution: Ensure your file is within the size limits for your Supabase plan.
Permission denied
Solution: Check bucket permissions in Supabase and ensure your JWT token has the necessary permissions.
Adhere to security best practices
When working with Supabase and cURL:
- Store API keys and tokens in environment variables, never hardcode them.
- Use appropriate bucket permissions (private buckets for sensitive data).
- Implement proper error handling and logging.
- Regularly rotate your API keys if they might be compromised.
- Use HTTPS for all requests (which Supabase enforces).
Optimize cURL commands
-
Use environment variables for sensitive data:
export SUPABASE_URL="https://YOUR_PROJECT_ID.supabase.co" export SUPABASE_ANON_KEY="YOUR_ANON_KEY" export SUPABASE_JWT="YOUR_JWT_TOKEN" curl --fail-with-body --show-error -X POST "$SUPABASE_URL/storage/v1/object/YOUR_BUCKET_NAME/file.txt" \ -H "apikey: $SUPABASE_ANON_KEY" \ -H "Authorization: Bearer $SUPABASE_JWT" \ -H "Content-Type: text/plain" \ --data-binary "@file.txt" -
Always specify the correct
Content-Typeheader for your file type. -
Implement retries for network reliability:
curl --fail-with-body --show-error --retry 3 --retry-delay 5 -X POST "https://YOUR_PROJECT_ID.supabase.co/storage/v1/object/YOUR_BUCKET_NAME/file.txt" \ -H "apikey: $SUPABASE_ANON_KEY" \ -H "Authorization: Bearer $SUPABASE_JWT" \ -H "Content-Type: text/plain" \ --data-binary "@file.txt" -
Use
--fail-with-bodyto make cURL return a nonzero exit code on HTTP errors while retaining the response body for diagnosis. -
Add the
-s(silent) flag to suppress progress meters for cleaner logs.
Conclusion
Using cURL to export files to Supabase provides a powerful, flexible approach to file management and automation. With the correct API endpoints, authentication headers, and best practices, you can build robust file export workflows that integrate seamlessly with your applications.
If you're looking for even more streamlined file exporting solutions, Transloadit offers a comprehensive File Exporting service with support for various storage providers.
