AWS CDK For Noobs: Deploying NextJS Apps
Tags: aws, cdk, nextjs, deployment
Published: 2024-01-24 08:41:22

As a software developer, have you ever wanted to deploy your personal projects to AWS instead of PaaS providers like Netlify or Heroku, but do not want to go through setting up everything manually through the AWS console or learning to write infrastructure-as-code?

**Then, you are the target audience for AWS Cloud Development Kit (CDK).**

> This post is part of my commitment to _[Women Who Code Days of Code challenge](https://hopin.com/events/wwcode-days-of-code/registration)_✨

## What is AWS CDK?

It is an AWS development framework for provisioning cloud infrastructure using programming languages **_familiar_** to software developers. 

Simply put, it's a tool for software developers to deploy their apps onto AWS without manually setting up resources through the console, or writing declarative/imperative infrastructure-as-code.

In this post, I'll share all about my first experience with CDK and how I eventually deployed the most basic NextJS app.

### First Attempt

I first tried it last month by starting with the free [AWS CDK Primer course](https://explore.skillbuilder.aws/learn/course/1475/aws-cloud-development-kit-primer) on Skills Builder; however, the course mostly covered the theory basics and a broad overview of how it may be used. There was not much insights on how it could be used for practical projects e.g deploying a full-stack app (which is understandable, since it was a **_free_** primer course).

Then, I tried using the [learning path on Cloud Academy](https://cloudacademy.com/learning-paths/aws-cdk-v2-7518/) but it quickly became disengaging since the contents were focused on Python (hence a different version of the API docs) and I preferred Typescript. Overall, I found myself quite lost, trying to figure out the "right" thing to do according to the docs, and if there was only one way to do it. Meanwhile, every other tutorial (even the basic ones) seemed to already know their way around navigating the necessary construct libraries.

I eventually tried [this tutorial](https://www.youtube.com/watch?v=YL2feD9ws9k) to get something done (at least) and was able to deploy a basic NextJS app.

## How to set up a CDK app for deploying a NextJS app to AWS Amplify
This assumes you have:

- installed the AWS CDK toolkit,

- installed Typescript (somehow, this was my first time doing this!),

- configured your AWS credentials, and

- generated a GitHub PAT and saved to AWS secrets manager.

> If necessary, watch the linked tutorial for all preliminary setup.

### 1) Create an empty folder (_e.g cdk-next-app_) and set up a CDK app

> `cdk init app --language typescript
> `

The _'app'_ template sets up a basic CDK app in _language_ Typescript.

### 2) Set up your preferred environment in `bin/cdk-next-app.ts`

This is optional but I personally think it might be best to specify and avoid the 'environment agnostic' situation.

```
COPY

COPY
import * as cdk from 'aws-cdk-lib';
import { CdkNextAppStack } from '../lib/cdk-next-app-stack';

const app = new cdk.App();
new CdkNextAppStack(app, 'CdkNextAppStack', {
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
```

This creates your CDK app and within it, a stack which will have all of the constructs needed to provision infrastructure for the Next app and deploy it to AWS Amplify.

> Check out the [Primer course](https://explore.skillbuilder.aws/learn/course/1475/aws-cloud-development-kit-primer) for AWS CDK basics.

### 3) Set up the stack in `lib/cdk-next-app-stack.ts`

**Note:** This uses `@aws-cdk/aws-amplify-alpha`, which is basically the construct library with experimental features for Amplify using CDK. The current stable version does not have L2 constructs (constructs for provisioning AWS resources) yet, so the option was either the experimental library or setting everything up using L1 constructs (which I would have to look into👀).

> _Comments have been added to briefly explain the codes._


```
COPY

COPY
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import {
  App,
  GitHubSourceCodeProvider,
  Platform,
  RedirectStatus
} from "@aws-cdk/aws-amplify-alpha";
import * as codebuild from 'aws-cdk-lib/aws-codebuild';

export class CdkNextAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    //create a new Amplify app
    const amplifyApp = new App(this, 'NextApp', {
      //set a code source provider for the app to be deployed e.g GitHub
      sourceCodeProvider: new GitHubSourceCodeProvider({
        //requires all three properties
        owner: 'khairahscorner',
        repository: 'sample-next-app',
        oauthToken: cdk.SecretValue.secretsManager('github-token-cdk'),
      }),
      autoBranchDeletion: true,
      platform: Platform.WEB_COMPUTE, //required for SSR apps 
      customRules: [{ //used to avoid page errors by redirecting them
        source: '/<*>',
        target: '/index.html',
        status: RedirectStatus.NOT_FOUND_REWRITE
      }],
      buildSpec: codebuild.BuildSpec.fromObjectToYaml({
          // Alternatively add a `amplify.yml` to the repo
          version: '1.0',
          frontend: {
            phases: {
              preBuild: {
                commands: ['npm ci'],
              },
              build: {
                commands: ['npm run build'],
              },
            },
            artifacts: {
              baseDirectory: '.next',
              files: ['**/*'],
            },
            // save time on npm reinstalling??
            cache: {
              paths: ['node_modules/**/*'],
            }
          }
      }),
    })

    // branch to deploy
    let branchName = 'main';
    amplifyApp.addBranch(branchName)

    //outputs the url to both your console and Outputs in the CF stack
    new cdk.CfnOutput(this, 'AmplifyAppUrl', {
      value: `https://${branchName}.${amplifyApp.appId}.amplifyapp.com`,
      description: 'Amplify App URL',
    });
    }
}
```

### 4) (Optional) Run `cdk bootstrap` and `cdk synth`

`cdk bootstrap` is used to setup necessary resources required to store and manage the deployment artifacts for your CDK app. Run this if it's your first time using AWS CDK, else it uses the existing setup on your AWS account.

`cdk synth` generates the AWS CloudFormation template version of your code, just to have a look through.

### 5) Deploy your app with `cdk deploy`


![CDK deploy terminal message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k09v9jzgpop60axq7jqk.png)

_**That's it!**_

![Next app deployed with AWS CDK](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gl80cc7qu1xam4jsl6r.png)

## Pitfalls to Avoid


#### 1) Ensure you have installed and authorised the AWS Amplify GitHub App.

I previously installed and authorised it for only one repository, so I encountered a permissions error and eventually fixed it by authorising the current repository.

#### 2) AWS Amplify seems to run with node v16 (with support up to v18.13).

However, Next14 requires a minimum of node v18.17, hence I was getting this error despite trying different fixes.


![Next14 error with Amplify](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x84tx32s2e3sqiqj7578.png)

In the end, I downgraded to next13 and it worked, but do let me know if you know of a workaround for next14.

## Up Next

I'll be trying more sample app deployments with CDK and maybe even explore [CDK for Terraform](https://github.com/hashicorp/terraform-cdk).

---

**_Thanks for reading!_**