Optimise your AWS Lambda performance with NodeJS top-level await
Published: 2022-12-01 18:30:10


A few months ago, I wrote an article about [how to speed up your Lambda function](https://www.freecodecamp.org/news/how-to-speed-up-lambda-functions), which explores cold starts a bit and talks about the init code phase and writing code outside the Lambda handler function.

I got a few comments asking how to call an async function outside the Lambda handler. There are a few use cases where this could be useful. For example, when retrieving a password from AWS Secrets Manager, loading a file from S3, or opening a connection to RDS database, it might not be required to do this operation upon every function invocation. So it would be great to run this operation during the function init.

```
const {
  SecretsManagerClient,
  GetSecretValueCommand,
} = require("@aws-sdk/client-secrets-manager");

const client = new SecretsManagerClient();
const input = {
  SecretId: "<SECRET_MANAGER_RESOURCE_ID>",
};

const command = new GetSecretValueCommand(input);
const response = await client.send(command); // This will throw an error

exports.handler = async (event) => {
    // TODO use the returned response
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};
```

This will throw the following error:

```
  "errorType": "Runtime.UserCodeSyntaxError",
  "errorMessage": "SyntaxError: await is only valid in async function",
```

The only way we used to have to keep an optimal performance was to move `const response = await client.send(command);` into the Lambda handler. This implementation is Ok but not the best, because it will be executed upon every Lambda invocation, and it doesn't help with the readability of the code.

However, NodeJS introduced Top-Level await as an experimental feature in [version 14](https://nodejs.org/docs/latest-v14.x/api/all.html#esm_top_level_await), then it became generally available in [version 16](https://nodejs.org/docs/latest-v16.x/api/all.html#esm_top_level_await).

That's great. How can we use it? We need to change our code to use [ES modules](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/). You can do this by either changing the extension of your JS file to have the `.mjs` file extension or simply adding the `"type": "module"` to your package.json file.

The code would look as follows:

```
import {
  SecretsManagerClient,
  GetSecretValueCommand,
} from "@aws-sdk/client-secrets-manager";

const client = new SecretsManagerClient();
const input = {
  SecretId: "<SECRET_MANAGER_RESOURCE_ID>",
};

const command = new GetSecretValueCommand(input);
const response = await client.send(command); // This will work well

export const handler = async (event) => {
    // TODO use the returned response
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

```

Do you know of any other valuable tips with Lambda and NodeJS? I'd love to hear from you.

---

Thanks for reading this far. Did you like this article, and do you think others might find it useful? Feel free to share it on [Twitter](twitter.com/intent/tweet?url=https%3A%2F%2Fdev.to%2Faws-builders%2Foptimise-your-aws-lambda-performance-with-nodejs-top-level-await-1jgc%0A%0A%23aws%20%23awscommunity%20%23awscommunitybuilder%20%23softwaredeveloment%20%20&text=Check%20this%20article%20by%20%40Alee_Haydar%20on%20how%20to%20optimize%20your%20NodeJs%20Lambda%20with%20top-level%20awaits%3A%20%F0%9F%91%89) or [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://dev.to/ahaydar/optimise-your-aws-lambda-performance-with-nodejs-top-level-await-1jgc).