A folder and a transformation are the same object

24 August 2026

Every file system has folders. Every image service has transformations. They are usually separate ideas: the folder is where you put it, the transformation is what you ask for later.

Keeping them separate is what makes upload code tangled, because in practice the two always agree. Everything in avatars/ is 400x400. Everything in receipts/ is a PDF nobody outside the account may read. The folder already implies the rule; the code just has to remember it.

Where the rule ends up living

Split across three places, typically:

being images.

  • The upload handler knows that avatars go to avatars/ and are checked for
  • The render code knows that avatars are requested at w_400,h_400.
  • The bucket policy knows that receipts/ is not public.

Nothing enforces that those three agree. A new endpoint uploads to avatars/ without the check. A component asks for w_300 because that is what its design needed. A prefix gets renamed and the policy does not follow. Each is a small mistake and each is invisible until something is the wrong size or the wrong person opens a receipt.

Merging them

A template is one object holding all three:

{
  "name": "Avatar",
  "accepts": "image",
  "width": 400,
  "height": 400,
  "format": "webp",
  "public": true
}

It is a folder, because files live in it and you can browse it. It is a transformation, because everything that goes in comes out 400x400 webp. It is a policy, because public decides who may read what is inside. Uploading to it is naming all three at once:

curl -X POST -F "img=@./whatever.png" \
  -H "Authorization: Bearer $FILEMON_KEY" \
  https://filemon.io/api/m1o900k8

There is no size in that request and no rule in that request. The destination carries them.

What this makes easy

Bulk changes. Because a folder is a transformation, "make every avatar smaller" is a property change plus a re-run over the originals, not a script that walks a prefix and guesses which files were avatars.

Honest restrictions. accepts: "image" is checked against the bytes when the file arrives, not against a filename, and not in three separate handlers.

Moving a file. Changing a file's folder means changing its shape, so a move re-runs the pipeline from the stored original and returns a new id. That sounds like a downside and is really the model being honest: a 400x400 avatar and a 1200px product shot are not the same bytes in two places.

What it costs

Flexibility you might miss. You cannot ask for an arbitrary size at render time, because sizes are properties of folders and folders are made deliberately. If your product lets users choose dimensions, this model fights you.

For everything else, which is most software, the sizes were decided once in a design file and have not changed since. Writing them down in the same object that says where the file lives is not a limitation. It is the thing your code was doing anyway, in three places, hoping they matched.

Try it on your own files

Filemon resizes and converts on upload, so the URL you get back is already the finished file. The free plan needs no card.

Create an account · Read the documentation