End of AWS Lambda support for Node.js 10: Should you switch from v10 to v14?

It’s the end of AWS Lambda support for Node.js v10. AWS Lambda support for Node.js 10 is due to end in August 2021. It’s time to switch! In this article, we’re discussing and comparing the differences of working with Node.js 10 and Node.js 14 + AWS Lambda, the impacts, and benefits of this change.

AWS Lambda supports multiple versions of programming language runtimes, but not forever. That’s because the creators of these programming languages don’t support them infinitely either.

AWS Lambda also only supports the long-term support (LTS) versions of Node.js: the even version numbers. Currently, versions 10, 12, and 14 are all supported, but in August 2021, the support for version 10 is running out.

So it’s time to switch, but besides evading the support end, what benefits does it bring to switch directly to version 14? In this article, I will go over the changes that have happened since version 10 of Node.js.

aws lambda monitoring

What Features were Added Since Version 10?

Let’s start with the ECMAScript additions to JavaScript. Usually, they are supported in the JavaScript engine before they are standardized. The idea is that nothing, that isn’t working in practice, gets standardized.

This doesn’t mean that all JavaScript engines support every ECMAScript feature before it is standardized. After all, the committee can’t wait for every JavaScript engine that is out there. For example, proper tail call optimization is standardized for years now, but only a few engines have implemented the feature.

Anyway, let’s check what happened since version 10!

Optional Chaining and Nullish Coalescing

This is one of the biggest additions, in my opinion. Gone are the crashes because you tried to access an attribute of an undefined variable, or you set a default for a value that was null-ish.

The optional chaining operator ?. is an alternative to the regular chaining operator . they can be used all the same; the only difference is that the regular chaining operator will crash if you try to access an attribute on an undefined variable. The optional chaining operator will simply return undefined

const deepValue = path?.to?.notDefined?.deep?.value;

If at least one part of this chain isn’t an object, deepValue will be set to undefined.

The nullish coalescing operator ?? is an alternative to the logical or operator || used to set variables to a default value.

The problem with the logical or operator was that it also used the default when the value was something that could be automatically converted to false, like the number 0. The nullish coalescing operator would only use the default when the checked variable was null or undefined.

<p>const input = 0;</p>

<p>let amount;</p>

<p>amount = input || 20;</p>

<p>amount = input ?? 20;</p>

In the example, the logic or operator would set the amount to 20 even if the input was 0, but the coalescing operator would leave it at 0.

The two new operators work nicely in tandem.

const deepValue = notDefined?.deep?.value ?? "default text";

Symbol Additions

The Symbol class got two new additions. If you create a new symbol with a description, you can now check it later with the description property.

This example will log “description” to the console.

const sym = Symbol("description");
	console.log(sym.description);

There is also a new well-known symbol called matchAll. It can be used to create custom matchAll functions for your data types.

const numbers = {
  *[Symbol.matchAll] (str) {
    for (const n of str.matchAll(/[0-9]+/g))
      yield n[0];
  }
};
console.log(Array.from("2021-05-12".matchAll(numbers)));

The object numbers needs a generator function (that’s what the * means) in its Symbol.matchAll property, so it can be used as a parameter for the String.prototype.matchAll method. This example will output ["2021", "05", "12"].

Global This

The unification of window, self, frames, and global into one global object called globalThis.  Back in the days, the access to the global object differed from where your script was running, but if you tried to access window inside Node.js or a worker thread, it would fail. With globalThis your script doesn’t have to care anymore.

This example works in all current browser versions and Node.js:

globalThis.aGlobalVariable = 123;

Class Fields

Since Node.js 10, there have been some additions to classes as well: instance class fields, static class fields, and private class fields.

Before version 12, instance fields had to be set in the constructor, and static fields had to be set via the prototype, and both were always public. Now you can set them all in the class definition and modify their visibility.

Let’s see how it works in practice:

class ResourceManager {
  static publicStaticField = 123;
  static #privateStaticField = 456;

  static publicStaticMethod() {}
  static #privateStaticMethod() {}

  publicInstanceField = 123;
  #privateInstanceField = 456;

  publicMethod() {}
  #privateMethod() {}
}

Flattening Arrays

If you end up with a nested array, and you want to lift the nested elements back to the top array, the new flat method for arrays is the solution.

const nested = [1, 2, 3, [4, 5], 6, 7];
const flattened = nested.flat();

The example above, flattened, will contain [1, 2, 3, 4, 5, 6, 7]. But keep in mind that it only flattens a depth of one; you have to call it again if you have deeper nested arrays you want to get rid of.

Since the flat method is usually called to clear up the array structure before a call to the map method, a shortcut method called flatMap() will work as a map with a flat applied before.

In the following example, the item is always a number and never an array because the nested array is flattened before passed to the callback function.

const nestedNumbers = [1, 2, [3, 4], 5];
const squaredNumbers = nested.flatMap(item => item * item);

International Display Names

The new Intl.DisplayNames API allows to translate region, language, and script display names automatically

This would display “德文”, the traditional Chinese translation of the language “German”.

