AWS EmulatorとLocalStackの速さとエラーの違い
AWS Emulator と LocalStack で同じ AWS CLI のコマンドを実行すると、S3 の応答とエラーはほとんど同じでしたが、起動の速さ、DynamoDB のテーブルを作った直後の状態、認証情報の扱いがはっきり違いました。ローカル環境や CI で、AWS の API を呼ぶテスト(結合テスト)をアカウントなしで動かしたいときに、どちらを選ぶかの材料になるように、測った数値と出力をそのまま載せます。
検証環境は Ubuntu 24.04(x86_64、4 CPU、メモリー 16GB)、AWS Emulator 1.0.353(Debian パッケージ)、LocalStack 4.14.0(Docker 29.9.2 で動かしたコミュニティ版のイメージ)、AWS CLI 2.40.3、Python 3.11 と Boto3 1.44.3 です。AWS と LocalStack のアカウントは使っていません。そのため、auth token が要る最新の LocalStack の中での動き、本物の AWS での動き(エラーの文面を含む)と AWS の料金、LocalStack のプランの中身と料金は確かめておらず、記事で触れるところは公式の情報を出どころにしています。比べたのは S3 と DynamoDB の一部の操作だけで、AWS Emulator を Docker で動かす方法も試していません。
比べた2つと、LocalStack のバージョン
AWS Emulator は、AWS 製のエミュレーターです。公式ドキュメントによると、AWS のアカウントは要らず、追加の料金もかかりません。Linux ではパッケージを入れて、1つのコマンドとして動かします。検証環境では、Linux 向けの手順どおりに Debian パッケージの署名を確かめてから入れました。
LocalStack は Docker のコンテナで動かします。ここで1つ注意があります。Docker Hub の LocalStack のページによると、いまの localstack/localstack のイメージは、起動に auth token が要ります。検証環境で最新のイメージ(latest、LocalStack 2026.10.7)を auth token なしで起動すると、次のように終了コード 55 で止まりました。
$ docker run --rm --name ls-latest -p 4567:4566 localstack/localstack:latest
LocalStack version: 2026.10.7
LocalStack build date: 2026-11-11
(中略)
Localstack returning with exit code 55. Reason:
===============================================
License activation failed! 🔑❌
Reason: No credentials were found in the environment. Please set the LOCALSTACK_AUTH_TOKEN variable to a valid auth token. Alternatively, run `lstk login` and start LocalStack with the lstk CLI, which configures the credentials for you.
auth token はアカウントを作って発行するものなので、この記事では、auth token なしで起動できたコミュニティ版のイメージ localstack/localstack:4.14.0(2026年2月のビルド)と比べました。起動すると、統一されたイメージに移るという案内が出ます。
You are starting the LocalStack Community Docker image.
We move towards a unified LocalStack for AWS image in March 2026.
LocalStack の GitHub のリポジトリは読み取り専用になっていて、README には、商用でない使い方なら無料の Hobby プランがあると書かれています。
2つの起動と、AWS CLI を向ける環境変数は次のとおりです。AWS Emulator は起動のたびにアクセスキーと証明書のファイルを作るので、環境変数でそのファイルの場所を指定します。AWS Emulator はその端末で動き続けるので、環境変数は別の端末で設定します。LocalStack は HTTP で受け付け、アクセスキーには test のような適当な値を入れます。
# AWS Emulator(-t off はテレメトリーを切る指定)。この端末で動き続ける
aws-emulator -t off
# 別の端末で
export AWS_ENDPOINT_URL=https://127.0.0.1:9297
export AWS_SHARED_CREDENTIALS_FILE=~/.aws/emulator/9297/emulator_credentials
export AWS_CONFIG_FILE=~/.aws/emulator/9297/config
export AWS_CA_BUNDLE=~/.aws/emulator/9297/ca.pem
export AWS_DISABLE_HOST_PREFIX_INJECTION=true
export AWS_EC2_METADATA_DISABLED=true
export AWS_DEFAULT_REGION=us-east-1
# LocalStack 4.14.0
docker run -d --name ls -p 4566:4566 localstack/localstack:4.14.0
export AWS_ENDPOINT_URL=http://localhost:4566
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_EC2_METADATA_DISABLED=true
export AWS_DEFAULT_REGION=us-east-1
違いの一覧
測った結果をまとめると、次のようになりました。数字の測り方は、このあとの節で説明します。
| 比べたこと | AWS Emulator | LocalStack 4.14.0 |
|---|---|---|
| 起動からヘルスチェックが通るまで | 0.21秒 | 1.44〜1.61秒 |
| 起動直後の最初の DynamoDB の呼び出し | 5〜6ミリ秒 | 約2秒 |
| S3 の応答と、S3 のエラー | 同じ | 同じ |
| CreateTable の直後のテーブルの状態 | CREATING(約3秒で ACTIVE) |
すぐ ACTIVE |
| DynamoDB のエラーコード | 同じ | 同じ |
| DynamoDB のエラーメッセージ | 違う文面 | 違う文面 |
| エミュレーターの鍵ではないアクセスキー | AccessDenied で断る |
通る |
| 1回あたりの応答時間(中央値) | 1.7〜2.5ミリ秒 | 3.4〜8.5ミリ秒 |
起動の速さ
起動のコマンドを実行してから、ヘルスチェックの URL が応答するまでの時間を、Python のスクリプトで測りました。AWS Emulator は https://127.0.0.1:9297/__admin/health、LocalStack は http://localhost:4566/_localstack/health を50ミリ秒おきに呼んでいます。LocalStack のイメージは取得したあとで、コンテナを作るところから測りました。続けて、Boto3 で S3 の ListBuckets と DynamoDB の ListTables を1回ずつ呼び、それぞれが返るまでの時間も測っています。3回ずつ測った結果です。
emu: health_ok=0.21s first_s3_ListBuckets=9ms first_dynamodb_ListTables=6ms second_ListTables=3ms
ls: health_ok=1.61s first_s3_ListBuckets=465ms first_dynamodb_ListTables=2043ms second_ListTables=9ms
emu: health_ok=0.21s first_s3_ListBuckets=7ms first_dynamodb_ListTables=5ms second_ListTables=2ms
ls: health_ok=1.60s first_s3_ListBuckets=485ms first_dynamodb_ListTables=2030ms second_ListTables=8ms
emu: health_ok=0.21s first_s3_ListBuckets=8ms first_dynamodb_ListTables=5ms second_ListTables=2ms
ls: health_ok=1.44s first_s3_ListBuckets=475ms first_dynamodb_ListTables=2005ms second_ListTables=9ms
emu が AWS Emulator、ls が LocalStack です。LocalStack はヘルスチェックが通ったあとも、S3 の最初の呼び出しに約0.5秒、DynamoDB の最初の呼び出しに約2秒かかりました。DynamoDB は2回目の ListTables が10ミリ秒以内だったので、時間がかかったのは最初の1回だけでした。AWS Emulator は、どちらの最初の呼び出しも10ミリ秒以内でした。テストのたびに起動し直す使い方では、この差が毎回かかります。

