The standard architecture for thumbnails is a queue. The upload endpoint stores the file and publishes a message, a worker picks it up, resizes, writes the result, and updates a row. The UI shows a spinner, or a placeholder, or the image pops in later.
It is a lot of moving parts for an operation that takes about as long as loading the page you are already waiting for.
How slow is it really
Resizing a photo from a phone, eight or twelve megapixels, to a 400x400 webp takes tens of milliseconds with a modern encoder. Reading and writing the bytes takes longer than the resize. A PDF's first page is slower, a few hundred milliseconds, still well inside what a form submit can absorb.
Against that, here is what the queue adds: a broker to run, a worker to deploy, retry and dead-letter handling, a "processing" state in your database, a UI for that state, and a class of bug where a file exists but its thumbnail never arrived and nothing notices.
Do it in the request
If the work is short, do it while the caller waits, and hand back something finished:
curl -X POST -F "img=@./photo.jpg" \
-H "Authorization: Bearer $FILEMON_KEY" \
https://filemon.io/api/m1o900k8
{ "id": "m1o900k8Zt8fLm3v", "url": "https://filemon.io/api/m1o900k8Zt8fLm3v" }By the time that response arrives, the resized file, its thumbnail and the untouched original are all stored. There is no pending state, because there is nothing pending. The URL in the response works immediately, which means your code can write it to the database and render it in the same request.
The thumbnail is a URL derived from the id, not a second thing to track:
https://filemon.io/api/m1o900k8Zt8fLm3v/previewWhat you lose
Two things, honestly.
Long jobs. Transcoding a two hour video is not a request, it is a job, and it wants a queue. The rule is roughly: under a second, do it inline; over ten seconds, queue it; in between, measure.
Burst absorption. A queue lets a spike of a thousand uploads drain at whatever rate your workers manage. Inline, a thousand simultaneous uploads are a thousand simultaneous resizes. For most products that spike never comes, and when it does, the answer is a bigger box before it is a queue.
The state you avoid
The real win is not the deleted infrastructure, it is the deleted state. "File uploaded, thumbnail pending" is a state your database has to hold, your API has to expose, your UI has to render, and your support team has to explain. Every feature that touches files has to know about it.
Doing the work while the caller waits deletes that entire branch. A file either exists, complete, or the upload failed and there is nothing. Two states instead of three, and the third was the one that caused all the trouble.