Problem definition

A curious case of curly brackets

Pardon me such violent start, but I would like to do a JavaScript Quiz with you. Everybody loves JavaScript quizzes, don’t they?

Can you point out the difference after calling both functions, without reaching out to the REPL? The most significant difference is related to the return value as the first function returns undefined when second returns a Promise.

It is another “kinda obvious, kinda not” behavior that you have to keep around in your head during programming. So we all are guilty. It’s not only a JS fault, as it appears in many other languages too, but we got used to it as programmers. We have Syntax Sugar Stockholm Syndrome deeply ingrained into our brains.

Why am I bashing JavaScript here? Let me introduce the change that recently happened in the AWS Lambda.

Node.js 6 is approaching end-of-life

At the beginning of the May 2019 AWS deprecated Node.js 6.10 runtime on AWS Lambda platform, as it approached the scheduled end-of-life (EOL). In the most usual cases, jump from 6.x to 8.x should not be a big deal. As they stated in this article it brings many performance improvements, changes in handling the asynchronous flow, new syntax, and language features and of course newer version of the V8. Sounds great, so far so good!

However there is one additional change, that is not related with the runtime update, but with the update in the AWS environment. A new version of the runtime (8.10) - supports async/await and it radically changes the asynchronous event flow. As AWS Lambda wants to be a modern environment and benefits from it, it behaves no different allowing you to ditch callbacks with the help of Promises or async handler.

As version with callback and more modern ones are still supported, you may ask: how does the runtime know which method use?

Great question! The key here is the return value - if you return a Promise it means that handler never evaluates the third argument, which is callback. In such a case, you tie execution flow to that main promise.

If you paused and had your AHA moment related to the puzzle above, you see the first pitfall that I would like to warn you.


Problem #1: You have to mix callback with Promises very carefully

As it detects behavior purely based on the return value of the function handler, you need to build and specify the flow around that handler carefully. It sounds and looks obvious when you read the lines above. However, there is one particular case about which I would like to warn you.

Problem #2: Beware the compilation pipeline

You need to be aware of the fact that when you are using WebPack or any tool for compiling JavaScript, it may happen that you primary handler after compilation is a function which returns a promise. That would be the reason for errors if you built execution flow on the callbacks.

It may happen accidentally - e.g., you are using Koa framework with TypeScript and serverless-http. As compiler does not know about the hidden behavior of the AWS Lambda it compiles blindly to a bad form. It is a straight path to a catastrophic event.

Problem #3: You cannot revert Node.js after the upgrade!

As AWS announced that they are deprecating 6.10 they did not stop on the words. They blocked the ability to deploy new functions on that runtime.

It means that the safest possible option for you is to leave it as it is, especially when it works and brings money. There is no backup mechanism other than creating the second function and switching triggers. The easiest way for that is to create a new Lambda function, test it, tear down, and then deploy with runtime update - after you prove its correctness.

Problem 4: null

Sometimes you will see a null as a result of using promises instead of callback

Such error can manifest itself in a much different manner. In some cases, you see a plaintext null instead of receiving a proper response object.

Why does it happen? Because AWS Lambda integration responds to its triggers a JSON object directly. The problem is that when you are changing from callback to the more modern way of asynchronous events handling, it means that return value takes over. In case of a resolved promise, it may result in returning undefined. So that is not a part of JSON protocol - only null is. That’s why runtime replaces that for us.

It is misleading and problematic, but after understanding that mechanism, we can live with it.


Knowing all of that, we have prepared a checklist in the form of an infographic:

Checklist for Node.js 6.x to 8.x migration on AWS Lambda


Those four pitfalls that I mentioned are not an exhaustive list of the potential traps. However, the sooner you find those, the better for you. Please let us know in the comments what we have missed here!

I hope that blog post with a short checklist help you with the migration and makes the process much clearer.

Are you facing problems with your Serverless apps on AWS?

Amazon Web Services and Serverless are our core expertise. Partner with us - experienced and pragmatic builders - and we help you innovate, move quickly, and be cost-effective with use of the cloud platform.

Reach out to specialists!