How to deploy a Nextjs app with AWS CDK

Steve Mu
2 min readMar 7, 2023

--

In one of my projects, I used AWS CDK to deploy a Nextjs app. In this article, I am going to share how it was done.

First, you would need to create an AWS CDK project.

What is AWS CDK?

AWS CDK (not SDK) is an IaC tool and is an abstraction on top of CloudFormation. AWS CDK allows you to write IaC with TypeScript (among other supported languages) and I found it was easier to use than Terraform.

To use AWS CDK, you would need to create a CDK project. An AWS CDK project is a normal npm package or project and has a package.json to store the dependencies of an AWS CDK project.

To learn the AWS CDK, you can watch the workshop.

Here is the boilerplate of my AWS CDK project if you wish to use it in your project:

/bin/demo.ts:

import * as cdk from 'aws-cdk-lib';
import { DemoStack } from '../lib/demo-stack';

const app = new cdk.App();
const imageTag: string | undefined = app.node.tryGetContext('imageTag');

if (!imageTag) {
throw new Error('imageTag not found')
}
// console.log(`using imageTag: ${imageTag}`)
new DemoStack(app, 'DemoStack', {env: {account: 'aws-account-id', region: 'us-east-1'}, imageTag});

/lib/demo-stack.ts:


import { Construct } from 'constructs';
import * as ecsPatterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Stack, StackProps } from 'aws-cdk-lib';
import { HostedZone } from 'aws-cdk-lib/aws-route53';
import { ApplicationProtocol } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { Repository } from 'aws-cdk-lib/aws-ecr';
import { ContainerImage } from 'aws-cdk-lib/aws-ecs';

export interface DemoStackProps extends StackProps {
imageTag: string;
}

export class DemoStack extends Stack {
constructor(scope: Construct, id: string, props?: DemoStackProps) {
super(scope, id, props);

const repository = Repository.fromRepositoryName(
this,
'id',
'repositoryName'
);

const image = ContainerImage.fromEcrRepository(repository, props?.imageTag);

new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'DemoEcsService', {
memoryLimitMiB: 1024,
desiredCount: 1,
cpu: 512,
assignPublicIp: true,
taskImageOptions: {
image,
containerPort: 3000,
},
taskSubnets: {
subnets: [ec2.Subnet.fromSubnetId(this, 'subnet', 'subnet-xxx')],
},
vpc: ec2.Vpc.fromLookup(this, 'DefaultVPC', {isDefault: true}),
domainName: 'demo.com',
domainZone: HostedZone.fromLookup(this, 'DemoZone', {
domainName: 'demo.com'
}),
redirectHTTP: true,
protocol: ApplicationProtocol.HTTPS,
});
}
}

This boilerplate does the following things:

  • it reads a container image tag from the command line
  • it goes to a prefined a AWS ECR to find the image with the tag provided
  • it creates a fargate service with the image provided with a custom domain

The command to deploy is:

cdk deploy - require-approval=never -c imageTag=$imageTag

For a full project demo, please check out this repo.

--

--