

# Building Lambda functions with TypeScript
<a name="lambda-typescript"></a>

You can use the Node.js runtime to run TypeScript code in AWS Lambda. Because Node.js doesn't run TypeScript code natively, you must first transpile your TypeScript code into JavaScript. Then, use the JavaScript files to deploy your function code to Lambda. Your code runs in an environment that includes the AWS SDK for JavaScript, with credentials from an AWS Identity and Access Management (IAM) role that you manage. To learn more about the SDK versions included with the Node.js runtimes, see [Runtime-included SDK versions](lambda-nodejs.md#nodejs-sdk-included).

Lambda supports the following Node.js runtimes.


| Name | Identifier | Operating system | Deprecation date | Block function create | Block function update | 
| --- | --- | --- | --- | --- | --- | 
|  Node.js 24  |  `nodejs24.x`  |  Amazon Linux 2023  |   Apr 30, 2028   |   Jun 1, 2028   |   Jul 1, 2028   | 
|  Node.js 22  |  `nodejs22.x`  |  Amazon Linux 2023  |   Apr 30, 2027   |   Jun 1, 2027   |   Jul 1, 2027   | 
|  Node.js 20  |  `nodejs20.x`  |  Amazon Linux 2023  |   Apr 30, 2026   |   Aug 31, 2026   |   Sep 30, 2026   | 

