How to deploy an express application to serverless with AWS Lambda
Introduction
AWS Lambda is an easy way to set up APIs which you don’t use regularly. The free tier from AWS is very generous (1 million requests per month). I personally found it to be a pain to find an easy way to setup a CI/CD workflow with it. After several hours, here is the approach I made myself to have a super easy way to set up a pipeline to Lambda.
Steps
- Initialise a nodejs application if you don’t have one already
npm init
- Install the packages
express
andserverless-http
npm install express serverless-http
- In the index.js file, create an express app and export it
const express = require("express");
const app = express();
app.get("/", (_, res) => {
res.send("Server active");
});
if (process.env.isDev) {
app.listen(5000, () => console.log("listening on port 5000"));
}
module.exports = app;
- Create a file called
lambda.js
which takes this exported app and converts the routes to lambda functions usingserverless-http
package.
// lambda.js
"use strict";
const app = require("./index");
const serverless = require("serverless-http");
module.exports.handler = serverless(app);
- Create a
serverless.yml
file like the one below. The service property can be renamed to anything you see fit.
There needs to be only one handler. Any routes created using standard express convention will be automatically configured as lambda routes using the filename as the endpoint slug.
service: express-to-lambda
provider:
name: aws
runtime: nodejs16.x
stage: prod
region: ap-south-1
memorySize: 512
functions:
app:
handler: lambda/lambda.handler
events:
- http:
path: /
method: ANY
cors: true
- http:
path: /{proxy+}
method: ANY
cors: true
NOTE: CORS is taken care by default in the above yml. If you would require fine grained control, you can add fine-grained and programmatic CORS control using the nodeJS CORS middleware.
- Deploy the functions
Deploying to AWS Lambda is super easy and can be done by the serverless
nodejs library.
Run the following from the root directory of your project.
npm i -g serverless
serverless config credentials --provider aws --key AWS_ACCESS_KEY_ID --secret AWS_SECRET_ACCESS_KEY
# replace the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY with your own values which can be received from AWS IAM
serverless deploy
For easier way, wake it into a shell alias or add it as a script to do one command deploy as well. You can also try adding it as new workflow in github actions for getting CI/CD.
There you go. That’s it. The above step may take some time, but with it, you would be able to deploy your express application with AWS Lambda.
Bonus
Setting up CI/CD pipeline to deploy from a github repo is super easy as well.
# Place in .github/workflows/deploy.yml
name: deploy to lambda
on:
push:
branches: main
jobs:
lambda-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v2
- name: Setup node environment
uses: actions/setup-node@v1
with:
node-version: 16
- name: Install serverless globally
run: npm install -g serverless
- name: Configure serverless authentication
run: sls config credentials --provider aws --key ${{ secrets.AWS_ACCESS_KEY_ID }} --secret ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Install npm dependencies
run: npm ci
- name: Deploy lambda function
run: sls deploy
Add the AWS values AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in github secrets and you’re good to go. Now each time a new change is made and the code committed to the main branch, this workflow will run and the updated serverless function will be deployed to AWS Lambda✨
By the way, small tip - when doing local development, you can just add the following dev script in package.json
to get live-reload as well.
"scripts": {
"dev": "isDev=true nodemon index.js"
}
Just run npm run dev
the next time when developing locally.
Now, you can develope the function routes using the normal familiar express way, while also getting the ability to host these functions in a serverless environment on pushing to your VCS.
Remarks
I wrote it for IEDC during my tenure as CTO. Once this was made multiple students were using it our projects. We had several serverless functions running for sending emails, doing cleanups, knowing status etc. Everyone who used it really found the benefit of this, especially in such ease of getting started with development.
Extra things to keep in mind
Do note that while lambda is great, it doesn’t usually go too well with things like puppeteer and other automation tools which spins up a full blown browser. You can get around this using special puppeteer packages made specifically for lambda. In our case, we had a small ec2 instance which was free and we just used that to run our puppeteer script quickly; Depending on your use case, you can do it either way✨.