はじめに
2025年11月14日、AWS LambdaでRustのサポートがGA(General Availability)になりました。
これまでは「experimental」として扱われていましたが、今回の発表で正式にAWS SupportとLambda SLAの対象となりました。
この記事では、RustでLambda関数を作成してデプロイするまでの流れを実際に試してみます。
開発環境は以下の通りです。
- M2 Mac
- zsh
- Rust 1.91.1
必要なツール
RustでLambda関数を開発するために、以下のツールを使用します。
Rust
まだRustをインストールしていない場合は、rustupを使ってインストールします。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Cargo Lambda
Cargo Lambdaは、RustでLambda関数をビルド・デプロイするためのCargoの拡張ツールです。
AWSも公式にこのツールの使用を推奨しています。
macOSの場合はHomebrewでインストールできます。
brew tap cargo-lambda/cargo-lambda
brew install cargo-lambda
インストール後、バージョンを確認しておきます。
$ cargo lambda --version
cargo-lambda 1.8.6 (345c38a 2025-07-18Z)
Lambda関数を作成する
プロジェクトの作成
cargo lambda newコマンドで新しいプロジェクトを作成します。
$ cargo lambda new hello-kane8n-cargo-lambda
> Is this function an HTTP function? No
> Event type that this function receives
$
HTTP関数にするかどうかを聞かれますが、今回はシンプルな関数を作成するのでNoを選択します。
その後にイベントタイプも聞かれますが、今回は簡単なサンプルプログラムを実行するだけなので空のままEnterキーを押します。
作成されたプロジェクトの構成は以下の通りです。
$ tree hello-kane8n-cargo-lambda/
hello-kane8n-cargo-lambda/
├── Cargo.toml
├── README.md
└── src
├── generic_handler.rs
└── main.rs
2 directories, 4 files
生成されたコードの確認
Cargo.tomlを確認してみます。
[package]
name = "hello-kane8n-cargo-lambda"
version = "0.1.0"
edition = "2021"
[dependencies]
lambda_runtime = "1.0.1"
serde = "1"
tokio = { version = "1", features = ["macros"] }
lambda_runtimeクレートがLambdaのランタイムを提供し、非同期処理にはtokioが使われています。
次にsrc/main.rsを確認します。
use lambda_runtime::{run, service_fn, tracing, Error};
mod generic_handler;
use generic_handler::function_handler;
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing::init_default_subscriber();
run(service_fn(function_handler)).await
}
main関数では、generic_handlerモジュールのfunction_handler関数をLambdaのエントリーポイントとして登録しています。
次にsrc/generic_handler.rsを確認します。
use lambda_runtime::{Error, LambdaEvent};
use serde::{Deserialize, Serialize};
/// This is a made-up example. Incoming messages come into the runtime as unicode
/// strings in json format, which can map to any structure that implements `serde::Deserialize`
/// The runtime pays no attention to the contents of the incoming message payload.
#[derive(Deserialize)]
pub(crate) struct IncomingMessage {
command: String,
}
/// This is a made-up example of what an outgoing message structure may look like.
/// There is no restriction on what it can be. The runtime requires responses
/// to be serialized into json. The runtime pays no attention
/// to the contents of the outgoing message payload.
#[derive(Serialize)]
pub(crate) struct OutgoingMessage {
req_id: String,
msg: String,
}
/// This is the main body for the function.
/// Write your code inside it.
/// There are some code example in the following URLs:
/// - https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/examples
/// - https://github.com/aws-samples/serverless-rust-demo/
pub(crate) async fn function_handler(event: LambdaEvent<IncomingMessage>) -> Result<OutgoingMessage, Error> {
// Extract some useful info from the request
let command = event.payload.command;
// Prepare the outgoing message
let resp = OutgoingMessage {
req_id: event.context.request_id,
msg: format!("Command {}.", command),
};
// Return `OutgoingMessage` (it will be serialized to JSON automatically by the runtime)
Ok(resp)
}
#[cfg(test)]
mod tests {
use super::*;
use lambda_runtime::{Context, LambdaEvent};
#[tokio::test]
async fn test_generic_handler() {
let event = LambdaEvent::new(IncomingMessage { command: "test".to_string() }, Context::default());
let response = function_handler(event).await.unwrap();
assert_eq!(response.msg, "Command test.");
}
}
このコードは、IncomingMessage構造体を受け取り、OutgoingMessage構造体を返すシンプルなLambda関数の例です。
テストコードも含まれています。
コードのカスタマイズ
せっかくなので少しカスタマイズして、挨拶を返す関数にしてみます。
src/generic_handler.rsのfunction_handlerの内容を以下のように変更します。
pub(crate) async fn function_handler(event: LambdaEvent<IncomingMessage>) -> Result<OutgoingMessage, Error> {
// Extract some useful info from the request
let command = event.payload.command;
// Prepare the outgoing message
let resp = OutgoingMessage {
req_id: event.context.request_id,
msg: format!("Hello!! Rust Lambda!! Command: {}.", command),
};
// Return `OutgoingMessage` (it will be serialized to JSON automatically by the runtime)
Ok(resp)
}
ローカルでテストする
Cargo Lambdaにはローカルでテストするための機能が備わっています。
まず、別のターミナルでLambdaをローカルで起動します。
[~/hello-kane8n-cargo-lambda] $ cargo lambda watch
INFO starting Runtime server runtime_addr=[::]:9000
INFO starting lambda function function="_" manifest=Some("Cargo.toml") cmd=Exec { prog: "/Users/kane8n/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo", args: ["run", "--color", "auto", "--manifest-path", "Cargo.toml"] }
Compiling hello-kane8n-cargo-lambda v0.1.0 (/Users/kane8n/hello-kane8n-cargo-lambda)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.67s
Running `target/debug/hello-kane8n-cargo-lambda`
次に、別のターミナルからリクエストを送信してテストします。
$ cargo lambda invoke --data-ascii '{"command": "test"}'
{"req_id":"ef3f35c2-c811-4388-927b-084fb4ef29e3","msg":"Hello!! Rust Lambda!! Command: test."}
正しくレスポンスが返ってきました!
ビルドとデプロイ
ビルド
Lambda用にビルドするにはcargo lambda buildコマンドを使用します。
--releaseフラグを付けて最適化されたバイナリを生成します。
[~/hello-kane8n-cargo-lambda] $ cargo lambda build --release
▪▪▪▪▪ Target component installed
Compiling proc-macro2 v1.0.103
~ 省略 ~
Compiling hello-kane8n-cargo-lambda v0.1.0 (/Users/kane8n/hello-kane8n-cargo-lambda)
Finished `release` profile [optimized] target(s) in 16.82s
ビルドが完了すると、target/lambda/hello-kane8n-cargo-lambda/にbootstrapファイルが生成されます。
[~/hello-kane8n-cargo-lambda] $ ll target/lambda/hello-kane8n-cargo-lambda
total 3928
-rwxr-xr-x 1 kane8n staff 2009096 12 2 15:13 bootstrap
バイナリサイズは約2MBです。
デプロイ
AWS Profileが設定されていれば、cargo lambda deployコマンドでデプロイできます。
[~/hello-kane8n-cargo-lambda] $ cargo lambda deploy
✅ function deployed successfully 🎉
🛠️ binary last compiled 6 minutes ago
🔍 arn: arn:aws:lambda:ap-northeast-1:111111111111:function:hello-kane8n-cargo-lambda
🎭 version: 1
デプロイが完了したら、AWSコンソールまたはAWS CLIからテストできます。
[~/hello-kane8n-cargo-lambda] $ aws lambda invoke --function-name hello-kane8n-cargo-lambda --payload '{"command": "test"}' --cli-binary-format raw-in-base64-out output.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
[~/hello-kane8n-cargo-lambda] $
[~/hello-kane8n-cargo-lambda] $ cat output.json
{"req_id":"d5bd93a6-a305-4ebc-b702-7fc6fa1c2305","msg":"Hello!! Rust Lambda!! Command: test."}%
実際にAWSコンソール上ではどう見えるかも確認してみます。
explorerを確認する感じだと、zipファイルとしてアップロードされているようです。
ランタイムは Amazon Linux 2023 になっています。
実際に試してみて、Cargo Lambdaを使うと非常にスムーズにRustのLambda関数を開発・デプロイできることが分かりました。
ここからは筆者がRustがGAになったという記事を見て、気になった点について書いていきます。
Container Imageを使う場合との違い
今回紹介した方法は、Cargo Lambdaを使ってzipファイルとしてデプロイする方法です。
一方で、Rustの実行バイナリを含んだContainer Imageを使ってLambdaをデプロイする方法もあります。
両者の比較
| 項目 | zip(Cargo Lambda) | Container Image |
|---|---|---|
| デプロイサイズ | 小さい(数MB程度) | 大きい(数十MB〜数百MB) |
| コールドスタート | 速い | 遅い傾向 |
| カスタマイズ性 | Lambda環境に依存 | OSレベルからカスタマイズ可能 |
| ローカルテスト | Cargo Lambdaで簡単 | Dockerで実行可能 |
| 依存ライブラリ | パッケージ同梱またはLayer経由で追加可能(展開後250MB制限あり) | 自由に追加可能(10GB制限) |
| ビルドパイプライン | シンプル | Dockerfileの管理が必要 |
どちらを選ぶべきか
-
zip(Cargo Lambda)がおすすめの場合
- 依存関係がシンプルなLambda関数
- コールドスタートを最小限にしたい場合
- シンプルなCI/CDパイプラインを維持したい場合
-
Container Imageがおすすめの場合
- 特定のシステムライブラリやツールが必要な場合
- 既存のDockerベースのワークフローがある場合
- Lambda以外の環境でも同じイメージを使いたい場合
Container ImageでのRust実行とSLAについて
LambdaでContainer Imageを使ってRustを実行すること自体は、以前から可能でした。
以前のContainer Image方式の位置づけ
Container Imageを使ったカスタムランタイム実行は、Lambdaサービスの可用性(99.95%)についてはSLAの対象でした。
ただし、Lambdaサービスとしての可用性は保証されていたものの、Rustランタイム自体の動作に関するAWSサポートは受けられませんでした。
つまり、以前は以下のような状況でした。
- Lambdaサービスの可用性:SLA対象
- Rustランタイムの動作:「experimental」としてAWSサポート対象外
- 問題発生時のサポート:Lambdaサービス側の問題のみ対応可能
今回のGAで変わったこと
2025年11月のGA発表により、Rustランタイム自体がAWS Supportの対象となりました。
これにより以下が変わりました。
-
lambda_runtimeクレートを使用したRust Lambda関数の動作がAWSサポートの対象に - 問題発生時にAWSサポートによる対応が受けられる
- Rustランタイム起因の問題もサポートチケットで対応可能
重要な点として、このサポートはlambda_runtimeクレートを使用した実装に対して適用されます。
Container Imageを使う場合でも、lambda_runtimeクレートを使って正しく実装されていれば、同様にサポートの対象となります。
CI/CDについて
ここまでの手順ではローカル環境からデプロイしましたが、実際のプロジェクトではCI/CDパイプラインを構築することが多いでしょう。
ここではGitHub Actionsを使ったCI/CDの例を紹介します。
GitHub Actionsでのデプロイ
GitHub Actionsでは、Cargo Lambdaを使ってビルドとデプロイを自動化できます。
以下は.github/workflows/deploy.ymlの例です。
name: Deploy Lambda
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Zig
uses: mlugg/setup-zig@v1
with:
version: 0.13.0
- name: Install Cargo Lambda
uses: jaxxstorm/action-install-gh-release@v1
with:
repo: cargo-lambda/cargo-lambda
platform: linux
arch: x86_64
- name: Build
run: cargo lambda build --release
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Deploy
run: cargo lambda deploy
このワークフローでは以下のことを行っています。
- Rustのセットアップ
- Zigのインストール(Cargo Lambdaがクロスコンパイルに使用)
- Cargo Lambdaのインストール
- Lambda関数のビルド
- AWS認証情報の設定
- Lambda関数のデプロイ
AWS認証情報はGitHubのSecretsにAWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを設定しておく必要があります。
より安全な方法としては、OIDC(OpenID Connect)を使ってIAMロールを引き受ける方法もあります。
既存のCloudFormation管理環境との統合
多くのプロジェクトでは、既にLambda関数をCloudFormationやSAMで管理しており、Container ImageをビルドしてECRにプッシュする運用が確立されていることがあります。
このような環境でCargo Lambdaを採用する場合、Cargo Lambdaはビルドのみを行い、デプロイはCloudFormationに任せる構成にする必要があります。
つまり、既存のECRベースのビルドパイプラインとは別に、Cargo Lambda用のビルドパイプラインを構築することになります。
以下は、Cargo Lambdaでビルドしたzipファイルをs3にアップロードし、CloudFormationでデプロイするワークフローの例です。
name: Build and Deploy via CloudFormation
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Zig
uses: mlugg/setup-zig@v1
with:
version: 0.13.0
- name: Install Cargo Lambda
uses: jaxxstorm/action-install-gh-release@v1
with:
repo: cargo-lambda/cargo-lambda
platform: linux
arch: x86_64
- name: Build
run: cargo lambda build --release --output-format zip
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Upload to S3
run: |
aws s3 cp target/lambda/hello-kane8n-cargo-lambda/bootstrap.zip \
s3://my-lambda-bucket/hello-kane8n-cargo-lambda/${{ github.sha }}.zip
- name: Deploy CloudFormation
run: |
aws cloudformation deploy \
--template-file template.yaml \
--stack-name my-lambda-stack \
--parameter-overrides LambdaCodeVersion=${{ github.sha }}
CloudFormationテンプレートでは、S3からzipファイルを参照します。
Parameters:
LambdaCodeVersion:
Type: String
Resources:
MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: hello-kane8n-cargo-lambda
Runtime: provided.al2023
Handler: bootstrap
Code:
S3Bucket: my-lambda-bucket
S3Key: !Sub "hello-kane8n-cargo-lambda/${LambdaCodeVersion}.zip"
# ... その他の設定
既存のContainer Image + ECR方式と比較すると、S3バケットの管理が追加で必要になりますが、デプロイサイズが小さくなりコールドスタートの改善が期待できます。
まとめ
AWS LambdaでRustが正式にサポートされたことで、高パフォーマンスで安全なサーバーレス関数をRustで開発できるようになりました。
Cargo Lambdaを使えば、開発からデプロイまでスムーズに行うことができます。
特に以下のような場面でRust Lambdaは威力を発揮するでしょう。
- 高速な処理が求められる場面
- メモリ効率が重要な場面
- 型安全性を重視したい場面
ぜひRustでのLambda開発を試してみてください!

