Andrew Welch · Insights · #images #frontend #aws

Published , updated · 5 min read ·

Please consider 🎗 sponsoring me 🎗 to keep writing articles like this.

Setting Up Your Own Image Transform Service

Cre­ate optimized/​transformed images for pen­nies by lever­ag­ing the pow­er of AWS Lamb­da to cre­ate your own Server­less Image Handler

Image trans­forms are a nec­es­sary part of mod­ern web devel­op­ment, because we want to deliv­er opti­mal­ly sized image srcsets to the client browser.

Whether you’re using a serv­er-ren­dered web­site or a JAM­stack set­up, image manip­u­la­tion is some­thing that needs to be done as a part of the process.

Even if you’re using some­thing like Gats­by JS, the work of trans­form­ing images still needs to be done, it just moves to build time. We’re just chang­ing where it gets done.

Unfortunately, image transforms are also very processor intensive.

Many CMS’s and oth­er serv­er-side ren­dered tech­nolo­gies have image trans­forms built into them. How­ev­er this essen­tial­ly means that you’re self-host­ing proces­sor-inten­sive image trans­forms on the same serv­er that you’re using to serve up your website.

If you haven’t run into issues self-host­ing image trans­forms, rest assured that you even­tu­al­ly will.

This is not a recipe for suc­cess in terms of serv­ing up your web­site in a per­for­mant man­ner. I’ve seen some web­servers fall over if the image trans­form cache is ever bro­ken, due to the CPU pow­er required to re-cre­ate the trans­formed images.

Addi­tion­al­ly, most built-in image trans­form sys­tems do not include an image opti­miza­tion phase.

For more infor­ma­tion on the how’s and why’s of image opti­miza­tion, check out my Cre­at­ing Opti­mized Images in Craft CMS arti­cle or the com­pre­hen­sive Essen­tial Image Opti­miza­tion arti­cle from Addy Osmani.

“We should all be automating our image compression.” — Addy Osmani

Because image trans­forms are so proces­sor inten­sive, ser­vices like Imgix and Cloud­i­nary allow you to offload the work to their scal­able servers. Both ser­vices are excel­lent, but they also cost mon­ey, and often do more than we actu­al­ly need.

Link Enter AWS Serverless Image Handler

Ama­zon AWS has offered a Server­less Image Han­dler for a while that allows you to spin up an AWS Lamb­da func­tion to cre­ate your own pri­vate lit­tle image trans­form ser­vice that is inex­pen­sive, fast, and is front­ed by the Cloud­Front con­tent deliv­ery net­work (CDN).

AWS Lamb­da is part of the new wave of server­less” func­tions that allow you to run code in the cloud with­out pro­vi­sion­ing or main­tain­ing a serv­er. It’s inex­pen­sive, and has­sle-free, which is a fan­tas­tic com­bo in my book.

Here’s what the AWS Lamb­da pric­ing looks like:

AWS Lamb­da Pricing

For many small­er sites, you may nev­er leave the free tier.

Under the hood, the AWS Server­less Image Han­dler uses Sharp JS, which is a Node JS pack­age built on high­ly per­for­mant lib­vips image pro­cess­ing library. Here’s an overview what it looks like:

AWS Lamb­da Overview

You can look at all of the code under the hood if you want, but the nice thing is that you don’t have to.

Link Setting up an AWS Serverless Image Handler

The won­der­ful part of all of this is that you can set up your own AWS Lamb­da func­tion with­out hav­ing to do a deep dive in how it all works.

You’ll need some minor expe­ri­ence with AWS, and maybe some sooth­ing music while you wade through the AWS UI/UX, but that’s it!

This is a point & click no-code solution 🎉

This works because you can spin up your ser­vice via AWS Cloud­For­ma­tion that uses pre­fab tem­plates for the cre­ation of a stack that com­pris­es your set­up. This means it’s essen­tial­ly point and click to set every­thing up on the serv­er side:

  • You need to have an Ama­zon AWS account; if you don’t have one, get one
  • Go to the Server­less Image Han­dler page, and click on Launch Solu­tion in AWS Con­sole, then go through the tem­plate setup:

Launch Solu­tion in Man­age­ment Console


You won’t need to change any­thing here, unless you want to use your own cus­tomized tem­plate. Click Next to proceed.

Step 1: Spec­i­fy a Template


Here there might be a few things you might choose to change (don’t wor­ry, you can go back and change these lat­er, too):

  • CORS Options — If you want to enable CORS, you can con­fig­ure it here
  • Image Sources — You need to list the AWS S3 Buck­ets that the Server­less Image Han­dler can access
  • Demo UI — This will cause it to set up a demo UI you can play with to test your API. This is option­al, but I think use­ful when you’re get­ting start­ed. You can delete the Demo resources lat­er on

Click Next to proceed.

Step 2: Spec­i­fy Stack Details


You won’t need to change any­thing here, unless you have a more involved AWS set­up in terms of per­mis­sions & poli­cies. Click Next to proceed.

Step 3: Con­fig­ure Stack Options


