Most file services give you an opaque id and a table that maps it to a location. Serving a file is then two steps: look up where it is, then fetch it. The lookup is fast, and it is still a database on the critical path of every image on every page.
There is another option: put the location in the id.
The shape
Sixteen alphanumeric characters, four segments:
m1o9 00 k8 Zt8fLm3v
│ │ │ └ random
│ │ └ template
│ └ project
└ accountEach segment is fixed width, so the id splits with slices rather than a parser, and the storage key falls out of it:
m1o900k8Zt8fLm3v -> m1o900/k8/Zt8fLm3v
m1o900/k8/preview/Zt8fLm3vA read is now: check the id is well formed, slice it, fetch that key. No query, no cache to keep warm, no table that has to be up for images to load.
What each segment buys
The account is the top-level folder, so everything one customer owns shares a prefix. Deleting an account is a prefix delete. Listing their storage is a prefix list. No WHERE user_id = involved.
The project groups templates for people who need it, and is reserved at 00 for everyone else. That is the interesting one: it costs two characters today and it means multi-tenancy can arrive later without invalidating a single URL that has been handed out. Ids are permanent, so the room has to be booked before anybody needs it.
The template says which transformation made this file, which is why the same suffix under a different template segment is a different version of the same upload.
The random part is the only unguessable bit, and it is doing the security work for public files. Eight characters is 218 trillion, so finding one by guessing takes longer than caring about it.
The trick that comes free
Template 00 is the passthrough, so the original of any file is the same id with 00 in the template segment:
m1o900k8Zt8fLm3v the file, as the template made it
m1o90000Zt8fLm3v the same upload, untouchedThere is no route for originals, no ?original=true, and nothing to store. The address is derived, so it costs nothing and cannot get out of sync.
That does impose one rule, which is worth stating because it is invisible until it bites: two files of the same account and project may never share a random suffix, or one would address the other's original. Allocation checks for that and retries.
The cost of the decision
The id is permanent, so its layout is permanent. Four characters of account is 14.8 million accounts, and if that is ever wrong there is no migration, only a second scheme running alongside the first. Every width in that diagram is a bet that cannot be re-taken.
That is the real trade against the opaque id and the lookup table. The table can be reshaped on a Tuesday. The id cannot be reshaped at all. What you get for that is a URL that resolves to bytes without asking anything, and the ability to delete a customer's entire storage with one prefix.