How to Deploy to AWS Lambda from CircleCI

Amazon Web Services Web Development

I received a question on Hashnode this morning from someone who's having trouble finding a way to deploy to AWS Lambda.

I am using CircleCI as a CI/CD tool to deploy to AWS S3. While there are commands provided for deploying to S3 bucket and EC2, I found no commands for deploying to Lambda. Is there a way to directly deploy to AWS Lambda using CircleCI?

Absolutely, yes, there is a way to deploy to AWS Lambda.

The CircleCI documentation portal doesn't currently have an example. However, the answers can be found in the AWS documentation.

Let me show you how I do it.

Function Creation First

The first thing to point out is that the creation of a Lambda function is a one-time step (or at least once per function). I haven't found function creation worth automating so I do it manually through the AWS console.

Once your Lambda function is created, you've got at least two good options for updating it: the command line interface and the AWS SDK.

Updating Using the Command Line Interface

The CLI tools can be downloaded from https://aws.amazon.com/cli/ and the command we want is lambda update-function-code.

You can update from an S3 bucket:

update-function-code \  --function-name helloWorld \  --s3-bucket MyBucket \  --s3-key builds/helloWorld.zip

Or you might want to update directly from your build machine:

update-function-code \  --function-name helloWorld \  --zip-file helloWorld.zip

Updating Using the AWS SDK

My continuous integration/deployment infrastructure predates Lambda support in the CLI. :(

Instead of the CLI, I currently use the AWS Lambda SDK for JavaScript to update my functions.

I use a deployment script, written in JavaScript, that zips up my ./dist folder and then uploads it to AWS.

bin/deploy.js

const fs = require('fs');const AdmZip = require('adm-zip');const AWS = require('aws-sdk');const zipper = new AdmZip();console.log('Zipping ./dist directory...');// Note: Does NOT work on Windows! See https://github.com/cthackers/adm-zip/pull/132zipper.addLocalFolder('dist', '');zipper.toBuffer(zipBuffer => {    console.log('Successfully created zip buffer');    const lambda = new AWS.Lambda({        apiVersion: '2015-03-31',        region: 'us-east-1', // Or whichever region you use        maxRetries: 3,        sslEnabled: true,        logger: console,    });    const params = {        FunctionName: 'helloWorld',        Publish: false,        ZipFile: zipBuffer,    };    lambda.updateFunctionCode(params, err => {        if (err) {            console.error(err);            process.exit(3);        }    });}, errString => {    console.error(`Failed to create zip buffer: ${errString}`);    process.exit(2);}, filename => {    console.log(`Zipping ${filename}...`);});

Now that you've got a deployment script or a handy command line, it's time to integrate with your build system.

Update package.json

Add the script and its dependencies into package.json.

(You can skip this step if you're doing the zipping and uploading from the command line).

package.json

{  "name": "helloWorld",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {    "deploy-production": "node bin/deploy.js",    //...  },  "dependencies": {    "adm-zip": "^0.4.7",    "aws-sdk": "^2.119.0",    //...  }}

Update circle.yml

circle.yml is a special file that sits in your project's root directory and instructs CircleCI how to build, test, and deploy your project.

This is a basic YAML file that nails down the Node.js and NPM versions, downloads dependencies, builds, and then calls our script to handle the actual deployment.

circle.yml

machine:    node:        version: 6.10.0    npm:        version: 4.0.5dependencies:    pre:        - sudo apt-get update    override:        - npm install --no-optional        - npm run builddeployment:    production:        branch: master        commands:            - npm run deploy-productiongeneral:    branches:        only:            - master

Alternate circle.yml

In theory, it should be trivial to replace the deploy script with a command to zip the directory and another command to update-function-code via the AWS CLI tools.

In fact, you should be able to follow the steps in Continuous Deployment With Amazon S3 and then add an extra command to update Lambda from S3 like this:

circle.yml

#...deployment:    prod:        branch: master        commands:            - aws s3 sync builds/helloWorld.zip s3://mybucket/builds --delete            - aws lambda update-function-code --function-name helloWorld --s3-bucket MyBucket --s3-key builds/helloWorld.zip#...

Disclaimer: I personally use AWS and CircleCI, I use them for client work, and I happily recommend them to others. I do so freely (i.e. I don't collect any referral fees).

Web development is *way* more complicated than it used to be. But you can learn from someone who's been there and done that.

Sign up on my email list where I write about modern web development with technology like React, Redux, TypeScript, Webpack and more.