https://aws.amazon.com/jp/blogs/compute/building-serverless-applications-with-rust-on-aws-lambda/
いままで AWS Lambda のRustはExperimentalとして提供されていましたが、2025年11月14日に一般提供開始となりました。
Custom Runtime と Cargo Lambda
LambdaのRustサポートはCargo Lambdaというオープンソースフレームワークにより実装されています。
2018年にLambdaがCustom Runtimeをサポートしました。これにより公式サポート外の言語(Rustを含む)でLambda関数が書けるようになりました。そのあとCustom Runtimeを使用したRust RuntimeがAWSにより開発されリリースされました。
https://github.com/aws/aws-lambda-rust-runtime
しかしながら標準でLambdaがRuntimeをサポートしていたなかったこともあり、ビルド・デプロイはかなり複雑でした。この問題を解決するためにコミュニティベースで開発されているものがCargo Lambdaです。今回のRust正式サポートでもこのCargo Lambdaを前提としています。
さっそくやってみる
環境はWSLで行っています。
Rust と Cargo Lambda 環境の整備
以下のコマンドで必要なライブラリをインストールした後WSLを再起動します。(一度閉じて開きなおせばOKです)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
cargo install cargo-lambda
sudo snap install zig --classic --betaプロジェクトの作成
cargo lambda new new-lambda-project
cd new-lambda-projectLambda 関数のデプロイ
cargo lambda build --release
cargo lambda deployデフォルトでは`us-west-2`にデプロイされます。

Runtimeがカスタムでデプロイされていることがわかります。
テスト
以下のイベントを使ってコンソールからテストを行います。
{
"command": "test command"
}
パフォーマンステスト
1から1000の間の素数を求める計算を行ってみます。
src/generic_handler.rs を以下に置き換えます。
use lambda_runtime::{Error, LambdaEvent};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
pub(crate) struct IncomingMessage {
max_number: Option<u32>, // オプション: 指定がなければ1000
}
#[derive(Serialize)]
pub(crate) struct OutgoingMessage {
req_id: String,
primes: Vec<u32>,
count: usize,
msg: String,
}
// 素数判定関数
fn is_prime(n: u32) -> bool {
if n < 2 {
return false;
}
if n == 2 {
return true;
}
if n % 2 == 0 {
return false;
}
let sqrt_n = (n as f64).sqrt() as u32;
for i in (3..=sqrt_n).step_by(2) {
if n % i == 0 {
return false;
}
}
true
}
// 素数を探す関数
fn find_primes(max: u32) -> Vec<u32> {
(1..=max).filter(|&n| is_prime(n)).collect()
}
pub(crate) async fn function_handler(event: LambdaEvent<IncomingMessage>) -> Result<OutgoingMessage, Error> {
// デフォルトは1000、指定があればその値を使用
let max_number = event.payload.max_number.unwrap_or(1000);
// 素数を検索
let primes = find_primes(max_number);
let count = primes.len();
let resp = OutgoingMessage {
req_id: event.context.request_id,
primes,
count,
msg: format!("Found {} primes between 1 and {}", count, max_number),
};
Ok(resp)
}
#[cfg(test)]
mod tests {
use super::*;
use lambda_runtime::{Context, LambdaEvent};
#[test]
fn test_is_prime() {
assert_eq!(is_prime(2), true);
assert_eq!(is_prime(3), true);
assert_eq!(is_prime(4), false);
assert_eq!(is_prime(17), true);
assert_eq!(is_prime(100), false);
}
#[tokio::test]
async fn test_generic_handler() {
let event = LambdaEvent::new(
IncomingMessage { max_number: Some(20) },
Context::default()
);
let response = function_handler(event).await.unwrap();
// 1-20の素数は: 2, 3, 5, 7, 11, 13, 17, 19
assert_eq!(response.count, 8);
assert_eq!(response.primes, vec![2, 3, 5, 7, 11, 13, 17, 19]);
}
}再度以下のコマンドでデプロイします。
cargo lambda build --release
cargo lambda deploy関数を4回実行して2-4回目の平均実行時間は1.45msでした。同様の事を以下のNode関数で行うと9.34msでした。は、はやい。
// 1から1000までの素数を探す
function isPrime(n) {
if (n < 2) return false;
if (n === 2) return true;
if (n % 2 === 0) return false;
const sqrt = Math.sqrt(n);
for (let i = 3; i <= sqrt; i += 2) {
if (n % i === 0) return false;
}
return true;
}
function findPrimes(max) {
const primes = [];
for (let i = 1; i <= max; i++) {
if (isPrime(i)) {
primes.push(i);
}
}
return primes;
}
export const handler = async (event) => {
const maxNumber = event.max_number || 1000;
const primes = findPrimes(maxNumber);
const response = {
statusCode: 200,
body: JSON.stringify({
primes: primes,
count: primes.length,
message: `Found ${primes.length} primes between 1 and ${maxNumber}`
})
};
return response;
};
