Lambda@Edge で Node.js 24 を試してみた
2025年11月25日、AWS Lambda が Node.js 24 のサポートを開始しました。通常のLambda関数での動作については、後述の記事で紹介しましたが、
今回は Lambda@Edge での動作を検証しました。
Lambda@Edge は CloudFront のエッジロケーションで実行される Lambda 関数で、通常の Lambda とは異なる制約があります。
Node.js 24 では callback 形式の廃止 という破壊的変更が含まれますが、この変更が Lambda@Edge の基本機能(4つのイベントフックやヘッダー操作)の互換性を損なっていないことを、実機検証を通じて確認しました。
検証環境
- リージョン: us-east-1
- ランタイム: nodejs24.x
- デプロイ方法: CloudFormation
- 検証項目: 4つのイベントタイプすべて(viewer-request, origin-request, origin-response, viewer-response)
Lambda@Edge 関数の実装
4つのトリガー用の Lambda@Edge 関数を用意しました。
1. Viewer Request ハンドラー
Viewer Request は CloudFront がビューワーからリクエストを受け取った直後に実行されます。リクエストヘッダーの追加や URI の書き換えが可能です。
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
// カスタムヘッダーを追加
request.headers['x-custom-header'] = [{
key: 'X-Custom-Header',
value: 'Node24-Edge'
}];
// URI書き換えの例
if (request.uri === '/old-path') {
request.uri = '/new-path';
}
return request;
};
制約:
- タイムアウト: 5秒
- メモリ: 128MB
2. Origin Request ハンドラー
Origin Request は CloudFront がオリジンにリクエストを転送する直前に実行されます。CloudFront が追加したヘッダー(地理情報など)を読み取ることができます。
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
// オリジンへのヘッダーを追加
request.headers['x-origin-header'] = [{
key: 'X-Origin-Header',
value: 'from-edge'
}];
// CloudFrontヘッダーの読み取り
console.log('CloudFront-Viewer-Country:',
request.headers['cloudfront-viewer-country']);
return request;
};
制約:
- タイムアウト: 30秒
- メモリ: 128MB
3. Origin Response ハンドラー
Origin Response は CloudFront がオリジンからレスポンスを受け取った直後に実行されます。セキュリティヘッダーの追加などに使用します。
exports.handler = async (event) => {
const response = event.Records[0].cf.response;
// セキュリティヘッダーを追加
response.headers['strict-transport-security'] = [{
key: 'Strict-Transport-Security',
value: 'max-age=63072000'
}];
response.headers['x-content-type-options'] = [{
key: 'X-Content-Type-Options',
value: 'nosniff'
}];
return response;
};
制約:
- タイムアウト: 30秒
- メモリ: 128MB
4. Viewer Response ハンドラー
Viewer Response は CloudFront がビューワーにレスポンスを返す直前に実行されます。キャッシュ制御ヘッダーの追加などに使用します。
exports.handler = async (event) => {
const response = event.Records[0].cf.response;
// キャッシュ制御ヘッダーを追加
response.headers['cache-control'] = [{
key: 'Cache-Control',
value: 'public, max-age=3600'
}];
// 注意: Viewer Responseではステータスコードの変更は不可
return response;
};
制約:
- タイムアウト: 5秒
- メモリ: 128MB
- ステータスコード変更不可
CloudFormation テンプレート
4つの Lambda@Edge 関数と CloudFront ディストリビューションを一括でデプロイする CloudFormation テンプレートを用意しました。
テンプレート全文
AWSTemplateFormatVersion: '2010-09-09'
Description: Lambda@Edge with Node.js 24 - All Event Types
Resources:
EdgeFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- edgelambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
ViewerRequestFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: node24-edge-viewer-request
Runtime: nodejs24.x
Handler: index.handler
Role: !GetAtt EdgeFunctionRole.Arn
Timeout: 5
MemorySize: 128
Code:
ZipFile: |
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
request.headers['x-custom-header'] = [{ key: 'X-Custom-Header', value: 'Node24-Edge' }];
if (request.uri === '/old-path') {
request.uri = '/new-path';
}
return request;
};
ViewerRequestVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName: !Ref ViewerRequestFunction
OriginRequestFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: node24-edge-origin-request
Runtime: nodejs24.x
Handler: index.handler
Role: !GetAtt EdgeFunctionRole.Arn
Timeout: 30
MemorySize: 128
Code:
ZipFile: |
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
request.headers['x-origin-header'] = [{ key: 'X-Origin-Header', value: 'from-edge' }];
console.log('CloudFront-Viewer-Country:', request.headers['cloudfront-viewer-country']);
return request;
};
OriginRequestVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName: !Ref OriginRequestFunction
OriginResponseFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: node24-edge-origin-response
Runtime: nodejs24.x
Handler: index.handler
Role: !GetAtt EdgeFunctionRole.Arn
Timeout: 30
MemorySize: 128
Code:
ZipFile: |
exports.handler = async (event) => {
const response = event.Records[0].cf.response;
response.headers['strict-transport-security'] = [{
key: 'Strict-Transport-Security',
value: 'max-age=63072000'
}];
response.headers['x-content-type-options'] = [{
key: 'X-Content-Type-Options',
value: 'nosniff'
}];
return response;
};
OriginResponseVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName: !Ref OriginResponseFunction
ViewerResponseFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: node24-edge-viewer-response
Runtime: nodejs24.x
Handler: index.handler
Role: !GetAtt EdgeFunctionRole.Arn
Timeout: 5
MemorySize: 128
Code:
ZipFile: |
exports.handler = async (event) => {
const response = event.Records[0].cf.response;
response.headers['cache-control'] = [{
key: 'Cache-Control',
value: 'public, max-age=3600'
}];
return response;
};
ViewerResponseVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName: !Ref ViewerResponseFunction
OriginBucket:
Type: AWS::S3::Bucket
Properties:
# ※注意: 123456789012 はダミーのAWSアカウントIDです。自身の環境に合わせて変更してください。
BucketName: !Sub 'node24-edge-origin-${AWS::AccountId}'
OriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: node24-edge-oac
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
LambdaFunctionAssociations:
- EventType: viewer-request
LambdaFunctionARN: !Ref ViewerRequestVersion
- EventType: origin-request
LambdaFunctionARN: !Ref OriginRequestVersion
- EventType: origin-response
LambdaFunctionARN: !Ref OriginResponseVersion
- EventType: viewer-response
LambdaFunctionARN: !Ref ViewerResponseVersion
Origins:
- Id: S3Origin
DomainName: !GetAtt OriginBucket.RegionalDomainName
OriginAccessControlId: !Ref OriginAccessControl
OriginShield:
Enabled: true
OriginShieldRegion: us-east-1
S3OriginConfig: {}
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref OriginBucket
PolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub '${OriginBucket.Arn}/*'
Condition:
StringEquals:
AWS:SourceArn: !Sub 'arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}'
Outputs:
DistributionDomainName:
Value: !GetAtt CloudFrontDistribution.DomainName
ViewerRequestVersion:
Value: !Ref ViewerRequestVersion
OriginRequestVersion:
Value: !Ref OriginRequestVersion
OriginResponseVersion:
Value: !Ref OriginResponseVersion
ViewerResponseVersion:
Value: !Ref ViewerResponseVersion
OriginBucket:
Value: !Ref OriginBucket
オリジンシールドの採用理由:
Lambda@Edge は各エッジロケーションで実行されるため、ログが世界中のリージョンに分散します。オリジンシールドを有効化することで、Origin Request/Response イベントのログを us-east-1 に集約できるため、ログの確認や分析が容易になります。
CloudFormation ZipFile での注意点:
CloudFormation の ZipFile プロパティを使用する場合、package.json を含めることができないため、CommonJS 形式(exports.handler)が必須です。ES Modules 形式(export const handler)を使用する場合は、別途 ZIP ファイルを作成して S3 にアップロードし、Code.S3Bucket / Code.S3Key を使用する必要があります。
デプロイ後、作成したCloudFrontのBehavior設定で、Lambda@Edgeが関連付けされていることを確認しました。

