- Small, structured metadata: who posted it, the caption, upload time, like count — data you query and join.
- The large image file: the multi-megabyte binary (pixels) produced by Alan’s phone camera.

- Relational databases such as PostgreSQL are optimized for many small, structured rows and fast relational queries.
- A photo’s metadata row is typically a few hundred bytes. If you embed a 15 MB binary in that row, tables that should be gigabytes will balloon to terabytes.
- Large binaries increase backup times, slow down replication and queries, and complicate scaling and maintenance.

- Store the small, structured metadata (caption, owner, upload time, like count) in your SQL database.
- Store the large image file in object storage (designed for large, durable blobs). The most common example is Amazon S3.
- Save the object location (object key or URL) in the database so metadata points to the file’s location.

How the upload flow should work (end-to-end)
- Alan selects and uploads an image from the app.
- The app or app server writes the raw image file to object storage.
- Object storage returns an object key or URL for the uploaded file.
- The app writes one small row in the database containing owner, caption, upload time, and that object location.
- To avoid routing the 15 MB binary through your app servers, have your backend issue a pre-signed URL that allows the client to upload directly to object storage.
- A pre-signed URL grants a temporary, scoped permission to upload to a specific object key, so the heavy upload goes straight from the client to S3.
- Advantages: reduced bandwidth and CPU usage on your servers and faster perceived upload time for the user.

- Users expect the feed to feel instant even if the full upload takes a few seconds.
- Serving a 15 MB original inline in a scrolling feed is unacceptable. Instead create multiple resized variants:
- Tiny thumbnails for the feed (fast, low bandwidth).
- Medium images for the post detail view.
- The original/high-quality image for downloads or zoom.
- Image resizing is CPU-intensive. Don’t block the user’s upload on resizing. Instead:
- Record the metadata and original object reference immediately.
- Return success to the client.
- Enqueue background work to create resized variants and store them back to object storage.

- Upload the original to object storage (or issue a pre-signed URL and let the client upload).
- Write small metadata records to the database with the object location.
- Offload resizing, transcoding, and other heavy tasks to background workers.
- Keep large files in object storage (
S3). - Keep small, structured metadata in your database (
PostgreSQL) with a reference to the file. - Offload slow processing (resizing, transcodes) to background workers to keep the request path fast.

Never store large binary files in your transactional database. Use object storage for big blobs and move slow, CPU-bound processing off the user-facing request path.
- Amazon S3 pre-signed URLs: https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html
- PostgreSQL documentation: https://www.postgresql.org
- Object storage design patterns and best practices: search for “object storage vs relational database for media” for architecture guides and examples.