With the introduction of Next.js 10 the new
next/image component was added. It is a modern approach to enhance the
<img> HTML-Element by adjusting the image based on the viewer’s needs. By recognizing what image extensions (e.g. newer formats like WebP) the client browser supports, it converts the source accordingly and also resizes the image optimized for the screen width of the viewer.
The optimization itself is performed on the fly when the resource is requested by the user. This makes the solution perfectly scalable whether it is used for 10 or 10 million images.
But what if you self-host your app as a single server or inside a docker container? Spinning up more instances just to deal with the increased traffic caused by image processing can be pretty expensive.
Fortunately the Next.js developers have a solution for this: You can use a cloud-based external image loader to perform this task. Currently Imgix, Cloudinary and Akamai are officially supported.
Since we were already using Amazon Web Services (AWS) we thought about how we could bring this service directly to their platform without relying on third-party cloud services. The basic idea was to isolate the part from Next.js core responsible for the image optimization, pack it into a serverless function (AWS Lambda) and use it as an external loader.
This way we would be able to archive full support of all
next/image features and a maximum of scalability because AWS Lambda can scale up and down dynamically to met the demand. Since we do not want to run the serverless function on every request we put it behind a CloudFront distribution that is able to serve recurring requests for the same resources from cache. It also makes the whole thing noticeably faster since CloudFront CDN network is able to store the cache close the viewers location.
Because we are already manage most of our DevOps stack with Terraform, we also used it to create the image optimizer. This also makes it possible to share the whole module so that it can easily be reused.
Deploy the serverless image optimizer to AWS
All you need to create your own image optimizer in 5 minutes is an AWS account and Terraform installed.
Then create a new file called
main.tf(Can be added to the same directory as your Next.js app), which contains the definition and configuration of the module:
next_image_domains variable should contain the domains where the external images should be fetched from. It takes the same configuration as the Domains setting from Next.js.
After that you are all set to deploy the module to your AWS account. All you need to do is running the two Terraform commands:
After Terraform has finished deploying the module, it shows you the following output on the Terminal:
Apply complete!Outputs:domain = "<distribution-id>.cloudfront.net"
The domain of the CloudFront distribution (
"<distribution-id.cloudfront.net") is all you need to tell your Next.js app to use the newly created image optimizer. Open or create your
next.config.js and add the following lines:
Last step is now to redeploy your Next.js app with the changed configuration. Now you are using your own, self-hosted image optimizer.
You can take look at the source code of the module on GitHub, since everything is Open Source:
Looking for a full stack solution to deploy Next.js on AWS?
If you don’t want to mess around with configuration and want a complete solution to host Next.js serverless on AWS, please checkout our Terraform Next.js module for AWS. It has image optimization already built in and can handle most features from Next.js in a cost-efficient way.