Skip to content

Setup

During the setup phase, you’re going to:

  • Setup a Git repository where this project will live.
  • Install all required dependencies (if you haven’t already).
  • Set up the NodeJS application that you’re going to deploy to the cloud.
  • Acquire the assets used for the application.

Let’s get building!

Create a new Git project where we’re going to store the IaC for our live infrastructure.

Terminal window
mkdir terralith-to-terragrunt
cd terralith-to-terragrunt
git init

(Assuming you are using it) Use mise to download, install and pin the version of tools you’re going to use in this project.

Terminal window
mise use terragrunt@0.83.2
mise use opentofu@1.10.3
mise use aws@2.27.63
mise use node@22.17.1

You should now have a local mise.toml file that looks like the following with all the tools pinned that you need.

mise.toml
[tools]
aws = "2.27.63"
node = "22.17.1"
opentofu = "1.10.3"
terragrunt = "0.83.2"

Now that you have the tools installed that are going to be used for this project, you’ll want to setup the application we’re going to be managing throughout the project.

It’s not a very interesting application (it was vibe coded pretty quickly), and the details of how it works aren’t that important to the topic of this blog post. Corners were also cut when designing the application to minimize the resources you have to provision, so don’t design any of your applications based on what you see there.

Create the application directory structure

Section titled “Create the application directory structure”

First, create the application directory structure:

Terminal window
mkdir -p app/best-cat
cd app/best-cat

Next, copy the application files into the new directory you just created.

{
"name": "best-cat",
"version": "1.0.0",
"description": "Vote for the best cat",
"main": "index.js",
"type": "module",
"scripts": {
"package": "zip -r ../../dist/best-cat.zip . -x '*.git*' 'node_modules/.cache/*'"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.420.0",
"@aws-sdk/client-dynamodb": "^3.420.0",
"@aws-sdk/lib-dynamodb": "^3.420.0",
"@aws-sdk/s3-request-presigner": "^3.420.0",
"handlebars": "^4.7.8"
},
"engines": {
"node": ">=22.0.0"
}
}

You should end up with an app/best-cat directory that looks like this:

  • Directoryapp
    • Directorybest-cat
      • index.js
      • package-lock.json
      • package.json
      • script.js
      • styles.css
      • template.html

Once you have the app stored in app/best-cat, you’ll want to create the dist directory, then package the application for delivery to a lambda function.

Terminal window
mkdir dist
cd app/best-cat
npm i
npm run package

I also recommend adding the following .gitignore file to your dist directory so you don’t accidentally commit any other content in this directory to your repository:

dist/.gitignore
*
!.gitignore

You’ll also want some assets to use in this project to make it more fun. I generated a bunch of cat pictures using Gemini, but feel free to use stock photos or something else to generate the assets.

I would recommend that you place the images in the same location I did (dist/static), so that the convenience scripts I wrote work out of the box without modification.

This is what my dist directory looks like after following these steps:

  • Directorydist
    • best-cat.zip
    • Directorystatic
      • 01-cat.png
      • 02-cat.png
      • 03-cat.png
      • 04-cat.png
      • 05-cat.png
      • 06-cat.png
      • 07-cat.png
      • 08-cat.png
      • 09-cat.png
      • 10-cat.png

Our end goal is to host a site that looks like this in AWS using these artifacts:

terralith-to-terragrunt-app-goal