

# Building Lambda functions with Rust
<a name="lambda-rust"></a>

Because Rust compiles to native code, you don't need a dedicated runtime to run Rust code on Lambda. Instead, use the [Rust runtime client](https://github.com/aws/aws-lambda-rust-runtime) to build your project locally, and then deploy it to Lambda using an [OS-only runtime](runtimes-provided.md). When you use an OS-only runtime, Lambda automatically keeps the operating system up to date with the latest patches.

**Tools and libraries for Rust**
+ [AWS SDK for Rust](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/getting-started.html): The AWS SDK for Rust provides Rust APIs to interact with Amazon Web Services infrastructure services.
+  [Rust runtime client for Lambda](https://github.com/aws/aws-lambda-rust-runtime): The Rust runtime client makes it easy to run Lambda functions written in Rust.
+ [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html): This is a third-party open-source extension to the Cargo command-line tool that simplifies building and deploying Rust Lambda functions.
+ [Lambda HTTP](https://github.com/aws/aws-lambda-rust-runtime/tree/main/lambda-http): This library provides a wrapper to work with HTTP events.
+  [Lambda Extension](https://github.com/aws/aws-lambda-rust-runtime/tree/main/lambda-extension): This library provides support to write Lambda Extensions with Rust. 
+ [AWS Lambda Events](https://crates.io/crates/aws_lambda_events): This library provides type definitions for common event source integrations.

**Sample Lambda applications for Rust**
+ [Basic Lambda function](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/basic-lambda): A Rust function that shows how to process basic events.
+ [Lambda function with error handling](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/basic-error-handling): A Rust function that shows how to handle custom Rust errors in Lambda.
+ [Lambda function with shared resources](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/basic-shared-resource): A Rust project that initializes shared resources before creating the Lambda function.
+ [Lambda HTTP events](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/http-basic-lambda): A Rust function that handles HTTP events.
+ [Lambda HTTP events with CORS headers](https://github.com/aws/aws-lambda-rust-runtime/blob/main//examples/http-cors): A Rust function that uses Tower to inject CORS headers.
+ [Lambda REST API](https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/http-axum-diesel): A REST API that uses Axum and Diesel to connect to a PostgreSQL database.
+ [Serverless Rust demo](https://github.com/aws-samples/serverless-rust-demo/): A Rust project that shows the use of Lambda's Rust libraries, logging, environment variables, and the AWS SDK.
+ [Basic Lambda Extension](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/extension-basic): A Rust extension that shows how to process basic extension events.
+ [Lambda Logs Amazon Data Firehose Extension](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/extension-logs-kinesis-firehose): A Rust extension that shows how to send Lambda logs to Firehose.

**Topics**
+ [Define Lambda function handlers in Rust](rust-handler.md)
+ [Using the Lambda context object to retrieve Rust function information](rust-context.md)
+ [Processing HTTP events with Rust](rust-http-events.md)
+ [Deploy Rust Lambda functions with .zip file archives](rust-package.md)
+ [Working with layers for Rust Lambda functions](rust-layers.md)
+ [Log and monitor Rust Lambda functions](rust-logging.md)

# Define Lambda function handlers in Rust
<a name="rust-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 Rust, including project initialization, naming conventions, and best practices. This page also includes an example of a Rust Lambda function that takes in information about an order, produces a text file receipt, and puts this file in an Amazon Simple Storage Service (S3) bucket. For more information about how to deploy your function after writing it, see [Deploy Rust Lambda functions with .zip file archives](rust-package.md).

**Topics**
+ [Setting up your Rust handler project](#rust-handler-setup)
+ [Example Rust Lambda function code](#rust-example-code)
+ [Valid class definitions for Rust handlers](#rust-handler-signatures)
+ [Handler naming conventions](#rust-example-naming)
+ [Defining and accessing the input event object](#rust-handler-input)
+ [Accessing and using the Lambda context object](#rust-example-context)
+ [Using the AWS SDK for Rust in your handler](#rust-example-sdk-usage)
+ [Accessing environment variables](#rust-example-envvars)
+ [Using shared state](#rust-shared-state)
+ [Code best practices for Rust Lambda functions](#rust-best-practices)

## Setting up your Rust handler project
<a name="rust-handler-setup"></a>

When working with Lambda functions in Rust, the process involves writing your code, compiling it, and deploying the compiled artifacts to Lambda. The simplest way to set up a Lambda handler project in Rust is to use the [AWS Lambda Runtime for Rust](https://github.com/aws/aws-lambda-rust-runtime). Despite its name, the AWS Lambda Runtime for Rust is not a managed runtime in the same sense as it is in Lambda for Python, Java, or Node.js. Instead, the AWS Lambda Runtime for Rust is a crate (`lambda_runtime`) that supports writing Lambda functions in Rust and interfacing with AWS Lambda's execution environment.

Use the following command to install [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html), a third-party open-source extension to the Cargo command-line tool that simplifies building and deploying Rust Lambda functions:

```
cargo install cargo-lambda
```

After you successfully install `cargo-lambda`, use the following command to initialize a new Rust Lambda function handler project:

```
cargo lambda new example-rust
```

When you run this command, the command line interface (CLI) asks you a couple of questions about your Lambda function:
+ **HTTP function** – If you intend to invoke your function via [API Gateway](services-apigateway.md) or a [function URL](urls-configuration.md), answer **Yes**. Otherwise, answer **No**. In the example code on this page, we invoke our function with a custom JSON event, so we answer **No**.
+ **Event type** – If you intend to use a predefined event shape to invoke your function, select the correct expected event type. Otherwise, leave this option blank. In the example code on this page, we invoke our function with a custom JSON event, so we leave this option blank.

After the command runs successfully, enter the main directory of your project:

```
cd example-rust
```

This command generates a `generic_handler.rs` file and a `main.rs` file in the `src` directory. The `generic_handler.rs` can be used to customize a generic event handler. The `main.rs` file contains your main application logic. The `Cargo.toml` file contains metadata about your package and lists its external dependencies.

## Example Rust Lambda function code
<a name="rust-example-code"></a>

The following example Rust Lambda function code takes in information about an order, produces a text file receipt, and puts this file in an Amazon S3 bucket.

**Example `main.rs` Lambda function**  

```
use aws_sdk_s3::{Client, primitives::ByteStream};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::env;

#[derive(Deserialize, Serialize)]
struct Order {
    order_id: String,
    amount: f64,
    item: String,
}

async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
    let payload = event.payload;

    // Deserialize the incoming event into Order struct
    let order: Order = serde_json::from_value(payload)?;

    let bucket_name = env::var("RECEIPT_BUCKET")
        .map_err(|_| "RECEIPT_BUCKET environment variable is not set")?;

    let receipt_content = format!(
        "OrderID: {}\nAmount: ${:.2}\nItem: {}",
        order.order_id, order.amount, order.item
    );
    let key = format!("receipts/{}.txt", order.order_id);

    let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
    let s3_client = Client::new(&config);

    upload_receipt_to_s3(&s3_client, &bucket_name, &key, &receipt_content).await?;

    Ok("Success".to_string())
}

async fn upload_receipt_to_s3(
    client: &Client,
    bucket_name: &str,
    key: &str,
    content: &str,
) -> Result<(), Error> {
    client
        .put_object()
        .bucket(bucket_name)
        .key(key)
        .body(ByteStream::from(content.as_bytes().to_vec()))  // Fixed conversion
        .content_type("text/plain")
        .send()
        .await?;

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    run(service_fn(function_handler)).await
}
```

This `main.rs` file contains the following sections of code:
+ `use` statements: Use these to import Rust crates and methods that your Lambda function requires.
+ `#[derive(Deserialize, Serialize)]`: Define the shape of the expected input event in this Rust struct.
+ `async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>`: This is the **main handler method**, which contains your main application logic.
+ `async fn upload_receipt_to_s3 (...)`: This is a helper method that's referenced by the main `function_handler` method.
+ `#[tokio::main]`: This is a macro that marks the entry point of a Rust program. It also sets up a [Tokio runtime](https://docs.rs/tokio/latest/tokio/runtime/index.html), which allows your `main()` method to use `async`/`await` and run asynchronously.
+ `async fn main() -> Result<(), Error>`: The `main()` function is the entry point of your code. Within it, we specify `function_handler` as the main handler method.

### Sample Cargo.toml file
<a name="rust-cargo-toml"></a>

The following `Cargo.toml` file accompanies this function.

```
[package]
name = "example-rust"
version = "0.1.0"
edition = "2024"

[dependencies]
aws-config = "1.5.18"
aws-sdk-s3 = "1.78.0"
lambda_runtime = "0.13.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
```

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.

## Valid class definitions for Rust handlers
<a name="rust-handler-signatures"></a>

In most cases, Lambda handler signatures that you define in Rust will have the following format:

```
async fn function_handler(event: LambdaEvent<T>) -> Result<U, Error>
```

For this handler:
+ The name of this handler is `function_handler`.
+ The singular input to the handler is event, and is of type `LambdaEvent<T>`.
  + `LambdaEvent` is a wrapper that comes from the `lambda_runtime` crate. Using this wrapper gives you access to the context object, which includes Lambda-specific metadata such as the request ID of the invocation.
  + `T` is the deserialized event type. For example, this can be `serde_json::Value`, which allows the handler to take in any generic JSON input. Alternatively, this can be a type like `ApiGatewayProxyRequest` if your function expects a specific, pre-defined input type.
+ The return type of the handler is `Result<U, Error>`.
  + `U` is the deserialized output type. `U` must implement the `serde::Serialize` trait so Lambda can convert the return value to JSON. For example, `U` can be a simple type like `String`, `serde_json::Value`, or a custom struct as long as it implements `Serialize`. When your code reaches an Ok(U) statement, this indicates successful execution, and your function returns a value of type `U`.
  + When your code encounters an error (i.e. `Err(Error)`), your function logs the error in Amazon CloudWatch and returns an error response of type `Error`.

In our example, the handler signature looks like the following:

```
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>
```

Other valid handler signatures can feature the following:
+ Omitting the `LambdaEvent` wrapper – If you omit `LambdaEvent`, you lose access to the Lambda context object within your function. The following is an example of this type of signature:

  ```
  async fn handler(event: serde_json::Value) -> Result<String, Error>
  ```
+ Using the unit type as an input – For Rust, you can use the unit type to represent an empty input. This is commonly used for functions with periodic, scheduled invocations. The following is an example of this type of signature:

  ```
  async fn handler(_: ()) -> Result<Value, Error>
  ```

## Handler naming conventions
<a name="rust-example-naming"></a>

Lambda handlers in Rust don’t have strict naming restrictions. Although you can use any name for your handler, function names in Rust are generally in `snake_case`.

For smaller applications, such as in this example, you can use a single `main.rs` file to contain all of your code. For larger projects, `main.rs` should contain the entry point to your function, but you can have additional files for that separate your code into logical modules. For example, you might have the following file structure:

```
/example-rust
│── src/
│   ├── main.rs        # Entry point
│   ├── handler.rs     # Contains main handler
│   ├── services.rs    # [Optional] Back-end service calls
│   ├── models.rs      # [Optional] Data models
│── Cargo.toml
```

## Defining and accessing the input event object
<a name="rust-handler-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"
}
```

In Rust, you can define the shape of the expected input event in a struct. In this example, we define the following struct to represent an `Order`:

```
#[derive(Deserialize, Serialize)]
struct Order {
    order_id: String,
    amount: f64,
    item: String,
}
```

This struct matches the expected input shape. In this example, the `#[derive(Deserialize, Serialize)]` macro automatically generates code for serialization and deserialization. This means that we can deserialize the generic input JSON type into our struct using the `serde_json::from_value()` method. This is illustrated in the first few lines of the handler:

```
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
    let payload = event.payload;

    // Deserialize the incoming event into Order struct
    let order: Order = serde_json::from_value(payload)?;
    ...
}
```

You can then access the fields of the object. For example, `order.order_id` retrieves the value of `order_id` from the original input.

### Pre-defined input event types
<a name="rust-input-event-types"></a>

There are many pre-defined input event types available in the `aws_lambda_events` crate. For example, if you intend to invoke your function with API Gateway, including the following import:

```
use aws_lambda_events::event::apigw::ApiGatewayProxyRequest;
```

Then, make sure your main handler uses the following signature:

```
async fn handler(event: LambdaEvent<ApiGatewayProxyRequest>) -> Result<String, Error> {
    let body = event.payload.body.unwrap_or_default();
    ...
}
```

Refer to the [aws\$1lambda\$1events crate](https://crates.io/crates/aws_lambda_events) for more information about other pre-defined input event types.

## Accessing and using the Lambda context object
<a name="rust-example-context"></a>

The Lambda [context object](rust-context.md) contains information about the invocation, function, and execution environment. In Rust, the `LambdaEvent` wrapper includes the context object. For example, you can use the context object to retrieve the request ID of the current invocation with the following code:

```
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
    let request_id = event.context.request_id;
    ...
}
```

For more information about the context object, see [Using the Lambda context object to retrieve Rust function information](rust-context.md).

## Using the AWS SDK for Rust in your handler
<a name="rust-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 Rust](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/welcome.html).

To add SDK dependencies to your function, add them in your `Cargo.toml` file. We recommend only adding the libraries that you need for your function. In the example code earlier, we used the `aws_sdk_s3::Client`. In the `Cargo.toml` file, you can add this dependency by adding the following line under the `[dependencies]` section:

```
aws-sdk-s3 = "1.78.0"
```

**Note**  
This may not be the most recent version. Choose the appropriate version for your application.

The, import the dependencies directly in your code:

```
use aws_sdk_s3::{Client, primitives::ByteStream};
```

The example code then initializes an Amazon S3 client as follows:

```
let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let s3_client = Client::new(&config);
```

After you initialize your SDK client, you can then use it to interact with other AWS services. The example code calls the Amazon S3 `PutObject` API in the `upload_receipt_to_s3` helper function.

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

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

```
let bucket_name = env::var("RECEIPT_BUCKET")
    .map_err(|_| "RECEIPT_BUCKET environment variable is not set")?;
```

## Using shared state
<a name="rust-shared-state"></a>

You can declare shared variables that are independent of your Lambda function's handler code. These variables can help you load state information during the [Init phase](lambda-runtime-environment.md#runtimes-lifecycle-ib), before your function receives any events. For example, you can modify the code on this page to use shared state when initializing the Amazon S3 client by updating the `main` function and handler signature:

```
async fn function_handler(client: &Client, event: LambdaEvent<Value>) -> Result<String, Error> {
    ...
    upload_receipt_to_s3(client, &bucket_name, &key, &receipt_content).await?;
    ...
}

...
      
#[tokio::main]
async fn main() -> Result<(), Error> {
    let shared_config = aws_config::from_env().load().await;
    let client = Client::new(&shared_config);
    let shared_client = &client;
    lambda_runtime::run(service_fn(move |event: LambdaEvent<Request>| async move {
        handler(&shared_client, event).await
    }))
    .await
```

## Code best practices for Rust Lambda functions
<a name="rust-best-practices"></a>

Adhere to the guidelines in the following list to use best coding practices when building your Lambda functions:
+ **Separate the Lambda handler from your core logic.** This allows you to make a more unit-testable function.
+ **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/).

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

When Lambda runs your function, it adds a context object to the LambdaEvent that the [handler](rust-handler.md) receives. This object provides properties with information about the invocation, function, and execution environment.

**Context properties**
+  `request_id`: The AWS request ID generated by the Lambda service. 
+  `deadline`: The execution deadline for the current invocation in milliseconds.
+  `invoked_function_arn`: The Amazon Resource Name (ARN) of the Lambda function being invoked.
+  `xray_trace_id`: The AWS X-Ray trace ID for the current invocation. 
+  `client_content`: The client context object sent by the AWS mobile SDK. This field is empty unless the function is invoked using an AWS mobile SDK. 
+  `identity`: The Amazon Cognito identity that invoked the function. This field is empty unless the invocation request to the Lambda APIs was made using AWS credentials issued by Amazon Cognito identity pools.
+  `env_config`: The Lambda function configuration from the local environment variables. This property includes information such as the function name, memory allocation, version, and log streams.

## Accessing invoke context information
<a name="rust-context-invoke"></a>

Lambda functions have access to metadata about their environment and the invocation request. The `LambaEvent` object that your function handler receives includes the `context` metadata:

```
use lambda_runtime::{service_fn, LambdaEvent, Error};
use serde_json::{json, Value};

async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    let invoked_function_arn = event.context.invoked_function_arn;
    Ok(json!({ "message": format!("Hello, this is function {invoked_function_arn}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}
```

# Processing HTTP events with Rust
<a name="rust-http-events"></a>

Amazon API Gateway APIs, Application Load Balancers, and [Lambda function URLs](urls-configuration.md) can send HTTP events to Lambda. You can use the [aws\$1lambda\$1events](https://crates.io/crates/aws_lambda_events) crate from crates.io to process events from these sources.

**Example — Handle API Gateway proxy request**  
Note the following:  
+ `use aws_lambda_events::apigw::{ApiGatewayProxyRequest, ApiGatewayProxyResponse}`: The [aws\$1lambda\$1events](https://crates.io/crates/aws-lambda-events) crate includes many Lambda events. To reduce compilation time, use feature flags to activate the events you need. Example: `aws_lambda_events = { version = "0.8.3", default-features = false, features = ["apigw"] }`.
+ `use http::HeaderMap`: This import requires you to add the [http](https://crates.io/crates/http) crate to your dependencies.

```
use aws_lambda_events::apigw::{ApiGatewayProxyRequest, ApiGatewayProxyResponse};
use http::HeaderMap;
use lambda_runtime::{service_fn, Error, LambdaEvent};

async fn handler(
    _event: LambdaEvent<ApiGatewayProxyRequest>,
) -> Result<ApiGatewayProxyResponse, Error> {
    let mut headers = HeaderMap::new();
    headers.insert("content-type", "text/html".parse().unwrap());
    let resp = ApiGatewayProxyResponse {
        status_code: 200,
        multi_value_headers: headers.clone(),
        is_base64_encoded: false,
        body: Some("Hello AWS Lambda HTTP request".into()),
        headers,
    };
    Ok(resp)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}
```

The [Rust runtime client for Lambda](https://github.com/aws/aws-lambda-rust-runtime) also provides an abstraction over these event types that allows you to work with native HTTP types, regardless of which service sends the events. The following code is equivalent to the previous example, and it works out of the box with Lambda function URLs, Application Load Balancers, and API Gateway.

**Note**  
The [lambda\$1http](https://crates.io/crates/lambda_http) crate uses the [lambda\$1runtime](https://crates.io/crates/lambda_runtime) crate underneath. You don't have to import `lambda_runtime` separately.

**Example — Handle HTTP requests**  

```
use lambda_http::{service_fn, Error, IntoResponse, Request, RequestExt, Response};

async fn handler(event: Request) -> Result<impl IntoResponse, Error> {
    let resp = Response::builder()
        .status(200)
        .header("content-type", "text/html")
        .body("Hello AWS Lambda HTTP request")
        .map_err(Box::new)?;
    Ok(resp)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_http::run(service_fn(handler)).await
}
```

For another example of how to use `lambda_http`, see the [http-axum code sample](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/http-axum/src/main.rs) on the AWS Labs GitHub repository.

**Sample HTTP Lambda events for Rust**
+ [Lambda HTTP events](https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/http-basic-lambda): A Rust function that handles HTTP events.
+ [Lambda HTTP events with CORS headers](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/http-cors): A Rust function that uses Tower to inject CORS headers.
+ [Lambda HTTP events with shared resources](https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/basic-shared-resource): A Rust function that uses shared resources initialized before the function handler is created.

# Deploy Rust Lambda functions with .zip file archives
<a name="rust-package"></a>

This page describes how to compile your Rust function, and then deploy the compiled binary to AWS Lambda using [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html). It also shows how to deploy the compiled binary with the AWS Command Line Interface and the AWS Serverless Application Model CLI.

**Topics**
+ [Prerequisites](#rust-package-prerequisites)
+ [Building Rust functions on macOS, Windows, or Linux](#rust-package-build)
+ [Deploying the Rust function binary with Cargo Lambda](#rust-deploy-cargo)
+ [Invoking your Rust function with Cargo Lambda](#rust-invoke-function)

## Prerequisites
<a name="rust-package-prerequisites"></a>
+ [Rust](https://www.rust-lang.org/tools/install)
+ [AWS CLI version 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)

## Building Rust functions on macOS, Windows, or Linux
<a name="rust-package-build"></a>

The following steps demonstrate how to create the project for your first Lambda function with Rust and compile it with [Cargo Lambda](https://www.cargo-lambda.info/), a third-party open-source extension to the Cargo command-line tool that simplifies building and deploying Rust Lambda functions.

1. Install [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html), a third-party open-source extension to the Cargo command-line tool that simplifies building and deploying Rust Lambda functions:

   ```
   cargo install cargo-lambda
   ```

   For other installation options, see [Installation](https://www.cargo-lambda.info/guide/installation.html) in the Cargo Lambda documentation.

1. Create the package structure. This command creates some basic function code in `src/main.rs`. You can use this code for testing or replace it with your own.

   ```
   cargo lambda new my-function
   ```

1. Inside the package's root directory, run the [build](https://www.cargo-lambda.info/commands/build.html) subcommand to compile the code in your function.

   ```
   cargo lambda build --release
   ```

   (Optional) If you want to use AWS Graviton2 on Lambda, add the `--arm64` flag to compile your code for ARM CPUs.

   ```
   cargo lambda build --release --arm64
   ```

1. Before deploying your Rust function, configure AWS credentials on your machine.

   ```
   aws configure
   ```

## Deploying the Rust function binary with Cargo Lambda
<a name="rust-deploy-cargo"></a>

Use the [deploy](https://www.cargo-lambda.info/commands/deploy.html) subcommand to deploy the compiled binary to Lambda. This command creates an [execution role](lambda-intro-execution-role.md) and then creates the Lambda function. To specify an existing execution role, use the [--iam-role flag](https://www.cargo-lambda.info/commands/deploy.html#iam-roles).

```
cargo lambda deploy my-function
```

### Deploying your Rust function binary with the AWS CLI
<a name="rust-deploy-aws-cli"></a>

You can also deploy your binary with the AWS CLI.

1. Use the [build](https://www.cargo-lambda.info/commands/build.html) subcommand to build the .zip deployment package.

   ```
   cargo lambda build --release --output-format zip
   ```

1. To deploy the .zip package to Lambda, run the [create-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) command.
   + For `--runtime`, specify `provided.al2023`. This is an [OS-only runtime](runtimes-provided.md). OS-only runtimes are used to deploy compiled binaries and custom runtimes to Lambda.
   + For `--role`, specify the ARN of the [execution role](lambda-intro-execution-role.md).

   ```
   aws lambda create-function \
        --function-name my-function \
        --runtime provided.al2023 \
        --role arn:aws:iam::111122223333:role/lambda-role \
        --handler rust.handler \
        --zip-file fileb://target/lambda/my-function/bootstrap.zip
   ```

### Deploying your Rust function binary with the AWS SAM CLI
<a name="rust-deploy-sam-cli"></a>

You can also deploy your binary with the AWS SAM CLI.

1. Create an AWS SAM template with the resource and property definition. For `Runtime`, specify `provided.al2023`. This is an [OS-only runtime](runtimes-provided.md). OS-only runtimes are used to deploy compiled binaries and custom runtimes to Lambda.

   For more information about deploying Lambda functions using AWS SAM, see [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html) in the *AWS Serverless Application Model Developer Guide*.  
**Example SAM resource and property definition for a Rust binary**  

   ```
   AWSTemplateFormatVersion: '2010-09-09'
   Transform: AWS::Serverless-2016-10-31
   Description: SAM template for Rust binaries
   Resources:
     RustFunction:
       Type: AWS::Serverless::Function 
       Properties:
         CodeUri: target/lambda/my-function/
         Handler: rust.handler
         Runtime: provided.al2023
   Outputs:
     RustFunction:
       Description: "Lambda Function ARN"
       Value: !GetAtt RustFunction.Arn
   ```

1. Use the [build](https://www.cargo-lambda.info/commands/build.html) subcommand to compile the function.

   ```
   cargo lambda build --release
   ```

1. Use the [sam deploy](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html) command to deploy the function to Lambda.

   ```
   sam deploy --guided
   ```

For more information about building Rust functions with the AWS SAM CLI, see [Building Rust Lambda functions with Cargo Lambda](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/building-rust.html) in the *AWS Serverless Application Model Developer Guide*.

## Invoking your Rust function with Cargo Lambda
<a name="rust-invoke-function"></a>

Use the [invoke](https://www.cargo-lambda.info/commands/invoke.html) subcommand to test your function with a payload.

```
cargo lambda invoke --remote --data-ascii '{"command": "Hello world"}' my-function
```

### Invoking your Rust function with the AWS CLI
<a name="rust-invoke-cli"></a>

You can also use the AWS CLI to invoke the function.

```
aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"command": "Hello world"}' /tmp/out.txt
```

The **cli-binary-format** option is required if you're using AWS CLI version 2. To make this the default setting, run `aws configure set cli-binary-format raw-in-base64-out`. For more information, see [AWS CLI supported global command line options](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list) in the *AWS Command Line Interface User Guide for Version 2*.

# Working with layers for Rust Lambda functions
<a name="rust-layers"></a>

We don't recommend using [layers](chapter-layers.md) to manage dependencies for Lambda functions written in Rust. This is because Lambda functions in Rust compile into a single executable, which you provide to Lambda when you deploy your function. This executable contains your compiled function code, along with all of its dependencies. Using layers not only complicates this process, but also leads to increased cold start times because your functions need to manually load extra assemblies into memory during the init phase.

To use external dependencies with your Rust handlers, include them directly in your deployment package. By doing so, you simplify the deployment process and also take advantage of built-in Rust compiler optimizations. For an example of how to import and use a dependency like the AWS SDK for Rust in your function, see [Define Lambda function handlers in Rust](rust-handler.md).

# Log and monitor Rust Lambda functions
<a name="rust-logging"></a>

AWS Lambda automatically monitors Lambda functions on your behalf and sends logs 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 to the log stream, and relays logs and other output from your function's code. For more information, see [Sending Lambda function logs to CloudWatch Logs](monitoring-cloudwatchlogs.md). For information about configuring log formats, see [Configuring JSON and plain text log formats](monitoring-cloudwatchlogs-logformat.md). This page describes how to produce log output from your Lambda function's code.

## Creating a function that writes logs
<a name="rust-logging-function"></a>

To output logs from your function code, you can use any logging function that writes to `stdout` or `stderr`, such as the `println!` macro. The following example uses `println!` to print a message when the function handler starts and before it finishes.

```
use lambda_runtime::{service_fn, LambdaEvent, Error};
use serde_json::{json, Value};
async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    println!("Rust function invoked");
    let payload = event.payload;
    let first_name = payload["firstName"].as_str().unwrap_or("world");
    println!("Rust function responds to {}", &first_name);
    Ok(json!({ "message": format!("Hello, {first_name}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}
```

## Implementing advanced logging with the Tracing crate
<a name="rust-logging-tracing"></a>

[Tracing](https://crates.io/crates/tracing) is a framework for instrumenting Rust programs to collect structured, event-based diagnostic information. This framework provides utilities to customize logging output levels and formats, like creating structured JSON log messages. To use this framework, you must initialize a `subscriber` before implementing the function handler. Then, you can use tracing macros like `debug`, `info`, and `error`, to specify the level of logging that you want for each scenario.

**Example — Using the Tracing crate**  
Note the following:  
+ `tracing_subscriber::fmt().json()`: When this option is included, logs are formatted in JSON. To use this option, you must include the `json` feature in the `tracing-subscriber` dependency (for example,`tracing-subscriber = { version = "0.3.11", features = ["json"] }`).
+ `#[tracing::instrument(skip(event), fields(req_id = %event.context.request_id))]`: This annotation generates a span every time the handler is invoked. The span adds the request ID to each log line.
+ `{ %first_name }`: This construct adds the `first_name` field to the log line where it's used. The value for this field corresponds to the variable with the same name.

```
use lambda_runtime::{service_fn, Error, LambdaEvent};
use serde_json::{json, Value};
#[tracing::instrument(skip(event), fields(req_id = %event.context.request_id))]
async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    tracing::info!("Rust function invoked");
    let payload = event.payload;
    let first_name = payload["firstName"].as_str().unwrap_or("world");
    tracing::info!({ %first_name }, "Rust function responds to event");
    Ok(json!({ "message": format!("Hello, {first_name}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt().json()
        .with_max_level(tracing::Level::INFO)
        // this needs to be set to remove duplicated information in the log.
        .with_current_span(false)
        // this needs to be set to false, otherwise ANSI color codes will
        // show up in a confusing manner in CloudWatch logs.
        .with_ansi(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        // remove the name of the function from every log entry
        .with_target(false)
        .init();
    lambda_runtime::run(service_fn(handler)).await
}
```

When this Rust function is invoked, it prints two log lines similar to the following:

```
{"level":"INFO","fields":{"message":"Rust function invoked"},"spans":[{"req_id":"45daaaa7-1a72-470c-9a62-e79860044bb5","name":"handler"}]}
{"level":"INFO","fields":{"message":"Rust function responds to event","first_name":"David"},"spans":[{"req_id":"45daaaa7-1a72-470c-9a62-e79860044bb5","name":"handler"}]}
```