There’s noth­ing to change here, you can just see an overview of what you’re going to cre­ate. Click Next to pro­ceed after check­ing the I acknowl­edge that AWS Cloud­For­ma­tion might cre­ate IAM resources with cus­tom names checkbox.

Step 4: Review

If you run into issues, use the Server­less Image Han­dler Deploy­ment Guide as the canon­i­cal source.

Link Using an AWS Serverless Image Handler

Now that you’ve spun up your ser­vice, assum­ing you set up the Demo UI as well, you’ll have the fol­low­ing Cloud­Front dis­tri­b­u­tions set up:

Cloud­Front distributions

  • Image han­dler dis­tri­b­u­tion — this is your Server­less Image Han­dler dis­tri­b­u­tion that you’ll access from your fron­tend code to get your opti­mized, trans­formed images
  • Web­site dis­tri­b­u­tion for solu­tion — this is a dis­tri­b­u­tion cre­at­ed by the Demo UI so you can play with

While this will cre­ate an S3 buck­et for you if you cre­ate the Demo UI, any S3 buck­ets that you need for your actu­al website/​webapp are up to you to create.

Just make sure you then add them to your Cloud­For­ma­tion stack. Typ­i­cal­ly your S3 buck­ets should be com­plete­ly pri­vate, and you set up Cloud­Front dis­tri­b­u­tions as gate­ways to the S3 buckets.

Pro tip: You don’t real­ly want to serve sta­t­ic assets like images out of an S3 buck­et, it’s intend­ed for stor­age, not dis­tri­b­u­tion. Use a CDN dis­tri­b­u­tion lay­er on top of S3, such as CloudFront.

Pro tip: if you don’t see a par­tic­u­lar ser­vice in AWS that you know you have cre­at­ed, make sure you’re in the cor­rect Region.

If you copy the URL to the Demo UI Web­site dis­tri­b­u­tion for solu­tion you’ll get a play­ground you can use to play around:

Server­less Image Han­dler Demo

So the fun thing about the API is that all you need to do is cre­ate a JSON blob of options:

  "bucket": "images.nystudio107",
  "key": "Octagon-Titlarks-House-02.jpg",
  "edits": {
    "resize": {
      "width": 500,
      "height": 300,
      "fit": "cover"
    "grayscale": true,
    "flip": true

Here are the impor­tant top-lev­el keys in the JSON:

  • bucket — This is the id of the S3 buck­et that the source image is in
  • key — This is the path to the source image in the S3 bucket
  • edits — A JSON-ified ver­sion of the Sharp JS API, con­tain­ing the changes you want applied to the image

Then in what­ev­er pro­gram­ming lan­guage you’re using, you just con­vert the JSON to a string, and then base64 encode it into a URL:

There’s an exam­ple of how to do this via JavaScript in the scripts.js that is cre­at­ed in your Demo UI S3 buck­et. Oth­er lan­guages are sim­i­lar­ly triv­ial to do it in.

All of the options that are imple­ment­ed in the Sharp JS API are avail­able to you! All of your trans­form options that would nor­mal­ly be chained func­tions in Sharp JS just are in JSON for­mat in the edits key.

You can resize, crop, rotate, tint, sharp­en, and a whole bunch of oth­er image manip­u­la­tions, includ­ing con­vert­ing between for­mats such as jpeg, webp, png, and tiff.

You have exquis­ite con­trol over the exact encod­ing meth­ods should you want it, and by default, all images are opti­mized for size.

Link Craft CMS Serverless Image Handler

The solu­tion described here works with any frontend/​backend set­up that you might be using.

How­ev­er, if you’re using Craft CMS, the Ima­geOp­ti­mize plu­g­in allows you to switch the Trans­form Method used site-wide to what­ev­er you want, from built-in Craft image trans­forms to Imgix image transforms.

Ver­sion 1.6.0 has added a Sharp trans­form method that works with the afore­men­tioned setup:

The nice thing about it is that you can change over to using dif­fer­ent Trans­form Meth­ods with zero tem­plate changes.

Link Wrapping Up!

That’s all it takes to cre­ate your own AWS Server­less Image Han­dler! Try it for a personal/​demo site to gain con­fi­dence in how to set things up, and then away you go.

It real­ly is very inex­pen­sive com­pared to services:

Yes, you’ll have to wade through a bit of AWS UX/UI that’s not fun, and learn a bit about AWS per­mis­sions… but I think it’s absolute­ly worth the effort.

Whether you’re using a serv­er-ren­dered solu­tion, a JAM­stack solu­tion, or some­thing like Gats­by, you’ll ben­e­fit. No mat­ter where the work of image trans­form­ing is done, a Server­less Image Han­dler will speed up the process.

Not only will you be able to offload CPU inten­sive image optimization/​transformation to your AWS Lamb­da func­tion, but you prob­a­bly can then down­size your serv­er (assum­ing you have one).

Addi­tion­al­ly, you’ll be learn­ing a bit of AWS in the process, which is a good thing to be famil­iar with in our business.

Hap­py transforming!