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-expressAnd 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:
accessKeyIdandsecretAccessKey: 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=trueto 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 supportsawsat 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 thecredentialsvariable from the.env.ymlwe wrote earlier. You can read more on how serverless deals with variables here. - custom:
- writeEnvVars: during deployment,serverless-plugin-write-env-varswill grab any value defined insidecustom.writeEnvVarsand create a.envfile for us, which our app can then read.
We’re grabbing values from our.env.ymlfile, like we did forcredentials. However, notice we’re also using anopt:stagevariable, which will be populated from the CLI--stageoption 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 thehandlerfunction we previously wrote on ourlambda.jsfile.
- 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 stagingAfter 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 -tAnd once you’re happy, deploy to production with
serverless deploy --stage productionThat’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.
