Easily deploy TypeScript project to AWS Lambda using Github Actions
Tags: typescript, tutorial, aws, github
Published: 2021-04-07 13:43:15

I recently worked on a small TypeScript project which I wanted to deploy as a Lambda to AWS.

My project had **multiple files** and some **npm dependencies**.

I found some resources online, but none of them really hit the spot.

Some didn’t explain how to include the `node_modules`, some didn’t explain how to do it with TypeScript and some just handled a single file.

In this post, I’ll describe how to prepare the project for deployment and show a detailed example of doing it using Github Actions.

#Project Structure#

Let’s assume our project structure looks like this:

``` 
 ├── package.json
 ├── tsconfig.json
 ├── node_modules
 │    ├── module_1
 │    ├── module_2
 │    └── etc..
 └── src
      ├── index.ts
      └── utils.ts
```

This is our `tsconfig.json`:

```
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2017",
    "lib": ["ES2019"],
    "rootDir": "src",
    "outDir": "dist",
    "declaration": false, 
    "sourceMap": false,
    "inlineSources": false,
    "types": ["node"]
  }
}
```

And `index.ts` contains as the main `handler`, and uses `utils.ts`, something like this:

```
import { APIGatewayEvent, Context } from 'aws-lambda';
import { doSomething } from './utils';

export const handler = async (event: APIGatewayEvent, context: Context) => { 
    doSomething();
    // Do some other stuff…
 }
```

#Problem#

AWS Lamda can only run **js** files!

Also, AWS Lambda can’t install `node_modules` for us.

With the default settings, AWS Lambda supports either:

* Deploying a single `index.js` file directly.
* Upload a **zip** file containing all the project files, which has the `index.js` in the zip root. 

So we need to zip the project correctly, without including the parent directory.

We also need to make sure the `node_modules` are part of this zip file.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ndo6g3lq3dersqz30j2n.jpeg)

#Prepare for deployment#

##1. Build the project##
We will use TypeScript’s `tsc` command to transpile the project into js files.

After building, this will be our project structure:
```
├── package.json
├── tsconfig.json
├── node_modules
├── dist
│    ├── index.js
│    └── utils.js
└── src
     ├── index.ts
     └── utils.ts
```

##2. Move node_modules to dist folder##

As mentioned before, AWS Lambda can’t install the node_modules for us, so we need to assure they are located correctly before creating our zip file.

#3. ZIP##

The project needs to be zipped in the required structure, **without the parent directory**. The easiest way I found to do it, is to run the following command from the project root:

```$ (cd dist && zip -r ../function.zip .)```

The zip is now ready for deployment.

#Deploy using Github Actions#

The deployment part will be done using [appleboy/lambda-action](https://github.com/marketplace/actions/aws-lambda-deploy), and can be easily substituted with a corresponding AWS CLI command, which comes preinstalled on Github Actions CI machines.

Here’s a detailed example of a Github action:
```
name: Deploy

on:
  push:
    branches: [ master ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v2

      - name: Install Dependencies
        run: yarn

        # build command should be set in your package.json scripts as: "build": "tsc"
      - name: Build
        run: yarn build

      - name: Move node_modules to dist
        run: mv node_modules dist/node_modules

      - name: Zip
        run: (cd dist && zip -r ../function.zip .)

      - name: Deploy to AWS
        uses: appleboy/lambda-action@master
        with:
          aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws_region: ${{ secrets.AWS_REGION }}
          function_name: my-cool-function
          zip_file: function.zip
```

That’s it! Your Lambda is now ready for work.

We post tutorials like this weekly on Aspecto [blog](https://www.aspecto.io/blog/?utm_source=dev.to&utm_medium=referral&utm_campaign=deploy-typescript-to-aws-lambda)!

Check out one of our latest tutorials - **[How to Send Large SQS/SNS Messages with Node.js](https://www.aspecto.io/blog/how-to-send-large-sqs-sns-messages-with-node-js/?utm_source=dev.to&utm_medium=referral&utm_campaign=deploy-typescript-to-aws-lambda)**