Amazon S3 is often the default choice when teams need to store and serve images. It's widely available, integrates with other AWS services, and appears cost-effective at first glance. But once you move past basic file storage, building a production-grade image system on top of S3 introduces significant complexity and ongoing maintenance burden.
This post outlines the common pitfalls of S3-based image pipelines and compares them to purpose-built alternatives.
1. S3 is just storage, not a system
S3 is an object store. It does not provide any image-specific functionality, like URL-based transforms or CDN delivery, out of the box. Developers must build or bolt on additional components to meet even basic image infrastructure requirements.
2. No Support for Temporary Uploads
S3 does not support auto-expiring files. Any temporary image uploads (e.g. tied to user form submissions) will remain until explicitly deleted. This leads to:
- Orphaned images from abandoned sessions
- Increased and unnecessary storage costs over time
- The need to implement background jobs (e.g. Lambda, cron) for cleanup
In order to circumvent this, you need to implement a custom solution with presigned URLs, lifecycle rules and manually copying objects from location to another.
3. Metadata Is Immutable
S3 object metadata cannot be modified after upload. If you need to update image metadata (e.g. related user ID, account ID, etc.):
- You must re-upload the image with updated metadata
- Or maintain a separate metadata database
- There is no native way to query images by metadata fields
While your metadata-based queries should probably live in a dedicated database anyway, it is a nuisance not to be able to assign a helpful piece of metadata to an image after it has been uploaded.
4. No Built-in Image Transformations
S3 does not offer any built-in image transformation capabilities. Features such as:
- Resizing
- Format conversion (e.g. PNG to WebP)
- Cropping
- Quality optimization
Meaning, these must be handled through separate tools such as a capable CDN layer in front of the bucket.
Or… building custom using something like AWS Lambda with ImageMagick or Sharp. But surely such a solved problem is not what you want to spend development time on.
5. No Native CDN Behavior
To serve images globally with caching, CloudFront must be configured separately. This setup includes:
- Defining cache behaviors and origin policies
- Managing signed URLs if access control is needed
- Manual cache invalidation when images are updated
Sounds simple, but it can be a surprising amount of work to get right.
6. Access Control Is Overly Complex
S3's access model is IAM-based. Implementing project-scoped access is not as straightforwad as with simple API keys.
Additionally, for client-facing public upload URLs, generating presigned URLs is required.
7. Unpredictable Costs
While S3 storage is inexpensive and scales linearly with usage, costs can easily balloon due to egress costs (granted, there is a generous free tier).
8. Comparison: S3-Based Stack vs Icefiery
Feature | S3-Based Stack | Icefiery |
---|---|---|
Temporary Uploads | Requires custom cleanup logic | Built-in auto-expiry (24h default) |
Metadata Editing | Not supported | Editable via API |
Image Transformations | Requires external tools (e.g. Lambda or external CDN product) | Built-in via CDN URL params |
CDN Setup | Requires manual CloudFront config | Built-in, zero-config CDN |
Local Development | Possible with e.g. MinIO | Fully runnable with Docker |
Access Control | IAM or signed URLs | Project-scoped API keys |
Cost Model | Multiple variables (storage, egress) | Simple monthly subscription |
Dev Experience | Multi-step, fragmented | Simple upload → transform → serve pipeline |
9. Conclusion
Developers generally default to "let's use S3" when they need to store images.
But it actually gets quite a bit more complicated than that.
Most of what a modern app needs, i.e. temporary uploads, image transformations, metadata editing, CDN delivery, scoped access and local development, are not natively supported by S3. These features must be added manually.
If your team is building software, not image CDN infrastructure, consider using a dedicated image CDN like Icefiery.