Storage Overview
ThinkEx supports two storage backends for handling file uploads (PDFs, images, and other media):Local File Storage
Store files directly on your server’s filesystem in the
./uploads directorySupabase Storage
Store files in Supabase cloud storage with CDN delivery
Local File Storage
Recommended for self-hosting - Simple setup with complete data control.Features
- Files stored in
./uploads/directory relative to the application root - No external dependencies or API keys required
- Full control over your data and storage location
- Simple backup and migration (just copy the directory)
- No bandwidth or storage limits beyond your server
- Ideal for single-server deployments
Configuration
Set Storage Type
In your
.env file, set:.env
The setup script automatically configures this for local development.
Verify Upload Directory
The
./uploads/ directory is created automatically when the first file is uploaded.Permissions: Ensure the Next.js process has write access:File Organization
Files are stored with unique identifiers to prevent conflicts:Backup and Migration
- Backup
- Restore
- Migration
Disk Space Management
Monitor storage usage
Monitor storage usage
Clean up orphaned files (advanced)
Clean up orphaned files (advanced)
Files that are no longer referenced in the database can be identified and removed:
Supabase Storage
Recommended for distributed deployments - Cloud-based storage with CDN delivery.Features
- Cloud storage with global CDN
- Automatic scaling and redundancy
- No local disk space requirements
- Suitable for multi-server deployments
- Built-in image transformations and optimizations
- Pay-as-you-go pricing
Prerequisites
- A Supabase account (free tier available)
- A Supabase project created
- Storage bucket configured
Configuration
Create Supabase Project
- Sign up at supabase.com
- Create a new project
- Wait for project initialization (1-2 minutes)
Create Storage Bucket
In your Supabase project dashboard:
- Navigate to Storage in the sidebar
- Click New bucket
- Set bucket name:
file-upload - Set bucket to Public
- Click Create bucket
Get API Credentials
In Supabase Dashboard → Project Settings → API:
- Copy Project URL (e.g.,
https://yourproject.supabase.co) - Copy anon public key from “Project API keys”
- Copy service_role secret key
The
service_role key is shown only once. Store it securely.Bucket Configuration
The storage bucket settings in Supabase:| Setting | Value | Description |
|---|---|---|
| Name | file-upload | Required bucket name |
| Public | ✅ Enabled | Files must be publicly accessible |
| File size limit | 50 MB (default) | Adjust based on needs |
| Allowed MIME types | All (default) | Or restrict to specific types |
Storage Policies (RLS)
For production, configure Row Level Security policies in Supabase:Migration Between Storage Types
- Local → Supabase
- Supabase → Local
Migrate existing local files to Supabase:
Update database records to reference new Supabase URLs after migration.
Comparison
When to Use Local Storage
Best for:
- Single-server deployments
- Full data ownership required
- Predictable storage costs
- Offline or air-gapped environments
- Simple backup requirements
- Server disk space limits
- No CDN (slower global access)
- Manual backup management
When to Use Supabase
Best for:
- Multi-server deployments
- Global user base (CDN benefits)
- Scalable storage needs
- Managed backups and redundancy
- Requires internet connectivity
- Third-party dependency
- Usage-based costs
- API rate limits
Troubleshooting
Local Storage: Permission Denied
Local Storage: Permission Denied
Problem: Cannot write to
./uploads/ directorySolution:Local Storage: Files Not Accessible
Local Storage: Files Not Accessible
Problem: Uploaded files return 404 errorsSolution:
- Verify files exist:
ls ./uploads/ - Check
STORAGE_TYPE=localin.env - Restart the Next.js server
- Check file permissions:
chmod 644 ./uploads/*
Supabase: Invalid Bucket Error
Supabase: Invalid Bucket Error
Problem: “Bucket not found” or “Access denied” errorsSolution:
- Verify bucket name is exactly
file-upload - Confirm bucket is set to Public
- Check API credentials are correct
- Verify
NEXT_PUBLIC_SUPABASE_URLformat:https://yourproject.supabase.co
Supabase: Upload Fails
Supabase: Upload Fails
Problem: File uploads fail silently or with errorsSolution:
- Check Supabase project is active (not paused)
- Verify
SUPABASE_SERVICE_ROLE_KEYis correct - Check file size is under bucket limit (default 50MB)
- Review Supabase Storage logs in dashboard
- Ensure RLS policies allow uploads (or disable RLS for testing)
Switching Storage Types
Switching Storage Types
Problem: Files lost after changing
STORAGE_TYPESolution:- Files are not automatically migrated
- Use migration scripts (see “Migration Between Storage Types” above)
- Database records still reference old storage locations
- Consider keeping both active during migration period
Security Best Practices
Next Steps
Configuration
Review all environment variables
Installation
Back to installation guide