DEV Community

Cover image for Create your own serverless image optimizer for Next.js in 5 minutes
Felix Haus
Felix Haus

Posted on • Updated on • Originally published at milli.is

Create your own serverless image optimizer for Next.js in 5 minutes

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.

Architecture diagram of the Terraform module

Serverless AWS stack for image optimization with Next.js

This way we would be able to achieve 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:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# Main AWS region where the resources should be created in
# Should be close to where your Next.js deployment is located
provider "aws" {
  region = "us-east-1"
}

module "next_image_optimizer" {
  source = "milliHQ/next-js-image-optimization/aws"

  next_image_domains = ["example.com", "sub.example.com"]
}

output "domain" {
  value = module.next_image_optimizer.cloudfront_domain_name
}
Enter fullscreen mode Exit fullscreen mode

The 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:

terraform init
terraform apply
Enter fullscreen mode Exit fullscreen mode

After Terraform has finished deploying the module, it shows you the following output on the Terminal:

Apply complete!

Outputs:

domain = "<distribution-id>.cloudfront.net"
Enter fullscreen mode Exit fullscreen mode

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:

module.exports = {
+  images: {
+    path: 'https://<distribution-id>.cloudfront.net/_next/image'
+  },
}
Enter fullscreen mode Exit fullscreen mode

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:

GitHub logo milliHQ / terraform-aws-next-js-image-optimization

A drop-in image optimization loader for Next.js image component powered by AWS Lambda.

Terraform Next.js Image Optimization module for AWS

CI

A drop-in image optimization loader for the Next.js image component next/image.

Notice: If you look for a complete solution to host a Next.js application with Terraform on AWS, please check out our Terraform Next.js module for AWS.

Features

Architecture

The image optimization module is designed as a full stack AWS app It relies on multiple AWS services and connects them to work as a single application:

Architecture overview diagram

Usage

1. Deploy the module to AWS

Initialize the module by creating a main.tf file with the following content (you can place the file in the same directory where your Next.js project…


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.

Discussion (0)