デプロイ手順
CLIを利用して、CloudFormation スタックの作成を行いました。
aws cloudformation create-stack \
--stack-name node24-lambda-edge \
--template-body file://cloudformation-edge.yaml \
--capabilities CAPABILITY_IAM \
--region us-east-1
動作確認
1. テストファイルのアップロード
# テスト用HTMLファイルを作成
cat > test.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Lambda@Edge Node.js 24 Test</title>
</head>
<body>
<h1>Lambda@Edge Node.js 24 Test Page</h1>
<p>This page tests all four Lambda@Edge event types.</p>
</body>
</html>
EOF
# S3にアップロード
# ※注意: node24-edge-origin-123456789012 はご自身の環境で作成されたバケット名に置き換えてください
aws s3 cp test.html s3://node24-edge-origin-123456789012/test.html --region us-east-1
2. CloudFront 経由でアクセス
curl -I https://d1234567890abc.cloudfront.net/test.html
3. 実行結果
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 451
Date: Fri, 28 Nov 2025 11:39:40 GMT
Last-Modified: Fri, 28 Nov 2025 11:39:30 GMT
ETag: "b4ec68bdc1ddae9aa15ce5803a10c28f"
Strict-Transport-Security: max-age=63072000
X-Content-Type-Options: nosniff
Cache-Control: public, max-age=3600
Via: 1.1 7bb66c5fc1e732675b1f05b324f80096.cloudfront.net (CloudFront)
X-Cache: Miss from cloudfront
以下、Lambda@Edge 関数の動作 が確認できました。
| イベントタイプ | 追加されたヘッダー | 値 |
|---|---|---|
| Origin Response | Strict-Transport-Security | max-age=63072000 |
| Origin Response | X-Content-Type-Options | nosniff |
| Viewer Response | Cache-Control | public, max-age=3600 |
| Viewer Request | X-Custom-Header | Node24-Edge(※) |
| Origin Request | X-Origin-Header | from-edge(※) |
※ リクエストヘッダーはレスポンスに表示されないため、CloudWatch Logs で確認
まとめ
今回の検証を通じて、Lambda@Edge 環境下でも Node.js 24 ランタイムが正常に動作し、基本機能が利用できることを確認できました。
Node.js 24 は 2028年4月までの長期サポート(LTS)が予定されており、エッジロケーションでの実行パフォーマンスも向上しています。今後の新規開発においては、第一候補とすることをおすすめします。
既存の Lambda@Edge 関数で callback 形式を採用していた場合、移行には async/await への書き換えが必須となります。ただし、Lambda@Edge の関数は一般的にコード量が少ない傾向にあるため、改修コストは比較的少なく済む可能性が高いです。
とはいえ、EoL 直前のアップデートは予期せぬリスクを伴います。余裕を持った Node.js 24 への移行計画をご検討ください。







