Deploying an Express Application to AWS Lambda, the easy way
--
In this post I’ll take an existing Express app I wrote for a previous blog post and show you how to deploy it to AWS. I’ll be using two libraries: serverless and aws-serverless-express.
** Note: you can find the complete code here.
Let’s start by adding some libraries to our app:
yarn add serverless serverless-plugin-write-env-vars --dev
yarn add aws-serverless-express
And we’ll write a .env.yml
file to hold our sensitive data. (make sure to add .env.yml
to your .gitignore
)
# .env.ymlcredentials:
accessKeyId: YOUR_AWS_ACCESS_KEY
secretAccessKey: YOUR_AWS_SECRET_KEYdevelopment:
NODE_ENV: development
DATABASE_URL: postgres://todo_user:todo_password@localhost/todostaging:
NODE_ENV: production
DATABASE_URL: postgres://user:password@myhost.com:5432/dbname?ssl=trueproduction:
NODE_ENV: production
DATABASE_URL: postgres://user:password@myhost.com:5432/dbname?ssl=true
You’ll need to replace the values for the following keys:
accessKeyId
andsecretAccessKey
: you can follow this instructions if you don’t have AWS credentials yet.DATABASE_URL
: you can provision free Postgres databases on Heroku, and you can get the url value from there (just make sure to add?ssl=true
to the end of the url)
Now we’ll use the aws-serverless-express
library to create a lambda function that will interact with our express application.
# lambda.js'use strict';const awsServerlessExpress = require('aws-serverless-express');
const app = require('./app');
const server = awsServerlessExpress.createServer(app);exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context);
The last piece of the puzzle is creating the serverless.yml
file, which lets serverless
know how to deploy our app.
# serverless.ymlservice: todoapiprovider:
name: aws
runtime: nodejs4.3
credentials: ${file(./.env.yml):credentials}custom:
writeEnvVars:
NODE_ENV: ${file(./.env.yml):${opt:stage}.NODE_ENV}
DATABASE_URL: ${file(./.env.yml):${opt:stage}.DATABASE_URL}plugins:
- serverless-plugin-write-env-varsfunctions:
api:
handler: lambda.handler
events:
- http: ANY {proxy+}
The serverless.yml
file may seem a little complex, but let’s break it down piece by piece.
- service: our app name
- provider:
- name: serverless only supportsaws
at the moment
- runtime: when writing your app, make sure you’re using a node version supported by AWS Lambda (at the time of this writing 4.3 was recommended)
- credentials: here we’re reading thecredentials
variable from the.env.yml
we wrote earlier. You can read more on how serverless deals with variables here. - custom:
- writeEnvVars: during deployment,serverless-plugin-write-env-vars
will grab any value defined insidecustom.writeEnvVars
and create a.env
file for us, which our app can then read.
We’re grabbing values from our.env.yml
file, like we did forcredentials
. However, notice we’re also using anopt:stage
variable, which will be populated from the CLI--stage
option when we run the serverless deploy command. - plugins: include any serverless plugin here.
- functions: a regular serverless app would usually have several functions defined. However, we’ll only use a single function that will cede control to our express app.
- api: I’m calling my functionapi
, but you can use any name you prefer. This name will be used to identify your function when running serverless commands like serverless logs.
- handler: here we specify we want to execute thehandler
function we previously wrote on ourlambda.js
file.
- events: a lambda function can be triggered from different events (an S3 bucket upload, an SNS topic, HTTP requests, etc). For this example, we’ll only deal with HTTP requests.
- http: here we’re saying we want to accept any http method to any path, and just hand it over to our express app.
Now we’re ready to deploy our app. Serverless allows you to deploy to different environments or “stages”. Let’s deploy to staging first:
serverless deploy --stage staging
After serverless is done uploading your app, you’ll get your app URL, which should look something like:
https://v5mmjbkn7e.execute-api.us-east-1.amazonaws.com/staging/
Take some time to test your app. You can check out app logs with:
serverless logs --stage staging --function api -t
And once you’re happy, deploy to production with
serverless deploy --stage production
That’s it. Your app is now running on AWS Lambda!
Special Considerations:
Do not rely on memory for storing data (if you’re using in-memory sessions, you’ll have to move them to a database, or go stateless).
You can take a look at the complete source code for this blog post here.