S3 は、応答もエラーも同じだった
S3 では、バケットを作り、ファイルを置いて、一覧を出し、読み出す操作を両方で実行しました。出力は、日時の行のほかは同じでした。AWS Emulator の出力です。
$ aws s3api create-bucket --bucket example-bucket
{
"Location": "/example-bucket",
"BucketArn": "arn:aws:s3:::example-bucket"
}
$ aws s3api put-object --bucket example-bucket --key hello.txt --body hello.txt
{
"ETag": "\"b1946ac92492d2347c6235b4d2611184\"",
"ChecksumCRC64NVME": "akP7S61aVgc=",
"ChecksumType": "FULL_OBJECT",
"ServerSideEncryption": "AES256"
}
$ aws s3api list-objects-v2 --bucket example-bucket --query 'Contents[].[Key,Size,StorageClass]' --output text
hello.txt 6 STANDARD
get-object の応答も、ContentLength、ETag、ContentType などの項目と値がそろっていて、違うのは LastModified の時刻だけでした。
失敗する操作も、エラーコードと HTTP ステータス、メッセージまで同じでした。Boto3 でエラーの中身を取り出した結果です(左から、エラーコード、HTTP ステータス、メッセージ)。
| 操作 | AWS Emulator と LocalStack(同じ) |
|---|---|
| ないキーを読む | NoSuchKey、404、The specified key does not exist. |
| ないバケットから読む | NoSuchBucket、404、The specified bucket does not exist |
大文字や _ を含む名前でバケットを作る |
InvalidBucketName、400、The specified bucket is not valid. |
| 中身があるバケットを消す | BucketNotEmpty、409、The bucket you tried to delete is not empty |
DynamoDB は、テーブルを作った直後の状態が違う
いちばん大きな違いは、DynamoDB でテーブルを作った直後でした。同じ create-table を実行すると、AWS Emulator は CREATING、LocalStack は ACTIVE を返しました。
$ aws dynamodb create-table --table-name Cats --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST --query TableDescription.TableStatus
"CREATING"
$ aws dynamodb create-table --table-name Cats --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST --query TableDescription.TableStatus
"ACTIVE"
上が AWS Emulator、下が LocalStack です。DynamoDB の CreateTable の API リファレンスでは、CreateTable は非同期の操作で、すぐに CREATING を返し、作り終えると ACTIVE になり、読み書きできるのは ACTIVE のテーブルだけ、と説明されています。AWS Emulator の返し方は、この説明と合っています。
CREATING のあいだに書き込むとどうなるかを、Boto3 で確かめました。テーブルを作った直後に PutItem を呼び、次に DescribeTable、もう一度 PutItem を呼んで、それぞれの結果とかかった時間を出しています(3回とも同じ傾向でした)。
emu CreateTable 27ms CREATING
emu PutItem(直後) 4ms ResourceNotFoundException HTTP 400 Requested resource not found
emu DescribeTable 2981ms ACTIVE
emu PutItem(DescribeTable のあと) 3ms 成功
ls CreateTable 257ms ACTIVE
ls PutItem(直後) 103ms 成功
ls DescribeTable 16ms ACTIVE
ls PutItem(DescribeTable のあと) 14ms 成功
AWS Emulator では、作った直後の書き込みが ResourceNotFoundException で失敗しました。PutItem の API リファレンスにも、このエラーはテーブルがないときだけでなく、ACTIVE でないときにも返ると書かれています。また、AWS Emulator の DescribeTable は約3秒待ってから ACTIVE を返しました。DescribeTable を呼ばずに待ったときは、1秒後の書き込みは失敗し、4秒後の書き込みは成功しました。
LocalStack では、作った直後の書き込みも通ります。そのため、テーブルを作ってすぐ書き込むテストは、LocalStack では通り、AWS Emulator では落ちます。両方で動くようにするには、作ったあとに ACTIVE になるまで待つ処理を入れます。AWS CLI なら aws dynamodb wait table-exists、Boto3 なら get_waiter("table_exists") です。検証環境で、起動し直した AWS Emulator と LocalStack のそれぞれで次の3つのコマンドを続けて実行すると、どちらも3つとも終了コード 0 で終わりました。
aws dynamodb create-table --table-name Cats --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST --query TableDescription.TableStatus
aws dynamodb wait table-exists --table-name Cats
aws dynamodb put-item --table-name Cats --item '{"id":{"S":"tama"},"age":{"N":"3"}}'
書き込んだあとの get-item と scan の結果は、両方で同じでした(get-item の出力の、属性の並び順だけが違いました)。ないキーを get-item で読むと、どちらも何も出さずに終了コード 0 で終わりました。
DynamoDB のエラーは、コードが同じでメッセージが違う
DynamoDB の失敗する操作では、エラーコードと HTTP ステータスは両方で同じでしたが、メッセージの文面が違うものがありました。
| 操作 | AWS Emulator | LocalStack 4.14.0 |
|---|---|---|
ないテーブルを DescribeTable |
Requested resource not found: Table: NoSuchTable not found | Cannot do operations on a non-existent table |
キーの属性がない項目を PutItem |
One or more parameter values were invalid: Missing the key id in the item | One of the required keys was not given a value |
キーの型が違う項目を PutItem |
One or more parameter values were invalid: Type mismatch for key id expected: S actual: N | One or more parameter values were invalid: Type mismatch for key |
| 同じ名前でテーブルを作る | Table already exists: Cats | Table already exists: Cats |
エラーコードは、上から ResourceNotFoundException、ValidationException、ValidationException、ResourceInUseException で、どれも HTTP 400 でした。テストでエラーを確かめるときは、メッセージの文面ではなくエラーコードで比べると、どちらのエミュレーターでも同じ結果になります。AWS Emulator の忠実度(Fidelity)のページでは、正しくない呼び出しには AWS と同じエラーを返すことを目指していると説明されています。
この節と認証情報の節で試した失敗では、AWS CLI の終了コードは両方とも 254 でした。AWS CLI の終了コードの説明では、254 はリクエストは送れたがサービスがエラーを返したことを表します。
認証情報の扱い
AWS Emulator に、起動のたびに作られるアクセスキーとは別のアクセスキーで呼ぶと、AccessDenied で断られました。LocalStack は、適当なアクセスキーでもそのまま通りました。
$ AWS_ACCESS_KEY_ID=DUMMYACCESSKEY AWS_SECRET_ACCESS_KEY=dummysecret aws s3api list-buckets --query 'Buckets[].Name'
aws: [ERROR]: An error occurred (AccessDenied) when calling the ListBuckets operation: Sign the request with the emulator credentials
$ AWS_ACCESS_KEY_ID=DUMMYACCESSKEY AWS_SECRET_ACCESS_KEY=dummysecret aws s3api list-buckets --query 'Buckets[].Name'
[
"example-bucket"
]
上が AWS Emulator、下が LocalStack です。aws sts get-caller-identity で見た呼び出し元も違い、AWS Emulator は arn:aws:iam::<12桁の0>:user/emulator、LocalStack は arn:aws:iam::<12桁の0>:root を返しました(0の並びは <12桁の0> と書いています)。
AWS Emulator の接続先の設定のページでは、アクセスキーの環境変数は認証情報ファイルより優先されるので、unset で消しておくよう案内されています。なお、AWS Emulator は署名は確かめますが、IAM のポリシーは AWS と同じようには評価しないと、AWS Emulator の公式ドキュメントに書かれています。
応答時間とメモリー
起動したあとの速さも比べました。Boto3 で同じ操作を210回ずつ呼び、最初の10回を除いた200回の、1回あたりの時間です。S3 は 1KB のオブジェクトの読み書き、DynamoDB は小さな項目の読み書きです。
| 操作 | AWS Emulator(中央値/95パーセンタイル) | LocalStack 4.14.0(中央値/95パーセンタイル) |
|---|---|---|
| S3 PutObject | 2.45ms/2.95ms | 3.82ms/4.97ms |
| S3 GetObject | 2.09ms/2.63ms | 3.36ms/4.05ms |
| DynamoDB PutItem | 1.81ms/2.06ms | 8.51ms/11.40ms |
| DynamoDB GetItem | 1.71ms/2.07ms | 5.60ms/7.14ms |
どの操作も AWS Emulator のほうが短く、差は DynamoDB で大きくなりました。ただ、どちらも数ミリ秒で、起動の差(最大で約2秒)やテーブルを作るときの待ち(約3秒)に比べると小さな差です。
ここまでの操作を終えたあとのメモリー使用量は、AWS Emulator のプロセスが 337MiB、LocalStack のコンテナが 388MiB でした(AWS Emulator は ps で見たプロセスの RSS、LocalStack は docker stats の値です)。ディスクは、AWS Emulator の入ったフォルダー(/opt/aws-emulator)が du -sh で 983M、LocalStack 4.14.0 のイメージが約1.77GB でした。
どちらを選ぶかの目安
検証環境で比べた範囲では、AWS Emulator はアカウントも auth token も要らずに最新版を使え、起動と応答が速く、DynamoDB のテーブルの状態の移り変わりも API リファレンスの説明どおりでした。一方で、テーブルを作ってすぐ書き込むテストは、LocalStack では通り、AWS Emulator では ResourceNotFoundException で落ちました。LocalStack から乗り換えるときは、テーブルを作るところに wait table-exists のような待ちが入っているかを見直します。
LocalStack は、検証環境では 4.14.0 なら auth token なしで起動でき、最新のイメージは auth token がないと起動しませんでした。最新の LocalStack を使うには、アカウントを作って auth token を設定します。



