Six reasons why you shouldn’t run Express.js inside AWS Lambda
By: Maxim Vynohradov
Tags: Nodejs, Serverless, AWS Lambda, Expressjs, Serverless Architecture

So below is a list of six reasons why the usage of Express.js inside AWS Lambda is in most cases redundant, you probably get many drawbacks from this approach.

1 — Increasing node_modules size and cold starts

A simple point: the bigger your node_modules, the bigger cold starts AWS Lambda will have. With no exceptions. Raw Express.js is near 541.1 KB, but you also need additional dependencies, mostly middleware, that can increase your node_modules size several times.

2 — Additional operational time

When you use standalone Express.js on the server (standard way), each HTTP request is some kind of text that the server parses to a well-known request object. Lambdas that people tried to use with Express.js inside, usually run under API Gateway or AWS Application Load Balancer, and data that comes from this event source is already parsed by API GW and ALB! (Yes, it’s different, but anyway).

When you use Express.js inside AWS Lambda your “system” makes the next thing with input HTTP data:

AWS API GW or AWS ALB parses HTTP request and convert them to the event payload. The library that wraps the Express.js server maps the lambda event to server request. Express.js one more time converts this to its request object. The similar with a response — the library that wraps Express.js converts HTTP response to AWS Lambda response object.

So many supplementary conversions. Sometimes it looks like just wasting processor time.

3 — AWS Lambda has a different limitation, that can be unexpected for your Express.js application:

First of all, lambdas are stateless — each AWS Lambda instance is an AWS Firecracker container, that will shut down after some period of inactivity. So you cannot simply persist data and share them across all lambda instances. The same situation is true with sessions — to use it with AWS Lambda, you need additional storage, for instance, Redis instance hosted as AWS ElasticCache.

— each AWS Lambda instance is an AWS Firecracker container, that will shut down after some period of inactivity. So you cannot simply persist data and share them across all lambda instances. The same situation is true with — to use it with AWS Lambda, you need additional storage, for instance, Redis instance hosted as AWS ElasticCache. Lambdas container can live during several handler executions (warm lambdas), but in any way, it quits unexpectedly. And this could break some tools or make their behavior unpredictable. The most impressive case is related to buffering, loggers, and any error trackers , like Sentry. Usually, they don’t send all logs, data immediately, they buffering them firstly, and then send several logs items at once, to make this more efficient. But when your lambda’s container quits, time-to-time these buffers do not have time to be flushed into storage or third-party services. For sure, we can disable buffering, but some of the services require another SDKs, that specific for AWS Lambda. And they cannot be re-used simply as Express.js middleware — you should wrap them up as your own middleware, that double work.

, like Sentry. Usually, they don’t send all logs, data immediately, they buffering them firstly, and then send several logs items at once, to make this more efficient. But when your lambda’s container quits, time-to-time these buffers do not have time to be flushed into storage or third-party services. For sure, we can disable buffering, but some of the services require another SDKs, that specific for AWS Lambda. And they cannot be re-used simply as Express.js middleware — you should wrap them up as your own middleware, that double work. Also, you cannot use web-sockets (WebSockets, socket.io) inside the Express.js application, for the same reason — the lifetime of lambda execution container. But at the same time, AWS API GW supports web sockets, but they are implemented in another way, you cannot connect socket.io to them.

4 — Some things that you are used to do in the Express.js app are different in AWS Lambda and has more adequate alternatives

Despite all disadvantages, the embedded middleware pattern in Express.js is probably one of the most popular things in the Node.js world. However, there is no need to use Express.js just for this, becasue at least one middleware library is better suited for AWS Lambda:

Also, it implements an onion-like middleware pattern, that is much more flexible than Express.js can provide for you.

5 — Best practices for Express.js and AWS Lambda are different

At least you can easily find out the next point — security protection approaches are different. When Express.js best practice guide proposes to use Helmet.js library, it doesn’t apply to AWS Lambdas. AWS proposes to use the AWS WAF service that:

Protects your web applications from common web exploits

6 — Lost benefits from individual packaging of lambdas

When you write classic AWS Lambda handlers, you usually can package each lambda artifact separately, to reduce each artifact size. But when you use Express.js, you cannot do this — all lambdas require the same dependencies. Technically you can, but all of them will have the same size, which negates their advantages. Also, in this case, serverless-webpack-plugin cannot optimize imports correctly, because technically each lambda will have the same dependencies tree.