File Upload System
Many SaaS products need file upload: avatars, images, PDFs, contracts, attachments, spreadsheets, audio, video, and import files.
File upload looks like a form feature, but in production it touches file size, format validation, storage path, permissions, security scanning, progress, retry, CDN, deletion policy, and cost.
If the first design is too casual, the system becomes difficult to maintain when files grow.
Do Not Store Files Directly in the Database
A common beginner mistake is storing file content directly in the database.
Databases are good for structured data: users, orders, projects, and file records. They are not good for large binary files. The actual file should live in object storage such as S3, R2, OSS, COS, or GCS.
The database stores metadata:
file_id
owner_id
bucket
object_key
file_name
mime_type
size
status
created_at
The database knows who owns the file, where it is, and what state it is in. Object storage stores the actual content.
Do Not Expose Business Structure in Paths
Object storage paths should be designed carefully.
Do not use the original filename as the unique path, and do not put sensitive business information directly into the path. Original filenames can duplicate, contain special characters, or expose private information.
Prefer system-generated keys:
uploads/{user_id}/{file_id}/{safe_file_name}
Or:
uploads/{yyyy}/{mm}/{file_id}
You can display the original filename to users, but storage paths should be controlled by the system.
Prefer Presigned Upload
Many early systems upload files to the business server first, then transfer them to object storage.
This is simple, but large files create bandwidth and memory pressure on your server. Presigned upload is usually better.
Flow:
1. Frontend asks backend for upload credentials
2. Backend checks user permission and file info
3. Backend creates presigned URL
4. Frontend uploads directly to object storage
5. Frontend notifies backend after upload
6. Backend updates file status
The file data does not pass through your business server, making the system more stable and resource efficient.
Validate Before and After Upload
Do not trust the file sent by the frontend.
Validate file size, extension, MIME type, business limits, user quota, upload frequency, and file count. Frontend validation improves user experience. Backend validation protects the system. Object storage policies can also restrict size and type.
Examples:
Avatar: jpg/png/webp only, max 5MB
PDF: application/pdf only, max 20MB
Import sheet: csv/xlsx only, max 10MB
Video: limit format, size, and duration
Clear validation rules reduce dirty data later.
Uploaded Does Not Mean Ready
A successful upload only means the file reached storage. It does not mean the file is usable.
Many files need post-processing: image compression, thumbnail generation, virus scan, PDF parsing, audio/video transcoding, spreadsheet parsing, or content safety checks.
The file table should have status:
pending_upload
uploaded
processing
ready
failed
deleted
After upload, show “processing” first, then mark it ready when background work finishes.
Design File Permissions Separately
File permissions cannot rely only on hidden URLs.
For private files, access should first go through your business system to check permissions, then generate a temporary access URL or return the file through a controlled download endpoint.
Common permission issues:
User A accesses user B's file
Team member accesses files from deleted projects
Public share link exposes private files
Removed member can still access old files
Temporary URL lasts too long
Files often contain private and business data. Permission design must be more careful than normal pages.
Separate Public and Private Files
Not all files need to be private.
Public avatars, cover images, and article images can live in a public bucket or CDN. Contracts, invoices, import data, user attachments, and internal documents should be private.
Public files optimize speed and caching. Private files optimize permission safety and auditability.
Do not mix all files into one permission model.
Progress and Retry Matter
File upload is different from a normal form. Users wait.
If a large upload has no progress, cancel button, or failure message, users do not know whether the system is stuck.
At minimum, provide:
Upload progress
Uploading state
Failure message
Retry upload
Cancel upload
Size limit hint
Format limit hint
Clear upload experience reduces support issues.
Deletion Needs a Policy
When a user deletes a file, should it be removed from object storage immediately?
It depends on the business. Many systems soft-delete the database record first, then clean object storage asynchronously. This prevents accidental deletion and leaves room for recovery and audit.
Consider:
Can users restore deleted files?
Is the file referenced by multiple objects?
Does object storage have lifecycle rules?
Do orphan files need scheduled cleanup?
Do audit records need to be kept?
File deletion is not just delete, especially in team and paid products.
Estimate Cost Early
File system cost is not only storage.
It also includes upload traffic, download traffic, CDN traffic, image processing, video transcoding, request count, backup, and cross-region replication.
If your product allows large files or videos, cost can rise quickly. Set size limits, quotas, and cleanup rules early.
Do not wait for a surprising bill before adding upload limits.
A File Upload Architecture
Use this structure:
Frontend:
Select file / validate / progress / retry
Backend:
Permission check / create file record / presigned URL / confirm upload
Object storage:
Original file / access control / lifecycle
Background jobs:
Scan / compress / parse / transcode / thumbnail
Database:
Metadata / status / owner / permission / business relation
This is closer to a real system than “one upload endpoint.”
Final Thoughts
The key to file upload is not uploading the file. It is defining clear rules for upload, storage, processing, access, deletion, and audit.
The recommended early structure is: object storage for files, database for metadata, presigned URL for direct upload, background jobs for processing, and separate permission control for access.
Next, we continue with storage choices: How to Choose Image Storage.
评论
0分享你对这一章的想法