**Topics**
+ [Setting up a TypeScript development environment](#typescript-dev)
+ [Type definitions for Lambda](#typescript-type-definitions)
+ [Define Lambda function handler in TypeScript](typescript-handler.md)
+ [Deploy transpiled TypeScript code in Lambda with .zip file archives](typescript-package.md)
+ [Deploy transpiled TypeScript code in Lambda with container images](typescript-image.md)
+ [Using the Lambda context object to retrieve TypeScript function information](typescript-context.md)
+ [Log and monitor TypeScript Lambda functions](typescript-logging.md)
+ [Tracing TypeScript code in AWS Lambda](typescript-tracing.md)

## Setting up a TypeScript development environment
<a name="typescript-dev"></a>

Use a local integrated development environment (IDE) or text editor to write your TypeScript function code. You can’t create TypeScript code on the Lambda console.

You can use either [esbuild](https://esbuild.github.io/) or Microsoft's TypeScript compiler (`tsc`) to transpile your TypeScript code into JavaScript. The [AWS Serverless Application Model (AWS SAM)](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html) and the [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) both use esbuild.

When using esbuild, consider the following:
+ There are several [TypeScript caveats](https://esbuild.github.io/content-types/#typescript-caveats).
+ You must configure your TypeScript transpilation settings to match the Node.js runtime that you plan to use. For more information, see [Target](https://esbuild.github.io/api/#target) in the esbuild documentation. For an example of a **tsconfig.json** file that demonstrates how to target a specific Node.js version supported by Lambda, refer to the [TypeScript GitHub repository](https://github.com/tsconfig/bases/blob/main/bases/node14.json).
+ esbuild doesn’t perform type checks. To check types, use the `tsc` compiler. Run `tsc -noEmit` or add a `"noEmit"` parameter to your **tsconfig.json** file, as shown in the following example. This configures `tsc` to not emit JavaScript files. After checking types, use esbuild to convert the TypeScript files into JavaScript.

**Example tsconfig.json**  

```
 {
  "compilerOptions": {
    "target": "es2020",
    "strict": true,
    "preserveConstEnums": true,
    "noEmit": true,
    "sourceMap": false,
    "module":"commonjs",
    "moduleResolution":"node",
    "esModuleInterop": true, 
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true, 
    "isolatedModules": true, 
  },
  "exclude": ["node_modules", "**/*.test.ts"]
}
```

## Type definitions for Lambda
<a name="typescript-type-definitions"></a>

The [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package provides type definitions for Lambda functions. Install this package when your function uses any of the following:
+ Common AWS event sources, such as:
  + `APIGatewayProxyEvent`: For [Amazon API Gateway proxy integrations](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html) 
  + `SNSEvent`: For [Amazon Simple Notification Service notifications](with-sns.md)
  + `SQSEvent`: For [Amazon Simple Queue Service messages](with-sqs.md)
  + `S3Event`: For [S3 trigger events](with-s3.md)
  + `DynamoDBStreamEvent`: For [Amazon DynamoDB Streams](with-ddb.md)
+ The Lambda [Context](typescript-context.md) object
+ The [callback](typescript-handler.md#typescript-handler-callback) handler pattern

To add the Lambda type definitions to your function, install `@types/aws-lambda` as a development dependency:

```
npm install -D @types/aws-lambda
```

Then, import the types from `aws-lambda`:

```
import { Context, S3Event, APIGatewayProxyEvent } from 'aws-lambda';

export const handler = async (event: S3Event, context: Context) => {
    // Function code
};
```

The `import ... from 'aws-lambda'` statement imports the type definitions. It does not import the `aws-lambda` npm package, which is an unrelated third-party tool. For more information, see [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda) in the DefinitelyTyped GitHub repository.

**Note**  
You don't need [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) when using your own custom type definitions. For an example function that defines its own type for an event object, see [Example TypeScript Lambda function code](typescript-handler.md#typescript-example-code).

# Define Lambda function handler in TypeScript
<a name="typescript-handler"></a>

The Lambda function *handler* is the method in your function code that processes events. When your function is invoked, Lambda runs the handler method. Your function runs until the handler returns a response, exits, or times out.

This page describes how to work with Lambda function handlers in TypeScript, including options for project setup, naming conventions, and best practices. This page also includes an example of a TypeScript Lambda function that takes in information about an order, produces a text file receipt, and puts this file in an Amazon Simple Storage Service (Amazon S3) bucket. For information about how to deploy your function after writing it, see [Deploy transpiled TypeScript code in Lambda with .zip file archives](typescript-package.md) or [Deploy transpiled TypeScript code in Lambda with container images](typescript-image.md).

**Topics**
+ [Setting up your TypeScript project](#typescript-handler-setup)
+ [Example TypeScript Lambda function code](#typescript-example-code)
+ [CommonJS and ES Modules](#typescript-commonjs-es-modules)
+ [Node.js initialization](#typescript-initialization)
+ [Handler naming conventions](#typescript-handler-naming)
+ [Defining and accessing the input event object](#typescript-example-input)
+ [Valid handler patterns for TypeScript functions](#typescript-handler-signatures)
+ [Using the SDK for JavaScript v3 in your handler](#typescript-example-sdk-usage)
+ [Accessing environment variables](#typescript-example-envvars)
+ [Using global state](#typescript-handler-state)
+ [Code best practices for TypeScript Lambda functions](#typescript-best-practices)

## Setting up your TypeScript project
<a name="typescript-handler-setup"></a>

Use a local integrated development environment (IDE) or text editor to write your TypeScript function code. You can’t create TypeScript code on the Lambda console.

There are multiple ways to initialize a TypeScript Lambda project. For example, you can create a project using `npm`, create an [AWS SAM application](typescript-package.md#aws-sam-ts), or create an [AWS CDK application](typescript-package.md#aws-cdk-ts). To create the project using `npm`:

```
npm init
```

Your function code lives in a `.ts` file, which you transpile into a JavaScript file at build time. You can use either [esbuild](https://esbuild.github.io/) or Microsoft's TypeScript compiler (`tsc`) to transpile your TypeScript code into JavaScript. To use esbuild, add it as a development dependency:

```
npm install -D esbuild
```

A typical TypeScript Lambda function project follows this general structure:

```
/project-root
  ├── index.ts - Contains main handler
  ├── dist/ - Contains compiled JavaScript
  ├── package.json - Project metadata and dependencies
  ├── package-lock.json - Dependency lock file
  ├── tsconfig.json - TypeScript configuration
  └── node_modules/ - Installed dependencies
```

## Example TypeScript Lambda function code
<a name="typescript-example-code"></a>

The following example Lambda function code takes in information about an order, produces a text file receipt, and puts this file in an Amazon S3 bucket. This example defines a custom event type (`OrderEvent`). To learn how to import type definitions for AWS event sources, see [Type definitions for Lambda](lambda-typescript.md#typescript-type-definitions).

**Note**  
This example uses an ES module handler. Lambda supports both ES module and CommonJS handlers. For more information, see [CommonJS and ES Modules](nodejs-handler.md#nodejs-commonjs-es-modules).

**Example index.ts Lambda function**  

```
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

// Initialize the S3 client outside the handler for reuse
const s3Client = new S3Client();

// Define the shape of the input event
type OrderEvent = {
    order_id: string;
    amount: number;
    item: string;
}

/**
 * Lambda handler for processing orders and storing receipts in S3.
 */
export const handler = async (event: OrderEvent): Promise<string> => {
    try {
        // Access environment variables
        const bucketName = process.env.RECEIPT_BUCKET;
        if (!bucketName) {
            throw new Error('RECEIPT_BUCKET environment variable is not set');
        }

        // Create the receipt content and key destination
        const receiptContent = `OrderID: ${event.order_id}\nAmount: $${event.amount.toFixed(2)}\nItem: ${event.item}`;
        const key = `receipts/${event.order_id}.txt`;

        // Upload the receipt to S3
        await uploadReceiptToS3(bucketName, key, receiptContent);

        console.log(`Successfully processed order ${event.order_id} and stored receipt in S3 bucket ${bucketName}`);
        return 'Success';
    } catch (error) {
        console.error(`Failed to process order: ${error instanceof Error ? error.message : 'Unknown error'}`);
        throw error;
    }
};

/**
 * Helper function to upload receipt to S3
 */
async function uploadReceiptToS3(bucketName: string, key: string, receiptContent: string): Promise<void> {
    try {
        const command = new PutObjectCommand({
            Bucket: bucketName,
            Key: key,
            Body: receiptContent
        });

        await s3Client.send(command);
    } catch (error) {
        throw new Error(`Failed to upload receipt to S3: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
}
```

This `index.ts` file contains the following sections of code:
+ `import` block: Use this block to include libraries that your Lambda function requires, such as [AWS SDK clients](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/the-request-object.html).
+ `const s3Client` declaration: This initializes an [Amazon S3 client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/) outside of the handler function. This causes Lambda to run this code during the [initialization phase](lambda-runtime-environment.md#runtimes-lifecycle-ib), and the client is preserved for [reuse across multiple invocations](lambda-runtime-environment.md#execution-environment-reuse).
+ `type OrderEvent`: Defines the structure of the expected input event.
+ `export const handler`: This is the main handler function that Lambda invokes. When deploying your function, specify `index.handler` for the [Handler](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler) property. The value of the `Handler` property is the file name and the name of the exported handler method, separated by a dot.
+ `uploadReceiptToS3` function: This is a helper function that's referenced by the main handler function.

For this function to work properly, its [ execution role](lambda-intro-execution-role.md) must allow the `s3:PutObject` action. Also, ensure that you define the `RECEIPT_BUCKET` environment variable. After a successful invocation, the Amazon S3 bucket should contain a receipt file.

## CommonJS and ES Modules
<a name="typescript-commonjs-es-modules"></a>

Node.js supports two module systems: CommonJS and ECMAScript modules (ES modules). Lambda recommends using ES modules as it supports top-level await, which enables asynchronous tasks to be completed during [execution environment initialization](#typescript-initialization).

Node.js treats files with a `.cjs` file name extension as CommonJS modules while a `.mjs` extension denotes ES modules. By default, Node.js treats files with the `.js` file name extension as CommonJS modules. You can configure Node.js to treat `.js` files as ES modules by specifying the `type` as `module` in the function's `package.json` file. You can configure Node.js in Lambda to detect automatically whether a `.js` file should be treated as CommonJS or as an ES module by adding the `—experimental-detect-module` flag to the `NODE_OPTIONS` environment variable. For more information, see [Experimental Node.js features](lambda-nodejs.md#nodejs-experimental-features).

The following examples show function handlers written using both ES modules and CommonJS modules. The remaining examples on this page all use ES modules.

## Node.js initialization
<a name="typescript-initialization"></a>

Node.js uses a non-blocking I/O model that supports efficient asynchronous operations using an event loop. For example, if Node.js makes a network call, the function continues to process other operations without blocking on a network response. When the network response is received, it is placed into the callback queue. Tasks from the queue are processed when the current task completes.

Lambda recommends using top-level await so that asynchronous tasks initiated during execution environment initialization are completed during initialization. Asynchronous tasks that are not completed during initialization will typically run during the first function invoke. This can cause unexpected behavior or errors. For example, your function initialization may make a network call to fetch a parameter from AWS Parameter Store. If this task is not completed during initialization, the value may be null during an invocation. There can also be a delay between initialization and invoke which can trigger errors in time-sensitive operations. In particular, AWS service calls can rely on time-sensitive request signatures, resulting in service call failures if the call is not completed during the initialization phase. Completing tasks during initialization typically improves cold-start performance, and first invoke performance when using Provisioned Concurrency. For more information, see our blog post [Using Node.js ES modules and top-level await in AWS Lambda](https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda).

## Handler naming conventions
<a name="typescript-handler-naming"></a>

When you configure a function, the value of the [Handler](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler) setting is the file name and the name of the exported handler method, separated by a dot. The default for functions created in the console and for examples in this guide is `index.handler`. This indicates the `handler` method that's exported from the `index.js` or `index.mjs` file.

If you create a function in the console using a different file name or function handler name, you must edit the default handler name.

**To change the function handler name (console)**

1. Open the [Functions](https://console.aws.amazon.com/lambda/home#/functions) page of the Lambda console and choose your function.

1. Choose the **Code** tab.

1. Scroll down to the **Runtime settings** pane and choose **Edit**.

1. In **Handler**, enter the new name for your function handler.

1. Choose **Save**.

## Defining and accessing the input event object
<a name="typescript-example-input"></a>

JSON is the most common and standard input format for Lambda functions. In this example, the function expects an input similar to the following:

```
{
    "order_id": "12345",
    "amount": 199.99,
    "item": "Wireless Headphones"
}
```

When working with Lambda functions in TypeScript, you can define the shape of the input event using a type or interface. In this example, we define the event structure using a type:

```
type OrderEvent = {
    order_id: string;
    amount: number;
    item: string;
}
```

After you define the type or interface, use it in your handler's signature to ensure type safety:

```
export const handler = async (event: OrderEvent): Promise<string> => {
```

During compilation, TypeScript validates that the event object contains the required fields with the correct types. For example, the TypeScript compiler reports an error if you try to use `event.order_id` as a number or `event.amount` as a string.

## Valid handler patterns for TypeScript functions
<a name="typescript-handler-signatures"></a>

We recommend that you use [async/await](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/using-async-await.html) to declare the function handler instead of using [callbacks](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/using-a-callback-function.html). Async/await is a concise and readable way to write asynchronous code, without the need for nested callbacks or chaining promises. With async/await, you can write code that reads like synchronous code, while still being asynchronous and non-blocking.

The examples in this section use the `S3Event` type. However, you can use any other AWS event types in the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package, or define your own event type. To use types from @types/aws-lambda:

1. Add the @types/aws-lambda package as a development dependency:

   ```
   npm install -D @types/aws-lambda
   ```

1. Import the types you need, such as `Context`, `S3Event`, or `Callback`.

### async function handlers (recommended)
<a name="typescript-handler-async"></a>

The `async` keyword marks a function as asynchronous, and the `await` keyword pauses the execution of the function until a `Promise` is resolved. The handler accepts the following arguments:
+ `event`: Contains the input data passed to your function.
+ `context`: Contains information about the invocation, function, and execution environment. For more information, see [Using the Lambda context object to retrieve TypeScript function information](typescript-context.md).

Here are the valid signatures for the async/await pattern:

```
export const handler = async (event: S3Event): Promise<void> => { };
```

```
export const handler = async (event: S3Event, context: Context): Promise<void> => { };
```

**Note**  
When processing arrays of items asynchronously, make sure to use await with `Promise.all` to ensure all operations complete. Methods like `forEach` don't wait for async callbacks to complete. For more information, see [Array.prototype.forEach()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) in the Mozilla documentation.

### Synchronous function handlers
<a name="typescript-handler-synchronous"></a>

Where your function does not perform any asynchronous tasks, you can use a synchronous function handler, using one of the following function signatures:

```
export const handler = (event: S3Event): void => { };
```

```
export const handler = (event: S3Event, context: Context): void => { };
```

### Response streaming function handlers
<a name="typescript-handler-response-streaming"></a>

Lambda supports response streaming with Node.js. Response streaming function handlers use the awslambda.streamifyResponse() decorator and take 3 parameters: event, responseStream, and context. The function signature is:

```
export const handler = awslambda.streamifyResponse(async (event: APIGatewayProxyEvent, responseStream: NodeJS.WritableStream, context: Context) => { });
```

For more information, see Response streaming for Lambda functions.

### Callback-based function handlers
<a name="typescript-handler-callback"></a>

**Note**  
Callback-based function handlers are only supported up to Node.js 22. Starting from Node.js 24, asynchronous tasks should be implemented using async function handlers.

Callback-based function handlers can use the event, context, and callback arguments. The callback argument expects an `Error` and a response, which must be JSON-serializable.

Here is the valid signature for the callback handler pattern:

```
export const handler = (event: S3Event, context: Context, callback: Callback<void>): void => { };
```

The function continues to execute until the [event loop](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/) is empty or the function times out. The response isn't sent to the invoker until all event loop tasks are finished. If the function times out, an error is returned instead. You can configure the runtime to send the response immediately by setting [context.callbackWaitsForEmptyEventLoop](typescript-context.md) to false.

**Example TypeScript function with callback**  
The following example uses `APIGatewayProxyCallback`, which is a specialized callback type specific to API Gateway integrations. Most AWS event sources use the generic `Callback` type shown in the signatures above.  

```
import { Context, APIGatewayProxyCallback, APIGatewayEvent } from 'aws-lambda';

export const lambdaHandler = (event: APIGatewayEvent, context: Context, callback: APIGatewayProxyCallback): void => {
    console.log(`Event: ${JSON.stringify(event, null, 2)}`);
    console.log(`Context: ${JSON.stringify(context, null, 2)}`);
    callback(null, {
        statusCode: 200,
        body: JSON.stringify({
            message: 'hello world',
        }),
    });
};
```

## Using the SDK for JavaScript v3 in your handler
<a name="typescript-example-sdk-usage"></a>

Often, you’ll use Lambda functions to interact with or make updates to other AWS resources. The simplest way to interface with these resources is to use the AWS SDK for JavaScript. All supported Lambda Node.js runtimes include the [SDK for JavaScript version 3](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/introduction/). However, we strongly recommend that you include the AWS SDK clients that you need in your deployment package. This maximizes [backward compatibility](runtimes-update.md#runtime-update-compatibility) during future Lambda runtime updates.

To add SDK dependencies to your function, use the `npm install` command for the specific SDK clients that you need. In the example code, we used the [Amazon S3 client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/). Add this dependency by running the following command in the directory that contains your `package.json` file:

```
npm install @aws-sdk/client-s3
```

In the function code, import the client and commands that you need, as the example function demonstrates:

```
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
```

Then, initialize an [Amazon S3 client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/):

```
const s3Client = new S3Client();
```

In this example, we initialized our Amazon S3 client outside of the main handler function to avoid having to initialize it every time we invoke our function. After you initialize your SDK client, you can then use it to make API calls for that AWS service. The example code calls the Amazon S3 [PutObject](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/command/PutObjectCommand/) API action as follows:

```
const command = new PutObjectCommand({
    Bucket: bucketName,
    Key: key,
    Body: receiptContent
});
```

## Accessing environment variables
<a name="typescript-example-envvars"></a>

In your handler code, you can reference any [environment variables](configuration-envvars.md) by using `process.env`. In this example, we reference the defined `RECEIPT_BUCKET` environment variable using the following lines of code:

```
// Access environment variables
const bucketName = process.env.RECEIPT_BUCKET;
if (!bucketName) {
    throw new Error('RECEIPT_BUCKET environment variable is not set');
}
```

## Using global state
<a name="typescript-handler-state"></a>

Lambda runs your static code during the [initialization phase](lambda-runtime-environment.md#runtimes-lifecycle-ib) before invoking your function for the first time. Resources created during initialization stay in memory between invocations, so you can avoid having to create them every time you invoke your function.

In the example code, the S3 client initialization code is outside the handler. The runtime initializes the client before the function handles its first event, and the client remains available for reuse across all invocations.

## Code best practices for TypeScript Lambda functions
<a name="typescript-best-practices"></a>

Follow these guidelines when building Lambda functions:
+ **Separate the Lambda handler from your core logic.** This allows you to make a more unit-testable function.
+ **Control the dependencies in your function's deployment package. ** The AWS Lambda execution environment contains a number of libraries. For the Node.js and Python runtimes, these include the AWS SDKs. To enable the latest set of features and security updates, Lambda will periodically update these libraries. These updates may introduce subtle changes to the behavior of your Lambda function. To have full control of the dependencies your function uses, package all of your dependencies with your deployment package. 
+ **Minimize the complexity of your dependencies.** Prefer simpler frameworks that load quickly on [execution environment](lambda-runtime-environment.md) startup.
+ **Minimize your deployment package size to its runtime necessities. ** This will reduce the amount of time that it takes for your deployment package to be downloaded and unpacked ahead of invocation.

**Take advantage of execution environment reuse to improve the performance of your function.** Initialize SDK clients and database connections outside of the function handler, and cache static assets locally in the `/tmp` directory. Subsequent invocations processed by the same instance of your function can reuse these resources. This saves cost by reducing function run time.

To avoid potential data leaks across invocations, don’t use the execution environment to store user data, events, or other information with security implications. If your function relies on a mutable state that can’t be stored in memory within the handler, consider creating a separate function or separate versions of a function for each user.

**Use a keep-alive directive to maintain persistent connections.** Lambda purges idle connections over time. Attempting to reuse an idle connection when invoking a function will result in a connection error. To maintain your persistent connection, use the keep-alive directive associated with your runtime. For an example, see [Reusing Connections with Keep-Alive in Node.js](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html).

**Use [environment variables](configuration-envvars.md) to pass operational parameters to your function.** For example, if you are writing to an Amazon S3 bucket, instead of hard-coding the bucket name you are writing to, configure the bucket name as an environment variable.

**Avoid using recursive invocations** in your Lambda function, where the function invokes itself or initiates a process that may invoke the function again. This could lead to unintended volume of function invocations and escalated costs. If you see an unintended volume of invocations, set the function reserved concurrency to `0` immediately to throttle all invocations to the function, while you update the code.

**Do not use non-documented, non-public APIs** in your Lambda function code. For AWS Lambda managed runtimes, Lambda periodically applies security and functional updates to Lambda's internal APIs. These internal API updates may be backwards-incompatible, leading to unintended consequences such as invocation failures if your function has a dependency on these non-public APIs. See [the API reference](https://docs.aws.amazon.com/lambda/latest/api/welcome.html) for a list of publicly available APIs.

**Write idempotent code.** Writing idempotent code for your functions ensures that duplicate events are handled the same way. Your code should properly validate events and gracefully handle duplicate events. For more information, see [How do I make my Lambda function idempotent?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/).

# Deploy transpiled TypeScript code in Lambda with .zip file archives
<a name="typescript-package"></a>

Before you can deploy TypeScript code to AWS Lambda, you need to transpile it into JavaScript. This page explains three ways to build and deploy TypeScript code to Lambda with .zip file archives:
+ [Using AWS Serverless Application Model (AWS SAM)](#aws-sam-ts)
+ [Using the AWS Cloud Development Kit (AWS CDK)](#aws-cdk-ts)
+ [Using the AWS Command Line Interface (AWS CLI) and esbuild](#aws-cli-ts)

AWS SAM and AWS CDK simplify building and deploying TypeScript functions. The [AWS SAM template specification](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html) provides a simple and clean syntax to describe the Lambda functions, APIs, permissions, configurations, and events that make up your serverless application. The [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/home.html) lets you build reliable, scalable, cost-effective applications in the cloud with the considerable expressive power of a programming language. The AWS CDK is intended for moderately to highly experienced AWS users. Both the AWS CDK and the AWS SAM use esbuild to transpile TypeScript code into JavaScript.

## Using AWS SAM to deploy TypeScript code to Lambda
<a name="aws-sam-ts"></a>

Follow the steps below to download, build, and deploy a sample Hello World TypeScript application using the AWS SAM. This application implements a basic API backend. It consists of an Amazon API Gateway endpoint and a Lambda function. When you send a GET request to the API Gateway endpoint, the Lambda function is invoked. The function returns a `hello world` message.

**Note**  
AWS SAM uses esbuild to create Node.js Lambda functions from TypeScript code. esbuild support is currently in public preview. During public preview, esbuild support may be subject to backwards incompatible changes.

**Prerequisites**

To complete the steps in this section, you must have the following:
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI version 1.75 or later](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
+ Node.js

**Deploy a sample AWS SAM application**

1. Initialize the application using the Hello World TypeScript template.

   ```
   sam init --app-template hello-world-typescript --name sam-app --package-type Zip --runtime nodejs24.x
   ```

1. (Optional) The sample application includes configurations for commonly used tools, such as [ESLlint](https://eslint.org/) for code linting and [Jest](https://jestjs.io/) for unit testing. To run lint and test commands:

   ```
   cd sam-app/hello-world
   npm install
   npm run lint
   npm run test
   ```

1. Build the app.

   ```
   cd sam-app
   sam build
   ```

1. Deploy the app.

   ```
   sam deploy --guided
   ```

1. Follow the on-screen prompts. To accept the default options provided in the interactive experience, respond with `Enter`.

1. The output shows the endpoint for the REST API. Open the endpoint in a browser to test the function. You should see this response:

   ```
   {"message":"hello world"}
   ```

1. This is a public API endpoint that is accessible over the internet. We recommend that you delete the endpoint after testing.

   ```
   sam delete
   ```

## Using the AWS CDK to deploy TypeScript code to Lambda
<a name="aws-cdk-ts"></a>

Follow the steps below to build and deploy a sample TypeScript application using the AWS CDK. This application implements a basic API backend. It consists of an API Gateway endpoint and a Lambda function. When you send a GET request to the API Gateway endpoint, the Lambda function is invoked. The function returns a `hello world` message.

**Prerequisites**

To complete the steps in this section, you must have the following:
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK version 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ Node.js
+ Either [Docker](https://www.docker.com/get-started/) or [esbuild](https://esbuild.github.io/)

**Deploy a sample AWS CDK application**

1. Create a project directory for your new application.

   ```
   mkdir hello-world
   cd hello-world
   ```

1. Initialize the app.

   ```
   cdk init app --language typescript
   ```

1. Add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency. This package contains the type definitions for Lambda.

   ```
   npm install -D @types/aws-lambda
   ```

1. Open the **lib** directory. You should see a file called **hello-world-stack.ts**. Create two new files in this directory: **hello-world.function.ts** and **hello-world.ts**.

1. Open **hello-world.function.ts** and add the following code to the file. This is the code for the Lambda function.
**Note**  
The `import` statement imports the type definitions from [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda). It does not import the `aws-lambda` NPM package, which is an unrelated third-party tool. For more information, see [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda) in the DefinitelyTyped GitHub repository.

   ```
   import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
       console.log(`Event: ${JSON.stringify(event, null, 2)}`);
       console.log(`Context: ${JSON.stringify(context, null, 2)}`);
       return {
           statusCode: 200,
           body: JSON.stringify({
               message: 'hello world',
           }),
       };
   };
   ```

1. Open **hello-world.ts** and add the following code to the file. This contains the [NodejsFunction construct](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html), which creates the Lambda function, and the [LambdaRestApi construct](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html), which creates the REST API.

   ```
   import { Construct } from 'constructs';
   import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
   import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';
     
   export class HelloWorld extends Construct {
     constructor(scope: Construct, id: string) {
       super(scope, id);
       const helloFunction = new NodejsFunction(this, 'function');
       new LambdaRestApi(this, 'apigw', {
         handler: helloFunction,
       });
     }
   }
   ```

   The `NodejsFunction` construct assumes the following by default:
   + Your function handler is called `handler`.
   + The .ts file that contains the function code (**hello-world.function.ts**) is in the same directory as the .ts file that contains the construct (**hello-world.ts**). The construct uses the construct's ID ("hello-world") and the name of the Lambda handler file ("function") to find the function code. For example, if your function code is in a file called **hello-world.my-function.ts**, the **hello-world.ts** file must reference the function code like this:

     ```
     const helloFunction = new NodejsFunction(this, 'my-function');
     ```

   You can change this behavior and configure other esbuild parameters. For more information, see [Configuring esbuild](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html#configuring-esbuild) in the AWS CDK API reference.

1. Open **hello-world-stack.ts**. This is the code that defines your [AWS CDK stack](https://docs.aws.amazon.com/cdk/v2/guide/stacks.html). Replace the code with the following:

   ```
   import { Stack, StackProps } from 'aws-cdk-lib';
   import { Construct } from 'constructs';
   import { HelloWorld } from './hello-world';
     
   export class HelloWorldStack extends Stack {
     constructor(scope: Construct, id: string, props?: StackProps) {
       super(scope, id, props);
       new HelloWorld(this, 'hello-world');
     }
   }
   ```

1. from the `hello-world` directory containing your `cdk.json` file, deploy your application.

   ```
   cdk deploy
   ```

1. The AWS CDK builds and packages the Lambda function using esbuild, and then deploys the function to the Lambda runtime. The output shows the endpoint for the REST API. Open the endpoint in a browser to test the function. You should see this response:

   ```
   {"message":"hello world"}
   ```

   This is a public API endpoint that is accessible over the internet. We recommend that you delete the endpoint after testing.

## Using the AWS CLI and esbuild to deploy TypeScript code to Lambda
<a name="aws-cli-ts"></a>

The following example demonstrates how to transpile and deploy TypeScript code to Lambda using esbuild and the AWS CLI. esbuild produces one JavaScript file with all dependencies. This is the only file that you need to add to the .zip archive.

**Prerequisites**

To complete the steps in this section, you must have the following:
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ Node.js
+ An [execution role](lambda-intro-execution-role.md) for the Lambda function
+ For Windows users, a zip file utility such as [7zip](https://www.7-zip.org/download.html).

**Deploy a sample function**

1. On your local machine, create a project directory for your new function. 

1. Create a new Node.js project with npm or a package manager of your choice.

   ```
   npm init
   ```

1. Add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) and [esbuild](https://esbuild.github.io/) packages as development dependencies. The `@types/aws-lambda` package contains the type definitions for Lambda.

   ```
   npm install -D @types/aws-lambda esbuild
   ```

1. Create a new file called **index.ts**. Add the following code to the new file. This is the code for the Lambda function. The function returns a `hello world` message. The function doesn’t create any API Gateway resources.
**Note**  
The `import` statement imports the type definitions from [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda). It does not import the `aws-lambda` NPM package, which is an unrelated third-party tool. For more information, see [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda) in the DefinitelyTyped GitHub repository.

   ```
   import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
     console.log(`Event: ${JSON.stringify(event, null, 2)}`);
     console.log(`Context: ${JSON.stringify(context, null, 2)}`);
     return {
         statusCode: 200,
         body: JSON.stringify({
             message: 'hello world',
         }),
      };
   };
   ```

1. Add a build script to the **package.json** file. This configures esbuild to automatically create the .zip deployment package. For more information, see [Build scripts](https://esbuild.github.io/getting-started/#build-scripts) in the esbuild documentation.

------
#### [ Linux and MacOS ]

   ```
   "scripts": {
     "prebuild": "rm -rf dist",
     "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js",
     "postbuild": "cd dist && zip -r index.zip index.js*"
   },
   ```

------
#### [ Windows ]

   In this example, the `"postbuild"` command uses the [7zip](https://www.7-zip.org/download.html) utility to create your .zip file. Use your own preferred Windows zip utility and modify the command as necessary.

   ```
   "scripts": {
     "prebuild": "del /q dist",
     "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js",
     "postbuild": "cd dist && 7z a -tzip index.zip index.js*"
   },
   ```

------

1. Build the package.

   ```
   npm run build
   ```

1. Create a Lambda function using the .zip deployment package. Replace the highlighted text with the Amazon Resource Name (ARN) of your [execution role](lambda-intro-execution-role.md).

   ```
   aws lambda create-function --function-name hello-world --runtime "nodejs24.x" --role arn:aws:iam::123456789012:role/lambda-ex --zip-file "fileb://dist/index.zip" --handler index.handler
   ```

1. [Run a test event](testing-functions.md) to confirm that the function returns the following response. If you want to invoke this function using API Gateway, [create and configure a REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-create-api.html).

   ```
   {
     "statusCode": 200,
     "body": "{\"message\":\"hello world\"}"
   }
   ```

# Deploy transpiled TypeScript code in Lambda with container images
<a name="typescript-image"></a>

You can deploy your TypeScript code to an AWS Lambda function as a Node.js [container image](images-create.md). AWS provides [base images](nodejs-image.md#nodejs-image-base) for Node.js to help you build the container image. These base images are preloaded with a language runtime and other components that are required to run the image on Lambda. AWS provides a Dockerfile for each of the base images to help with building your container image.

If you use a community or private enterprise base image, you must [add the Node.js runtime interface client (RIC)](nodejs-image.md#nodejs-image-clients) to the base image to make it compatible with Lambda.

Lambda provides a runtime interface emulator for local testing. The AWS base images for Node.js include the runtime interface emulator. If you use an alternative base image, such as an Alpine Linux or Debian image, you can [build the emulator into your image](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#build-rie-into-your-base-image) or [install it on your local machine](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#test-an-image-without-adding-rie-to-the-image).

## Using a Node.js base image to build and package TypeScript function code
<a name="base-image-typescript"></a>

### Prerequisites
<a name="typescript-image-prerequisites"></a>

To complete the steps in this section, you must have the following:
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker) (minimum version 25.0.0)
+ The Docker [buildx plugin](https://github.com/docker/buildx/blob/master/README.md).
+ Node.js 22.x

### Creating an image from a base image
<a name="typescript-image-create"></a>

**To create an image from an AWS base image for Lambda**

1. On your local machine, create a project directory for your new function.

1. Create a new Node.js project with `npm` or a package manager of your choice.

   ```
   npm init
   ```

1. Add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) and [esbuild](https://esbuild.github.io/) packages as development dependencies. The `@types/aws-lambda` package contains the type definitions for Lambda.

   ```
   npm install -D @types/aws-lambda esbuild
   ```

1. Add a [build script](https://esbuild.github.io/getting-started/#build-scripts) to the `package.json` file.

   ```
     "scripts": {
     "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js"
   }
   ```

1. Create a new file called `index.ts`. Add the following sample code to the new file. This is the code for the Lambda function. The function returns a `hello world` message.
**Note**  
The `import` statement imports the type definitions from [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda). It does not import the `aws-lambda` NPM package, which is an unrelated third-party tool. For more information, see [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda) in the DefinitelyTyped GitHub repository.

   ```
   import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
       console.log(`Event: ${JSON.stringify(event, null, 2)}`);
       console.log(`Context: ${JSON.stringify(context, null, 2)}`);
       return {
           statusCode: 200,
           body: JSON.stringify({
               message: 'hello world',
           }),
       };
   };
   ```

1. Create a new Dockerfile with the following configuration:
   + Set the `FROM` property to the URI of the base image.
   + Set the `CMD` argument to specify the Lambda function handler.

   The following example Dockerfile uses a multi-stage build. The first step transpiles the TypeScript code into JavaScript. The second step produces a container image that contains only JavaScript files and production dependencies.

   Note that the example Dockerfile does not include a [USER instruction](https://docs.docker.com/reference/dockerfile/#user). When you deploy a container image to Lambda, Lambda automatically defines a default Linux user with least-privileged permissions. This is different from standard Docker behavior which defaults to the `root` user when no `USER` instruction is provided.  
**Example Dockerfile**  

   ```
   FROM public.ecr.aws/lambda/nodejs:22 as builder
   WORKDIR /usr/app
   COPY package.json index.ts  ./
   RUN npm install
   RUN npm run build
       
   FROM public.ecr.aws/lambda/nodejs:22
   WORKDIR ${LAMBDA_TASK_ROOT}
   COPY --from=builder /usr/app/dist/* ./
   CMD ["index.handler"]
   ```

1. Build the Docker image with the [docker build](https://docs.docker.com/engine/reference/commandline/build/) command. The following example names the image `docker-image` and gives it the `test` [tag](https://docs.docker.com/engine/reference/commandline/build/#tag). To make your image compatible with Lambda, you must use the `--provenance=false` option.

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**Note**  
The command specifies the `--platform linux/amd64` option to ensure that your container is compatible with the Lambda execution environment regardless of the architecture of your build machine. If you intend to create a Lambda function using the ARM64 instruction set architecture, be sure to change the command to use the `--platform linux/arm64` option instead.

### (Optional) Test the image locally
<a name="typescript-image-test"></a>

1. Start the Docker image with the **docker run** command. In this example, `docker-image` is the image name and `test` is the tag.

   ```
   docker run --platform linux/amd64 -p 9000:8080 docker-image:test
   ```

   This command runs the image as a container and creates a local endpoint at `localhost:9000/2015-03-31/functions/function/invocations`.
**Note**  
If you built the Docker image for the ARM64 instruction set architecture, be sure to use the `--platform linux/arm64` option instead of `--platform linux/amd64`.

1. From a new terminal window, post an event to the local endpoint.

------
#### [ Linux/macOS ]

   In Linux and macOS, run the following `curl` command:

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
   ```

   This command invokes the function with an empty event and returns a response. If you're using your own function code rather than the sample function code, you might want to invoke the function with a JSON payload. Example:

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
   ```

------
#### [ PowerShell ]

   In PowerShell, run the following `Invoke-WebRequest` command:

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
   ```

   This command invokes the function with an empty event and returns a response. If you're using your own function code rather than the sample function code, you might want to invoke the function with a JSON payload. Example:

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
   ```

------

1. Get the container ID.

   ```
   docker ps
   ```

1. Use the [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) command to stop the container. In this command, replace `3766c4ab331c` with the container ID from the previous step.

   ```
   docker kill 3766c4ab331c
   ```

### Deploying the image
<a name="typescript-image-deploy"></a>

**To upload the image to Amazon ECR and create the Lambda function**

1. Run the [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) command to authenticate the Docker CLI to your Amazon ECR registry.
   + Set the `--region` value to the AWS Region where you want to create the Amazon ECR repository.
   + Replace `111122223333` with your AWS account ID.

   ```
   aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
   ```

1. Create a repository in Amazon ECR using the [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html) command.

   ```
   aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**Note**  
The Amazon ECR repository must be in the same AWS Region as the Lambda function.

   If successful, you see a response like this:

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world",
           "createdAt": "2023-03-09T10:39:01+00:00",
           "imageTagMutability": "MUTABLE",
           "imageScanningConfiguration": {
               "scanOnPush": true
           },
           "encryptionConfiguration": {
               "encryptionType": "AES256"
           }
       }
   }
   ```

1. Copy the `repositoryUri` from the output in the previous step.

1. Run the [docker tag](https://docs.docker.com/engine/reference/commandline/tag/) command to tag your local image into your Amazon ECR repository as the latest version. In this command:
   + `docker-image:test` is the name and [tag](https://docs.docker.com/engine/reference/commandline/build/#tag) of your Docker image. This is the image name and tag that you specified in the `docker build` command.
   + Replace `<ECRrepositoryUri>` with the `repositoryUri` that you copied. Make sure to include `:latest` at the end of the URI.

   ```
   docker tag docker-image:test <ECRrepositoryUri>:latest
   ```

   Example:

   ```
   docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. Run the [docker push](https://docs.docker.com/engine/reference/commandline/push/) command to deploy your local image to the Amazon ECR repository. Make sure to include `:latest` at the end of the repository URI.

   ```
   docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. [Create an execution role](lambda-intro-execution-role.md#permissions-executionrole-api) for the function, if you don't already have one. You need the Amazon Resource Name (ARN) of the role in the next step.

1. Create the Lambda function. For `ImageUri`, specify the repository URI from earlier. Make sure to include `:latest` at the end of the URI.

   ```
   aws lambda create-function \
     --function-name hello-world \
     --package-type Image \
     --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**Note**  
You can create a function using an image in a different AWS account, as long as the image is in the same Region as the Lambda function. For more information, see [Amazon ECR cross-account permissions](images-create.md#configuration-images-xaccount-permissions).

1. Invoke the function.

   ```
   aws lambda invoke --function-name hello-world response.json
   ```

   You should see a response like this:

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. To see the output of the function, check the `response.json` file.

To update the function code, you must build the image again, upload the new image to the Amazon ECR repository, and then use the [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) command to deploy the image to the Lambda function.

Lambda resolves the image tag to a specific image digest. This means that if you point the image tag that was used to deploy the function to a new image in Amazon ECR, Lambda doesn't automatically update the function to use the new image.

To deploy the new image to the same Lambda function, you must use the [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) command, even if the image tag in Amazon ECR remains the same. In the following example, the `--publish` option creates a new version of the function using the updated container image.

```
aws lambda update-function-code \
  --function-name hello-world \
  --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
  --publish
```

# Using the Lambda context object to retrieve TypeScript function information
<a name="typescript-context"></a>

When Lambda runs your function, it passes a context object to the [handler](typescript-handler.md). This object provides methods and properties that provide information about the invocation, function, and execution environment.

To enable type checking for the context object, you must add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency and import the `Context` type. For more information, see [Type definitions for Lambda](lambda-typescript.md#typescript-type-definitions).

**Context methods**
+ `getRemainingTimeInMillis()` – Returns the number of milliseconds left before the execution times out.

**Context properties**
+ `functionName` – The name of the Lambda function.
+ `functionVersion` – The [version](configuration-versions.md) of the function.
+ `invokedFunctionArn` – The Amazon Resource Name (ARN) that's used to invoke the function. Indicates if the invoker specified a version number or alias.
+ `memoryLimitInMB` – The amount of memory that's allocated for the function.
+ `awsRequestId` – The identifier of the invocation request.
+ `logGroupName` – The log group for the function.
+ `logStreamName` – The log stream for the function instance.
+ `identity` – (mobile apps) Information about the Amazon Cognito identity that authorized the request.
  + `cognitoIdentityId` – The authenticated Amazon Cognito identity.
  + `cognitoIdentityPoolId` – The Amazon Cognito identity pool that authorized the invocation.
+ `clientContext` – (mobile apps) Client context that's provided to Lambda by the client application.
  + `client.installation_id`
  + `client.app_title`
  + `client.app_version_name`
  + `client.app_version_code`
  + `client.app_package_name`
  + `env.platform_version`
  + `env.platform`
  + `env.make`
  + `env.model`
  + `env.locale`
  + `Custom` – Custom values that are set by the client application. 
+ `callbackWaitsForEmptyEventLoop` – By default (`true`), when using a callback-based function handler, Lambda waits for the event loop to be empty after the callback runs before ending the function invoke. Set to `false` to send the response and end the invoke immediately after the callback runs instead of waiting for the event loop to be empty. Outstanding events continue to run during the next invocation. Note that Lambda supports callback-based function handlers for Node.js 22 and earlier runtimes only.

**Example index.ts file**  
The following example function logs context information and returns the location of the logs.  
Before using this code in a Lambda function, you must add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency. This package contains the type definitions for Lambda. For more information, see [Type definitions for Lambda](lambda-typescript.md#typescript-type-definitions).

```
import { Context } from 'aws-lambda';
export const lambdaHandler = async (event: string, context: Context): Promise<string> => {
  console.log('Remaining time: ', context.getRemainingTimeInMillis());
  console.log('Function name: ', context.functionName);
  return context.logStreamName;
};
```

# Log and monitor TypeScript Lambda functions
<a name="typescript-logging"></a>

AWS Lambda automatically monitors Lambda functions and sends log entries to Amazon CloudWatch. Your Lambda function comes with a CloudWatch Logs log group and a log stream for each instance of your function. The Lambda runtime environment sends details about each invocation and other output from your function's code to the log stream. For more information about CloudWatch Logs, see [Sending Lambda function logs to CloudWatch Logs](monitoring-cloudwatchlogs.md).

To output logs from your function code, you can use methods on the [console object](https://nodejs.org/docs/latest-v18.x/api/console.html). For more detailed logging, you can use any logging library that writes to `stdout` or `stderr`.

**Topics**
+ [Using logging tools and libraries](#typescript-tools-libraries)
+ [Using Powertools for AWS Lambda (TypeScript) and AWS SAM for structured logging](#typescript-logging-sam)
+ [Using Powertools for AWS Lambda (TypeScript) and the AWS CDK for structured logging](#typescript-logging-cdk)
+ [Viewing logs in the Lambda console](#typescript-logging-console)
+ [Viewing logs in the CloudWatch console](#typescript-logging-cwconsole)

## Using logging tools and libraries
<a name="typescript-tools-libraries"></a>

[Powertools for AWS Lambda (TypeScript)](https://docs.aws.amazon.com/powertools/typescript/) is a developer toolkit to implement Serverless best practices and increase developer velocity. The [Logger utility](https://docs.powertools.aws.dev/lambda/typescript/latest/features/logger/) provides a Lambda optimized logger which includes additional information about function context across all your functions with output structured as JSON. Use this utility to do the following:
+ Capture key fields from the Lambda context, cold start and structures logging output as JSON
+ Log Lambda invocation events when instructed (disabled by default)
+ Print all the logs only for a percentage of invocations via log sampling (disabled by default)
+ Append additional keys to structured log at any point in time
+ Use a custom log formatter (Bring Your Own Formatter) to output logs in a structure compatible with your organization’s Logging RFC

## Using Powertools for AWS Lambda (TypeScript) and AWS SAM for structured logging
<a name="typescript-logging-sam"></a>

Follow the steps below to download, build, and deploy a sample Hello World TypeScript application with integrated [Powertools for AWS Lambda (TypeScript)](https://docs.powertools.aws.dev/lambda-typescript) modules using the AWS SAM. This application implements a basic API backend and uses Powertools for emitting logs, metrics, and traces. It consists of an Amazon API Gateway endpoint and a Lambda function. When you send a GET request to the API Gateway endpoint, the Lambda function invokes, sends logs and metrics using Embedded Metric Format to CloudWatch, and sends traces to AWS X-Ray. The function returns a `hello world` message.

**Prerequisites**

To complete the steps in this section, you must have the following:
+ Node.js 20 or later
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI version 1.75 or later](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). If you have an older version of the AWS SAM CLI, see [Upgrading the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade).

**Deploy a sample AWS SAM application**

1. Initialize the application using the Hello World TypeScript template.

   ```
   sam init --app-template hello-world-powertools-typescript --name sam-app --package-type Zip --runtime nodejs24.x
   ```

1. Build the app.

   ```
   cd sam-app && sam build
   ```

1. Deploy the app.

   ```
   sam deploy --guided
   ```

1. Follow the on-screen prompts. To accept the default options provided in the interactive experience, press `Enter`.
**Note**  
For **HelloWorldFunction may not have authorization defined, Is this okay?**, make sure to enter `y`.

1. Get the URL of the deployed application:

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. Invoke the API endpoint:

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

   If successful, you'll see this response:

   ```
   {"message":"hello world"}
   ```

1. To get the logs for the function, run [sam logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html). For more information, see [Working with logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html) in the *AWS Serverless Application Model Developer Guide*.

   ```
   sam logs --stack-name sam-app
   ```

   The log output looks like this:

   ```
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.552000 START RequestId: 70693159-7e94-4102-a2af-98a6343fb8fb Version: $LATEST
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.594000 2025-08-31T09:33:10.557Z 70693159-7e94-4102-a2af-98a6343fb8fb INFO {"_aws":{"Timestamp":1661938390556,"CloudWatchMetrics":[{"Namespace":"sam-app","Dimensions":[["service"]],"Metrics":[{"Name":"ColdStart","Unit":"Count"}]}]},"service":"helloWorld","ColdStart":1}
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.595000 2025-08-31T09:33:10.595Z 70693159-7e94-4102-a2af-98a6343fb8fb INFO {"level":"INFO","message":"This is an INFO log - sending HTTP 200 - hello world response","service":"helloWorld","timestamp":"2025-08-31T09:33:10.594Z"}
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.655000 2025-08-31T09:33:10.655Z 70693159-7e94-4102-a2af-98a6343fb8fb INFO {"_aws":{"Timestamp":1661938390655,"CloudWatchMetrics":[{"Namespace":"sam-app","Dimensions":[["service"]],"Metrics":[]}]},"service":"helloWorld"}
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.754000 END RequestId: 70693159-7e94-4102-a2af-98a6343fb8fb
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.754000 REPORT RequestId: 70693159-7e94-4102-a2af-98a6343fb8fb Duration: 201.55 ms Billed Duration: 202 ms Memory Size: 128 MB Max Memory Used: 66 MB Init Duration: 252.42 ms
   XRAY TraceId: 1-630f2ad5-1de22b6d29a658a466e7ecf5 SegmentId: 567c116658fbf11a Sampled: true
   ```

1. This is a public API endpoint that is accessible over the internet. We recommend that you delete the endpoint after testing.

   ```
   sam delete
   ```

### Managing log retention
<a name="typescript-log-retention"></a>

Log groups aren't deleted automatically when you delete a function. To avoid storing logs indefinitely, delete the log group, or configure a retention period after which CloudWatch automatically deletes the logs. To set up log retention, add the following to your AWS SAM template:

```
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
    # Omitting other properties
  
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${HelloWorldFunction}"
      RetentionInDays: 7
```

## Using Powertools for AWS Lambda (TypeScript) and the AWS CDK for structured logging
<a name="typescript-logging-cdk"></a>

Follow the steps below to download, build, and deploy a sample Hello World TypeScript application with integrated [Powertools for AWS Lambda (TypeScript)](https://docs.powertools.aws.dev/lambda-typescript) modules using the AWS CDK. This application implements a basic API backend and uses Powertools for emitting logs, metrics, and traces. It consists of an Amazon API Gateway endpoint and a Lambda function. When you send a GET request to the API Gateway endpoint, the Lambda function invokes, sends logs and metrics using Embedded Metric Format to CloudWatch, and sends traces to AWS X-Ray. The function returns a `hello world` message.

**Prerequisites**

To complete the steps in this section, you must have the following:
+ Node.js 20 or later
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK version 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI version 1.75 or later](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). If you have an older version of the AWS SAM CLI, see [Upgrading the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade).

**Deploy a sample AWS CDK application**

1. Create a project directory for your new application.

   ```
   mkdir hello-world
   cd hello-world
   ```

1. Initialize the app.

   ```
   cdk init app --language typescript
   ```

1. Add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency.

   ```
   npm install -D @types/aws-lambda
   ```

1. Install the Powertools [Logger utility](https://docs.aws.amazon.com/powertools/typescript/latest/features/logger/).

   ```
   npm install @aws-lambda-powertools/logger
   ```

1. Open the **lib** directory. You should see a file called **hello-world-stack.ts**. Create new two new files in this directory: **hello-world.function.ts** and **hello-world.ts**.

1. Open **hello-world.function.ts** and add the following code to the file. This is the code for the Lambda function.

   ```
   import { APIGatewayEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
   import { Logger } from '@aws-lambda-powertools/logger';
   const logger = new Logger();
     
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
     logger.info('This is an INFO log - sending HTTP 200 - hello world response');
     return {
       statusCode: 200,
       body: JSON.stringify({
         message: 'hello world',
       }),
     };
   };
   ```

1. Open **hello-world.ts** and add the following code to the file. This contains the [NodejsFunction construct](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html), which creates the Lambda function, configures environment variables for Powertools, and sets log retention to one week. It also includes the [LambdaRestApi construct](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html), which creates the REST API.

   ```
   import { Construct } from 'constructs';
   import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
   import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';
   import { RetentionDays } from 'aws-cdk-lib/aws-logs';
   import { CfnOutput } from 'aws-cdk-lib';
     
   export class HelloWorld extends Construct {
     constructor(scope: Construct, id: string) {
       super(scope, id);
       const helloFunction = new NodejsFunction(this, 'function', {
         environment: {
           Powertools_SERVICE_NAME: 'helloWorld',
           LOG_LEVEL: 'INFO',
         },
         logRetention: RetentionDays.ONE_WEEK,
       });
       const api = new LambdaRestApi(this, 'apigw', {
         handler: helloFunction,
       });
       new CfnOutput(this, 'apiUrl', {
         exportName: 'apiUrl',
         value: api.url,
       });
     }
   }
   ```

1. Open **hello-world-stack.ts**. This is the code that defines your [AWS CDK stack](https://docs.aws.amazon.com/cdk/v2/guide/stacks.html). Replace the code with the following:

   ```
   import { Stack, StackProps } from 'aws-cdk-lib';
   import { Construct } from 'constructs';
   import { HelloWorld } from './hello-world';
       
   export class HelloWorldStack extends Stack {
     constructor(scope: Construct, id: string, props?: StackProps) {
       super(scope, id, props);
       new HelloWorld(this, 'hello-world');
     }
   }
   ```

1. Go back to the project directory.

   ```
   cd hello-world
   ```

1. Deploy your application.

   ```
   cdk deploy
   ```

1. Get the URL of the deployed application:

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?ExportName==`apiUrl`].OutputValue' --output text
   ```

1. Invoke the API endpoint:

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

   If successful, you'll see this response:

   ```
   {"message":"hello world"}
   ```

1. To get the logs for the function, run [sam logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html). For more information, see [Working with logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html) in the *AWS Serverless Application Model Developer Guide*.

   ```
   sam logs --stack-name HelloWorldStack
   ```

   The log output looks like this:

   ```
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.047000 START RequestId: 19ad1007-ff67-40ce-9afe-0af0a9eb512c Version: $LATEST
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.050000 {
   "level": "INFO",
   "message": "This is an INFO log - sending HTTP 200 - hello world response",
   "service": "helloWorld",
   "timestamp": "2025-08-31T14:48:37.048Z",
   "xray_trace_id": "1-630f74c4-2b080cf77680a04f2362bcf2"
   }
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.082000 END RequestId: 19ad1007-ff67-40ce-9afe-0af0a9eb512c
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.082000 REPORT RequestId: 19ad1007-ff67-40ce-9afe-0af0a9eb512c Duration: 34.60 ms Billed Duration: 35 ms Memory Size: 128 MB Max Memory Used: 57 MB Init Duration: 173.48 ms
   ```

1. This is a public API endpoint that is accessible over the internet. We recommend that you delete the endpoint after testing.

   ```
   cdk destroy
   ```

## Viewing logs in the Lambda console
<a name="typescript-logging-console"></a>

You can use the Lambda console to view log output after you invoke a Lambda function.

If your code can be tested from the embedded **Code** editor, you will find logs in the **execution results**. When you use the console test feature to invoke a function, you'll find **Log output** in the **Details** section.

## Viewing logs in the CloudWatch console
<a name="typescript-logging-cwconsole"></a>

You can use the Amazon CloudWatch console to view logs for all Lambda function invocations.

**To view logs on the CloudWatch console**

1. Open the [Log groups page](https://console.aws.amazon.com/cloudwatch/home?#logs:) on the CloudWatch console.

1. Choose the log group for your function (**/aws/lambda/*your-function-name***).

1. Choose a log stream.

Each log stream corresponds to an [instance of your function](lambda-runtime-environment.md). A log stream appears when you update your Lambda function, and when additional instances are created to handle concurrent invocations. To find logs for a specific invocation, we recommend instrumenting your function with AWS X-Ray. X-Ray records details about the request and the log stream in the trace.

# Tracing TypeScript code in AWS Lambda
<a name="typescript-tracing"></a>

Lambda integrates with AWS X-Ray to help you trace, debug, and optimize Lambda applications. You can use X-Ray to trace a request as it traverses resources in your application, which may include Lambda functions and other AWS services.

To send tracing data to X-Ray, you can use one of three SDK libraries:
+ [AWS Distro for OpenTelemetry (ADOT)](https://aws.amazon.com/otel) – A secure, production-ready, AWS-supported distribution of the OpenTelemetry (OTel) SDK.
+ [AWS X-Ray SDK for Node.js](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs.html) – An SDK for generating and sending trace data to X-Ray.
+ [Powertools for AWS Lambda (TypeScript)](https://docs.aws.amazon.com/powertools/typescript/latest/) – A developer toolkit to implement Serverless best practices and increase developer velocity.

Each of the SDKs offer ways to send your telemetry data to the X-Ray service. You can then use X-Ray to view, filter, and gain insights into your application's performance metrics to identify issues and opportunities for optimization.

**Important**  
The X-Ray and Powertools for AWS Lambda SDKs are part of a tightly integrated instrumentation solution offered by AWS. The ADOT Lambda Layers are part of an industry-wide standard for tracing instrumentation that collect more data in general, but may not be suited for all use cases. You can implement end-to-end tracing in X-Ray using either solution. To learn more about choosing between them, see [Choosing between the AWS Distro for Open Telemetry and X-Ray SDKs](https://docs.aws.amazon.com/xray/latest/devguide/xray-instrumenting-your-app.html#xray-instrumenting-choosing).

**Topics**
+ [Using Powertools for AWS Lambda (TypeScript) and AWS SAM for tracing](#typescript-tracing-sam)
+ [Using Powertools for AWS Lambda (TypeScript) and the AWS CDK for tracing](#typescript-tracing-cdk)
+ [Interpreting an X-Ray trace](#typescript-tracing-interpretation)

## Using Powertools for AWS Lambda (TypeScript) and AWS SAM for tracing
<a name="typescript-tracing-sam"></a>

Follow the steps below to download, build, and deploy a sample Hello World TypeScript application with integrated [Powertools for AWS Lambda (TypeScript)](https://docs.powertools.aws.dev/lambda-typescript) modules using the AWS SAM. This application implements a basic API backend and uses Powertools for emitting logs, metrics, and traces. It consists of an Amazon API Gateway endpoint and a Lambda function. When you send a GET request to the API Gateway endpoint, the Lambda function invokes, sends logs and metrics using Embedded Metric Format to CloudWatch, and sends traces to AWS X-Ray. The function returns a `hello world` message.

**Prerequisites**

To complete the steps in this section, you must have the following:
+ Node.js
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI version 1.75 or later](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). If you have an older version of the AWS SAM CLI, see [Upgrading the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade).

**Deploy a sample AWS SAM application**

1. Initialize the application using the Hello World TypeScript template.

   ```
   sam init --app-template hello-world-powertools-typescript --name sam-app --package-type Zip --runtime nodejs24.x --no-tracing
   ```

1. Build the app.

   ```
   cd sam-app && sam build
   ```

1. Deploy the app.

   ```
   sam deploy --guided
   ```

1. Follow the on-screen prompts. To accept the default options provided in the interactive experience, press `Enter`.
**Note**  
For **HelloWorldFunction may not have authorization defined, Is this okay?**, make sure to enter `y`.

1. Get the URL of the deployed application:

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. Invoke the API endpoint:

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

   If successful, you'll see this response:

   ```
   {"message":"hello world"}
   ```

1. To get the traces for the function, run [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html).

   ```
   sam traces
   ```

   The trace output looks like this:

   ```
   XRay Event [revision 1] at (2023-01-31T11:29:40.527000) with id (1-11a2222-111a222222cb33de3b95daf9) and duration (0.483s)
     - 0.425s - sam-app/Prod [HTTP: 200]
       - 0.422s - Lambda [HTTP: 200]
     - 0.406s - sam-app-HelloWorldFunction-Xyzv11a1bcde [HTTP: 200]
     - 0.172s - sam-app-HelloWorldFunction-Xyzv11a1bcde
       - 0.179s - Initialization
       - 0.112s - Invocation
         - 0.052s - ## app.lambdaHandler
           - 0.001s - ### MySubSegment
       - 0.059s - Overhead
   ```

1. This is a public API endpoint that is accessible over the internet. We recommend that you delete the endpoint after testing.

   ```
   sam delete
   ```

X-Ray doesn't trace all requests to your application. X-Ray applies a sampling algorithm to ensure that tracing is efficient, while still providing a representative sample of all requests. The sampling rate is 1 request per second and 5 percent of additional requests. You can't configure the X-Ray sampling rate for your functions.

## Using Powertools for AWS Lambda (TypeScript) and the AWS CDK for tracing
<a name="typescript-tracing-cdk"></a>

Follow the steps below to download, build, and deploy a sample Hello World TypeScript application with integrated [Powertools for AWS Lambda (TypeScript)](https://docs.powertools.aws.dev/lambda-typescript) modules using the AWS CDK. This application implements a basic API backend and uses Powertools for emitting logs, metrics, and traces. It consists of an Amazon API Gateway endpoint and a Lambda function. When you send a GET request to the API Gateway endpoint, the Lambda function invokes, sends logs and metrics using Embedded Metric Format to CloudWatch, and sends traces to AWS X-Ray. The function returns a `hello world` message.

**Prerequisites**

To complete the steps in this section, you must have the following:
+ Node.js
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK version 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI version 1.75 or later](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). If you have an older version of the AWS SAM CLI, see [Upgrading the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade).

**Deploy a sample AWS Cloud Development Kit (AWS CDK) application**

1. Create a project directory for your new application.

   ```
   mkdir hello-world
   cd hello-world
   ```

1. Initialize the app.

   ```
   cdk init app --language typescript
   ```

1. Add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency.

   ```
   npm install -D @types/aws-lambda
   ```

1. Install the Powertools [Tracer utility](https://docs.aws.amazon.com/powertools/typescript/latest/features/tracer/).

   ```
   npm install @aws-lambda-powertools/tracer
   ```

1. Open the **lib** directory. You should see a file called **hello-world-stack.ts**. Create new two new files in this directory: **hello-world.function.ts** and **hello-world.ts**.

1. Open **hello-world.function.ts** and add the following code to the file. This is the code for the Lambda function.

   ```
   import { APIGatewayEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
   import { Tracer } from '@aws-lambda-powertools/tracer';
   const tracer = new Tracer();
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
     // Get facade segment created by Lambda
     const segment = tracer.getSegment();
   
     // Create subsegment for the function and set it as active
     const handlerSegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`);
     tracer.setSegment(handlerSegment);
   
     // Annotate the subsegment with the cold start and serviceName
     tracer.annotateColdStart();
     tracer.addServiceNameAnnotation();
   
     // Add annotation for the awsRequestId
     tracer.putAnnotation('awsRequestId', context.awsRequestId);
     // Create another subsegment and set it as active
     const subsegment = handlerSegment.addNewSubsegment('### MySubSegment');
     tracer.setSegment(subsegment);
     let response: APIGatewayProxyResult = {
       statusCode: 200,
       body: JSON.stringify({
         message: 'hello world',
       }),
     };
     // Close subsegments (the Lambda one is closed automatically)
     subsegment.close(); // (### MySubSegment)
     handlerSegment.close(); // (## index.handler)
   
     // Set the facade segment as active again (the one created by Lambda)
     tracer.setSegment(segment);
     return response;
   };
   ```

1. Open **hello-world.ts** and add the following code to the file. This contains the [NodejsFunction construct](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html), which creates the Lambda function, configures environment variables for Powertools, and sets log retention to one week. It also includes the [LambdaRestApi construct](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html), which creates the REST API.

   ```
   import { Construct } from 'constructs';
   import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
   import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';
   import { CfnOutput } from 'aws-cdk-lib';
   import { Tracing } from 'aws-cdk-lib/aws-lambda';
   
   export class HelloWorld extends Construct {
     constructor(scope: Construct, id: string) {
       super(scope, id);
       const helloFunction = new NodejsFunction(this, 'function', {
         environment: {
           POWERTOOLS_SERVICE_NAME: 'helloWorld',
         },
         tracing: Tracing.ACTIVE,
       });
       const api = new LambdaRestApi(this, 'apigw', {
         handler: helloFunction,
       });
       new CfnOutput(this, 'apiUrl', {
         exportName: 'apiUrl',
         value: api.url,
       });
     }
   }
   ```

1. Open **hello-world-stack.ts**. This is the code that defines your [AWS CDK stack](https://docs.aws.amazon.com/cdk/v2/guide/stacks.html). Replace the code with the following:

   ```
   import { Stack, StackProps } from 'aws-cdk-lib';
   import { Construct } from 'constructs';
   import { HelloWorld } from './hello-world';
     
   export class HelloWorldStack extends Stack {
     constructor(scope: Construct, id: string, props?: StackProps) {
       super(scope, id, props);
       new HelloWorld(this, 'hello-world');
     }
   }
   ```

1. Deploy your application.

   ```
   cd ..
   cdk deploy
   ```

1. Get the URL of the deployed application:

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?ExportName==`apiUrl`].OutputValue' --output text
   ```

1. Invoke the API endpoint:

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

   If successful, you'll see this response:

   ```
   {"message":"hello world"}
   ```

1. To get the traces for the function, run [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html).

   ```
   sam traces
   ```

   The trace output looks like this:

   ```
   XRay Event [revision 1] at (2023-01-31T11:50:06.997000) with id (1-11a2222-111a222222cb33de3b95daf9) and duration (0.449s)
     - 0.350s - HelloWorldStack-helloworldfunction111A2BCD-Xyzv11a1bcde [HTTP: 200]
     - 0.157s - HelloWorldStack-helloworldfunction111A2BCD-Xyzv11a1bcde
       - 0.169s - Initialization
       - 0.058s - Invocation
         - 0.055s - ## index.handler
           - 0.000s - ### MySubSegment
       - 0.099s - Overhead
   ```

1. This is a public API endpoint that is accessible over the internet. We recommend that you delete the endpoint after testing.

   ```
   cdk destroy
   ```

## Interpreting an X-Ray trace
<a name="typescript-tracing-interpretation"></a>

After you've configured active tracing, you can observe specific requests through your application. The [ X-Ray trace map](https://docs.aws.amazon.com/xray/latest/devguide/xray-console-servicemap.html) provides information about your application and all its components. The following example shows a trace from the sample application:

![\[\]](http://docs.aws.amazon.com/lambda/latest/dg/images/sample-typescript-servicemap.png)
