「Step FunctionsとLambdaはどちらを使えばよいのか」という問いは、実は比較の前提がずれています。Lambdaはコードを実行するサービスで、Step Functionsはその実行の順序・分岐・失敗時の扱いを管理するサービスです。競合する関係ではなく、担う層が違うサービスです。この記事では両者の役割の差を実行時間・入出力上限・課金単位で比べたうえで、Lambda単体で組むべき場面とStep Functionsでつなぐべき場面の境界、Step FunctionsからLambdaを呼ぶ2つの書き方、Lambdaの例外を分けて扱うRetryとCatchの定義例までを扱います。数値と仕様は2026年10月時点のAWS公式ドキュメントに基づきます。
まとめ:Step FunctionsとLambdaの違いと使い分けの判断基準
Lambdaは1回の呼び出しで最大900秒(15分)までコードを動かす実行基盤です。Step Functionsは標準ワークフローなら最大1年、複数の処理をステートマシンとしてつなぎ、各ステップの再試行と失敗時の分岐を定義で持ちます。処理が1〜2個で、エラー処理も単純なら、Lambdaを直接呼ぶ構成で足ります。
一方、処理が3段以上に分かれる、人の承認待ちがある、失敗の種類ごとに戻り先を変えたい。この3つのどれかに当たるなら、Lambdaの中に制御を書くより、Step Functionsへ外出しするほうが保守は軽くなります。AWS公式も、1つのLambdaが別のLambdaを順に呼び出して結果を検証する構成をアンチパターンとして明記しています。
実装面では、Step FunctionsからLambdaを呼ぶときは arn:aws:states:::lambda:invoke を使い、Lambdaの一時的なサービス例外・スロットリング・業務エラーの3種類をRetryで分けて扱います。再試行は1回ごとに状態遷移として課金されるため、回数は無制限に増やさず上限と待ち時間の上限を置いてください。
Step FunctionsとLambdaの役割の違いを実行時間・上限・課金で比べる
両者の差は、何を担うかに尽きます。Lambdaは「1つの処理を実行する」、Step Functionsは「処理と処理のあいだを管理する」。この切り分けが、クォータと課金の差にそのまま表れています。
Lambdaは処理を実行し、Step Functionsは順序と失敗を管理する
Lambdaの関数はイベントを受け取り、結果を返して終わります。前回の呼び出しで何が起きたかは保持しません。注文処理を例に取ると、在庫確認・決済・請求書発行のそれぞれを関数にすることはできますが、「決済が失敗したら在庫の引き当てを戻す」という処理間の判断は、どこかに書く必要があります。
Step Functionsはこの「どこか」を引き受けます。Amazon States Language(ASL)というJSON形式の定義で、次にどのステートへ進むか、失敗したら何回やり直すか、どのエラーならどこへ逃がすかを宣言する仕組みです。実行ごとの履歴が残り、コンソールのグラフ表示でどのステップで止まったかを追えます。仕組みそのものの解説はAWS Step Functionsとは?ステートマシンの仕組み・料金と2種のワークフロー・採用判断を実装者目線で解説にまとめています。
実行時間・入出力サイズ・課金単位をクォータ表で並べた設計上の差
クォータは設計の上限を決めます。LambdaのクォータとStep Functionsのクォータから、比較に効く項目を抜き出しました。
| 項目 | Lambda | Step Functions |
|---|---|---|
| 最大実行時間 | 900秒(15分) | 標準1年・Express5分 |
| 入出力の上限 | 同期6MB・非同期1MB | 256KiB |
| 課金単位 | リクエスト数とGB秒 | 標準は状態遷移数 |
| 実行履歴 | ログ出力のみ | 標準は90日保持 |
| 再試行の制御 | 非同期は既定2回 | ステートごとに定義 |
見落とされやすいのが入出力の上限です。Lambdaの同期呼び出しは6MBまで返せますが、Step Functionsのステート間で渡せるのは256KiBまで。Lambdaが大きな結果を返す設計のままStep Functionsに組み込むと、States.DataLimitExceeded で実行が止まります。対処は後述します。
Lambda単体で組むかStep Functionsでつなぐかを分ける判断条件
Step Functionsは便利ですが、入れれば必ず良くなるわけではありません。公式ドキュメントは採用すべき場面と、採用しないほうがよい場面の両方を挙げています。
Lambdaから別のLambdaを呼ぶ構成がアンチパターンとされる理由
公式が挙げるアンチパターンは、1つのLambdaが他のLambdaを順に呼び出し、応答を検証し、エラー時のやり直しや指数バックオフも自前で実装する構成です。問題は3つあります。
- 呼び出し側の関数は、呼び出し先が終わるまで待つあいだも実行時間として課金される
- 呼び出し側の900秒の上限に、全ステップの合計時間が収まらなければならない
- どのステップで失敗したかが、ログを突き合わせないと分からない
Step Functionsに移すと、各関数は自分の処理だけを書けば済みます。待機中のLambda課金は発生せず、標準ワークフローなら全体で最大1年まで伸ばせます。
SQSやEventBridgeから直接呼べばStep Functionsが不要な場面
逆に、公式は単純なアプリケーションではStep Functionsが不要な複雑さを足すと書いています。SQSのメッセージを処理するだけ、EventBridgeのイベントに反応するだけ、関数が1〜2個でエラー処理も単純。この条件なら、キューやイベントバスから関数を直接起動する構成のほうが、デプロイも運用も軽く済みます。
キュー経由の構成は、可視性タイムアウトとデッドレターキューで失敗を扱えます。設計はAmazon SQSとは?標準キューとFIFOの違い・可視性タイムアウトとDLQ設計を解説、イベント駆動の配線はAmazon EventBridgeとはで扱っています。
Lambda durable functionsという第3の選択肢と選び分けの軸
2026年10月時点では、Lambdaの中でワークフローをコードとして書くdurable functionsも選べます。公式の比較ページは、判断の軸を次のように整理しています。
- 処理の中心がLambdaで、業務ロジックとワークフローを同じコードに置きたい:durable functions(JavaScript/TypeScript・Python)
- Lambda以外のAWSサービスを多数つなぐ、非エンジニアにも流れを図で見せたい:Step Functions(220を超えるサービスと統合)
両方を併用する構成も公式に示されています。アプリケーション内の状態管理はdurable functionsに、サービス横断の上位フローはStep Functionsに任せる分担です。durable functionsの実装はLambda Durable Functionsとは?東京リージョン対応と15分制限を超える長時間ワークフロー実装で解説しています。
Step FunctionsのLambda呼び出し2方式とlambda:invokeの実装
Step FunctionsのTaskステートからLambdaを呼ぶ方法は2つあります。どちらでも関数は動きますが、使える機能と出力の形が違います。
lambda:invoke統合と関数ARN直接指定で変わる出力と使える機能
Lambda連携の公式ドキュメントによると、違いは次のとおりです。
arn:aws:states:::lambda:invokeを指定する方式:結果はPayload・StatusCodeなどのメタデータに包まれて返る。.waitForTaskTokenによるコールバック待ちや、InvocationTypeによる非同期呼び出しが使える- Resourceに関数ARNを直接書く方式:結果は関数の戻り値だけになる。
.waitForTaskTokenは指定できない
新規に書くなら前者を選んでください。人の承認待ちを後から足したくなったとき、直接指定の方式では書き換えが必要になります。出力の入れ子は、次の定義例のように Output で Payload だけを取り出せば扱いやすくなります。
以下は、決済用のLambdaを呼び、Lambdaのサービス例外・スロットリング・業務エラーを分けて扱うJSONata形式の定義例です。関数名・アカウントIDは自分の環境に置き換えてください。
{
"Comment": "決済Lambdaを呼び、例外の種類ごとに再試行と分岐を変える",
"QueryLanguage": "JSONata",
"StartAt": "ChargePayment",
"States": {
"ChargePayment": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Arguments": {
"FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:charge-payment:prod",
"Payload": "{% $states.input %}"
},
"Output": "{% $merge([$states.input, $states.result.Payload]) %}",
"TimeoutSeconds": 60,
"Retry": [
{
"ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException", "Lambda.SdkClientException", "Lambda.ClientExecutionTimeoutException"],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
},
{
"ErrorEquals": ["Lambda.TooManyRequestsException"],
"IntervalSeconds": 5,
"MaxAttempts": 5,
"BackoffRate": 2,
"MaxDelaySeconds": 60,
"JitterStrategy": "FULL"
},
{
"ErrorEquals": ["PaymentDeclined"],
"MaxAttempts": 0
}
],
"Catch": [
{
"ErrorEquals": ["PaymentDeclined"],
"Output": "{% $merge([$states.input, {'error': $states.errorOutput}]) %}",
"Next": "NotifyDeclined"
},
{
"ErrorEquals": ["States.ALL"],
"Next": "PaymentFailed"
}
],
"Next": "Done"
},
"NotifyDeclined": { "Type": "Pass", "End": true },
"PaymentFailed": { "Type": "Fail", "Error": "PaymentFailed", "Cause": "決済処理が再試行後も失敗" },
"Done": { "Type": "Succeed" }
}
}
関数名の末尾に :prod のようなエイリアスを付けた場合、実行ロールのIAMポリシー側もエイリアス付きのARN(または末尾 :*)で許可しなければなりません。公式ドキュメントには、エイリアスなしのARNだけを許可しているとAccess Deniedで失敗すると注記があります。本番で最初に踏みやすい罠です。
関数側で決済拒否などの業務エラーを例外名として返すPythonの書き方
Step Functionsは、Lambdaが投げた例外のクラス名をエラー名として受け取ります。業務上の失敗(カードの拒否など)を独自の例外クラスで投げれば、定義側の ErrorEquals でその名前を指定して分岐できます。
class PaymentDeclined(Exception):
"""カード会社が拒否した場合の業務エラー。再試行しても結果は変わらない"""
def lambda_handler(event, context):
order_id = event["orderId"]
amount = event["amount"]
result = charge(order_id, amount) # 決済APIの呼び出し(実装は省略)
if result["status"] == "declined":
# 例外クラス名がそのままStep Functions側のエラー名になる
raise PaymentDeclined(f"order {order_id} was declined")
return {"chargeId": result["id"], "status": "charged"}
この分け方が要です。カード拒否は何度やり直しても通らないため、定義例では MaxAttempts を0にして即座に通知へ回しています。再試行に意味があるのは、Lambda側の一時障害とスロットリングだけです。
AWS CLIでステートマシンを作成して実行結果を確かめる手順
定義を sfn.json に保存したら、CLIで作成と実行まで確認できます。ロールのARNは事前に作成したStep Functions用の実行ロールに置き換えてください。
# ステートマシンを作成する(標準ワークフロー)
aws stepfunctions create-state-machine \
--name order-payment \
--definition file://sfn.json \
--role-arn arn:aws:iam::123456789012:role/sfn-order-payment-role \
--type STANDARD \
--region ap-northeast-1
# 実行を開始する
aws stepfunctions start-execution \
--state-machine-arn arn:aws:states:ap-northeast-1:123456789012:stateMachine:order-payment \
--input '{"orderId":"A-1001","amount":4800}' \
--region ap-northeast-1
# 実行状態と出力を確認する(executionArnは前のコマンドの出力から取る)
aws stepfunctions describe-execution \
--execution-arn arn:aws:states:ap-northeast-1:123456789012:execution:order-payment:実行ID \
--query '{status:status,output:output}' \
--region ap-northeast-1
失敗した場合は get-execution-history で、どのステートで何回再試行したかがイベント単位で確認できます。Lambdaのログを突き合わせなくても、失敗の位置が履歴から分かる点がStep Functionsへ外出しする利点です。
Lambda呼び出しのリトライ設計で二重実行と課金の増加を防ぐ
Retryは書けば安心という設定ではありません。どの層で何回やり直すかを決めないと、同じ処理が何重にも走り、請求も膨らみます。
Lambdaの一時的なサービス例外とスロットリングを分けて再試行する理由
Step Functionsのベストプラクティスは、Lambdaがまれに返す500系の一時エラー(ServiceException・AWSLambdaException・SdkClientException など)を Lambda. 接頭辞付きのエラー名でRetryするよう勧めています。示されている値は間隔2秒・最大6回・倍率2です。
スロットリング(Lambda.TooManyRequestsException)は性質が違います。同時実行数の上限に当たっている状態なので、短い間隔で一斉にやり直すと再び詰まります。定義例で待ち時間の上限 MaxDelaySeconds とジッター JitterStrategy: FULL を付けたのはこのためです。エラー処理の公式ドキュメントによると、ジッターを付けると各回の待ち時間が0秒から計算値までの乱数になり、並列実行が同じ瞬間に再試行するのを避けられます。
なお、Lambdaの実行時間切れは新しいランタイムでは Sandbox.Timedout、古い形式では Lambda.Unknown として報告されます。Catchの最後に States.ALL を置けば拾えますが、States.ALL は配列の中で単独・かつ最後に置く決まりがあります。
関数内とStep Functions側でリトライを二重にしない責務分担
よくある失敗が、関数の中で外部APIを最大3回試し、Step Functions側でも最初の呼び出しに加えて6回やり直す構成です。最悪の場合は3回×7回で21回、決済APIが叩かれます。方針は単純にしてください。
- 関数の中では再試行しない。失敗したら例外を投げて終わる
- 再試行の回数と間隔はStep Functionsの定義に一本化する
- 決済のように二重実行が許されない処理は、注文IDを冪等キーとして外部APIへ渡す
Step FunctionsからLambdaを同期で呼ぶ場合、Lambda自身の非同期リトライ(既定で最大2回)は働きません。ただし InvocationType: Event で非同期に呼ぶと、Lambda側の2回とStep Functions側のRetryが重なります。非同期呼び出しを選ぶなら、関数の非同期設定で再試行回数を0にしておくと二重計上を防げます。
再試行1回ごとに状態遷移として課金される点を踏まえた回数設計
Step Functionsの料金ページは、標準ワークフローの課金を状態遷移の総数とし、Retryによる再試行もそれぞれ追加の状態遷移として課金すると明記しています。米国東部(バージニア北部)の単価は1遷移0.000025USD、無料枠は毎月4,000遷移です。
5ステップのワークフローを月100万回動かすと500万遷移で、無料枠を引いて約124.90USD。障害時に全実行が6回ずつ再試行すれば、その分が上乗せされます。単価そのものは小さい一方、リトライ回数を「念のため多め」に置くと障害の日だけ請求が跳ねる構造です。東京リージョンの単価は料金ページのリージョン選択で確認してください。Lambda側の実額はAWS Lambdaの料金を東京リージョンの実額で計算するで整理しています。
256KiBの入出力上限とタイムアウト未設定で止まる実行の回避
LambdaをStep Functionsに組み込んだとき、Lambda単体では起きなかった止まり方が2つあります。
大きな処理結果はS3に置きステート間でキーだけを渡す受け渡しの設計
前述のとおり、ステート間で渡せるデータは256KiBまでです。ベストプラクティスのページは、これを超えそうなデータはS3に保存し、バケット名とキーだけをステート間で渡すよう勧めています。Lambdaは受け取ったキーでS3から読み、処理結果も再びS3に書いてキーを返す。この形にしておけば、データ量が増えても定義を変えずに済みます。S3上の大量ファイルを1件ずつLambdaへ渡して並列処理する場合は、Step FunctionsのMapステート:インラインと分散マップの違いとS3大量ファイルの並列処理手順で分散マップの組み方をまとめています。
TaskにTimeoutSecondsを付けず応答待ちで止まる実行の回避
ASLは既定でTaskのタイムアウトを持ちません。Lambda呼び出し自体は関数のタイムアウトで必ず終わりますが、.waitForTaskToken でコールバックを待つ構成では、トークンが返らない限り実行は最大1年待ち続けます。コールバック待ちには TimeoutSeconds と、それより短い HeartbeatSeconds を付けてください。止まった理由が「処理が遅い」のか「処理が死んだ」のかを区別できるようになります。
Step Functionsを採用する条件とLambda単体で済ませる見送り場面
ここまでの比較を、採用と見送りの条件として言い切ります。
Step Functionsを採用する条件は、次のいずれかに当たる場合です。処理が3段以上に分かれ、途中の失敗で戻り先が変わる。人の承認や外部システムのコールバックを待つ。合計時間が15分を超える。失敗した位置を運用担当者が画面で追う必要がある。この場合、制御をLambdaの中に書くと、関数がワークフローエンジンの再実装になります。
Lambda単体で済ませる場面は、関数が1〜2個で、再試行もSQSのデッドレターキューで足りる構成です。ここにStep Functionsを足すと、定義ファイルとIAMロールが増えるだけで得るものがありません。また、処理の大半がLambda内のロジックで、図で見せる相手もいないなら、durable functionsでコードのまま書くほうが開発は速く進みます。
迷ったときは「エラーの種類ごとに戻り先を変えたいか」を問いにしてください。変えたいならStep Functions、全部同じ扱いでよいならLambda単体です。既存のLambda群をStep Functionsへ移すかどうかの棚卸しや、リトライ設計の見直しから相談したい場合は、インフラ構築(AWS・Google Cloud・Azure)で対応しています。
よくある質問
Step FunctionsとLambdaはどちらか一方を選ぶものですか?
いいえ。Lambdaは処理を実行し、Step Functionsは複数の処理の順序と失敗時の扱いを管理するため、併用が基本形です。AWS公式も、タスクごとに個別のLambda関数を作り、Step Functionsでワークフローを管理する構成を推奨例として示しています。比較すべきは「Step Functionsを足すか、Lambdaの中に制御を書くか」です。
Step Functionsを使うとLambdaの15分制限を超えられますか?
ワークフロー全体としては超えられます。標準ワークフローの最大実行時間は1年で、15分以内に収まるよう処理を複数の関数に分ければ、合計時間はLambdaの上限に縛られません。ただし1つの関数の1回の実行は900秒が上限のままです。1つの処理自体が長い場合は、Lambda Managed InstancesやECSのタスクへ切り出す判断になります。
lambda:invokeと関数ARNの直接指定はどちらを使うべきですか?
arn:aws:states:::lambda:invoke を使う方式が推奨です。コールバック待ち(.waitForTaskToken)や非同期呼び出しが使え、後から要件が増えても定義を書き換えずに済みます。出力がメタデータに包まれる点は、Output で Payload だけを取り出せば解消します。
Lambdaの例外はStep Functionsでどのようなエラー名になりますか?
エラー名として使われるのは、関数が投げた例外のクラス名そのものです。Pythonで PaymentDeclined を投げれば、定義側の ErrorEquals に同じ名前を書いて分岐できます。Lambdaサービス自体の一時エラーは Lambda.ServiceException のように Lambda. 接頭辞付き、同時実行の上限超過は Lambda.TooManyRequestsException として報告されます。
Step Functionsの料金はLambdaに上乗せでかかりますか?
追加の料金がかかる仕組みです。Lambdaのリクエスト課金とGB秒課金はそのまま発生し、標準ワークフローでは状態遷移数に応じた料金も課金対象です。米国東部では1遷移0.000025USD・月4,000遷移の無料枠で、再試行も1回ごとに遷移として数えられます。短時間・大量の処理なら、リクエスト数と実行時間で課金されるExpressワークフローのほうが安くなる場合があります。
関連記事
- AWS Step Functionsとは?ステートマシンの仕組み・料金と2種のワークフロー・採用判断を実装者目線で解説:標準とExpressの違い・料金の全体像
- AWS Lambdaとは?仕組み・料金体系とコールドスタート対策・採用判断を実装者目線で解説:関数単体の仕組みと制約
- Lambda Durable Functionsとは?東京リージョン対応と15分制限を超える長時間ワークフロー実装:コードで書くワークフローの選択肢
- Lambda Managed Instancesとは?料金の実額・90分実行・標準Lambdaとの使い分け【2026年9月】:1つの処理が長い場合の受け皿
- Amazon SQSとは?標準キューとFIFOの違い・可視性タイムアウトとDLQ設計を解説:Step Functionsを使わない失敗処理
- サーバーレスとは?仕組み・メリットとコンテナとの使い分けを解説:検討段階での全体整理