Proper image handling in web and mobile applications is critical to performance, therefore to user experience.

The Problem with Images

Image handling in frontend development is problematic in a number of ways:


Image caching is an absolute requirement in frontend development otherwise each reload will re-download all images.

Caching is simple in theory, but uncertain in practice: one can’t really be sure that all requested images are cached properly especially when dealing with images from different domains/sources (own domain fixable, CDNs are reliable, but what about the rest?)


Images should be delivered in the optimal supported format and size:

  • image format should be adapted to browser support
    • e.g. send WebP when it is supported, otherwise send PNG or JPG
  • image size should be adapted to display size which usually depends on viewport
  • image file should be compressed losslessly

Current observed practices regarding these matters are questionable and impractical: having multiple versions of each image in different formats/sizes, and choosing image format and/or size from frontend.


Image processing, even though doable and even performant in some case, is not the job of a frontend application.

Introducing Thumbor

Thumbor is a smart imaging service. It enables on-demand crop, resizing and flipping of images. It features a very smart detection of important points in the image for better cropping and resizing, using state-of-the-art face and feature detection algorithms.

Thumbor provides a comprehensive features set: image upload, storage, retrieval, caching, and processing (crop, resize, flip, filter).

It comes with a set of plugins (AWS S3, MongoDB, …) and libraries (JavaScript, Python, Ruby, …) adding more features and enabling flexible integration.

Thumbor is installed as pip package (pip install thumbor), executed in CLI as thumbor, and used as following:



Original Image

Original Image

Resized Image


Resized Image

Resized and Blurred Image


Resized and Blurred Image

Proposed Solution

Use Thumbor as intermediate image server for optimal image handling:

  • caches by default (configurable)
  • all processing should be done by Thumbor (crop, resize, filter, …)

and request images with exact display size in frontend:

  • varies from simple (viewport width minus container margin/padding) to tricky (requires some clever code with DOM node width measure, still doable)
  • common frontend framework filter feature is useful to construct Thumbor URL from original image URL (<img src="{{ imgSrc | thumborize }}">, with thumborize a custom filter)