const tradChinese = new Intl.DisplayNames(
  ['zh-Hant'],
  {type: 'language'}
);
     tradChinese.of('de');

Numeric Separators

It’s now possible to add underlines to number literals to make them more readable inside the code.

const oneMillion = 1_000_000;
const hexBlue = 0x00_00_FF;

Performance Improvements

Since version 10, many performance improvements have happened. The startup time improved by 30%, which can shave quite some time from your cold start latency.

The heap size configuration was done with two default values before, but in version 14, Node.js will take the actual available memory into account when configuring the optimal heap size. Since AWS Lambda allows for very flexible memory configurations per function, this could help you get more bang for the buck.

Find out more about saving money on Lambdas in our 6 AWS Lambda Cost Optimization Strategies That Work article.

I tried a prime number calculation on AWS Lambda with Node.js 10 and 14 to see the differences. First, I calculated primes between one hundred and one thousand and then those between one hundred and one billion. I run this with 128MB and 1024MB memory configuration, to see how the init times and runtime durations changed between the two versions.

The following graphs illustrate the differences.

aws lambda node.js 10 vs 14

Blue marks Node.js 10 and red 14. As you can see, the init timings got better by ~20% and I just switched the runtime version. Because Lambda functions are billed by millisecond this is real money you can save. Also, short-running Lambda functions can reduce the latency quite a bit.

aws lambda node.js 10 vs 14 duration

Again, blue marks Node.js 10 and red 14. This time I measured the duration an invocation took. The difference between the primes between hundred and thousand wasn’t much, so I left them out here, but for longer computations, like finding the primes between one hundred and one billion, it makes a huge difference. This saves a huge chunk of money and could even make it possible to do slow calculations synchronously as an API Gateway response now.

Other Additions

The diagnostic reports help with analyzing the behavior of a Node.js program. It will log out a JSON formatted string into a file that you can check for more details than CloudWatch gives you

Find out how you can get even more detailed and faster AWS data analytics, observability and debugging.

TLS 1.3 and QUIC protocol support have landed in the LTS version of Node.js, so your Lambda can keep communicating with the latest services out there.

The worker threads API is now stable. You can use it for computation-intensive workloads. Usually, Node.js is a single-threaded environment, but you can now execute JavaScript with worker threads in parallel. When you configure Lambda memory, the vCPU cores are also configured implicitly. If you set a memory limit of 10 GB, you also get 6 vCPU cores, which you can now utilize with Node.js worker threads.

Full International Components for Unicode (ICU) support has landed in Node.js. ICU is a set of “libraries providing Unicode and Globalization support for software applications”. The full list of features can be found on Node.js’s GitHub Repository.

Conclusion

The sun is setting on the LTS for Node.js version 10 in a few months’ time, and so is the AWS Lambda runtime support. If you have to switch anyway, why not go straight to version 14? It will give you a longer support time in the future, and you get a whole bag of extra features that improve the coding of Lambda functions and their performance on the AWS platform.


Further reading:

AWS Lambda Node.js errors and exceptions

How to deploy a Node.js application to AWS Lambda using Serverless

AWS Lambda metrics you should definitely monitoring

Read our blog

ANNOUNCEMENT: new pricing and the end of free tier

Today we are announcing a new, updated pricing model and the end of free tier for Dashbird.

4 Tips for AWS Lambda Performance Optimization

In this article, we’re covering 4 tips for AWS Lambda optimization for production. Covering error handling, memory provisioning, monitoring, performance, and more.

AWS Lambda Free Tier: Where Are The Limits?

In this article we’ll go through the ins and outs of AWS Lambda pricing model, how it works, what additional charges you might be looking at and what’s in the fine print.

More articles

Made by developers for developers

Dashbird was born out of our own need for an enhanced serverless debugging and monitoring tool, and we take pride in being developers.

What our customers say

Dashbird gives us a simple and easy to use tool to have peace of mind and know that all of our Serverless functions are running correctly. We are instantly aware now if there’s a problem. We love the fact that we have enough information in the Slack notification itself to take appropriate action immediately and know exactly where the issue occurred.

Thanks to Dashbird the time to discover the occurrence of an issue reduced from 2-4 hours to a matter of seconds or minutes. It also means that hundreds of dollars are saved every month.

Great onboarding: it takes just a couple of minutes to connect an AWS account to an organization in Dashbird. The UI is clean and gives a good overview of what is happening with the Lambdas and API Gateways in the account.

I mean, it is just extremely time-saving. It’s so efficient! I don’t think it’s an exaggeration or dramatic to say that Dashbird has been a lifesaver for us.

Dashbird provides an easier interface to monitor and debug problems with our Lambdas. Relevant logs are simple to find and view. Dashbird’s support has been good, and they take product suggestions with grace.

Great UI. Easy to navigate through CloudWatch logs. Simple setup.

Dashbird helped us refine the size of our Lambdas, resulting in significantly reduced costs. We have Dashbird alert us in seconds via email when any of our functions behaves abnormally. Their app immediately makes the cause and severity of errors obvious.