AWSが2026年5月にオープンソースプロジェクト「ExtendDB」を公開しました。一言で言うと、DynamoDBのAPIをそのまま使いながら、PostgreSQLなど別のストレージで動かせるアダプターです。
なぜExtendDBが生まれたのか
Amazon DynamoDBはAWSを代表するNoSQLデータベースです。高速で使いやすく、多くのチームがDynamoDBを中心にアプリケーションを構築しています。しかしその分、DynamoDBへの依存度も高くなります。
問題になるのが、クラウドに接続できない環境です。たとえば航空会社の搭乗ゲートシステムや機内販売システムは、ネットワーク障害中でも動き続けなければなりません。しかしDynamoDBはAWS上のマネージドサービスのため、クラウド接続なしには使えません。結果として、開発チームはオンプレミス向けに別のデータアクセス層を作り、2つのコードベースを維持するという二重のコストを強いられてきました。
ExtendDBはこの課題を解決するために作られました。
ExtendDBとは何か
ExtendDBはRust製のアダプターで、DynamoDBのワイヤープロトコルを実装しています。アプリケーションから見るとDynamoDBと全く同じAPIに見えますが、実際のデータはPostgreSQLに保存されます。既存のAWS SDK・CLI・ツール類は一切変更不要で、エンドポイントのURLを差し替えるだけで接続先をDynamoDB↔ExtendDBで切り替えられます。
主なユースケースは3つです。
- ローカル開発・CI/CD ではクラウドへの依存なしにDynamoDBのコードをそのまま動かせます。テストがすぐ起動し、クリーンに終了します。
- オンプレミス・エアギャップ環境 では、クラウド非接続の環境でもDynamoDB APIを使い続けられます。冒頭の航空会社の例がまさにこのケースです。
- マルチクラウド・ハイブリッド では、PostgreSQLが動く場所ならどこでもDynamoDB APIを使えるため、インフラの選択肢が広がります。
技術的な特徴
ExtendDBはシングルバイナリで動作し、外部ランタイムは不要です。ストレージ層はRustのトレイトで抽象化されており、現在はPostgreSQLが実装されていますが、将来的にはCassandraなど他のバックエンドも追加できる設計になっています。セキュリティ面ではTLSが必須で、自己署名証明書を自動生成します。認証はAWS SDKと同じSigV4署名方式を採用しており、アプリコードの変更が不要です。
対応している操作も充実しており、テーブル操作・アイテムのCRUD・クエリ・スキャン・トランザクション・Streams・TTLなど、DynamoDBの主要な機能をカバーしています。
注意点
ExtendDBはあくまでv0.1の開発・実験段階のリリースです。マネージドDynamoDBの代替ではなく、パフォーマンス特性や運用特性は異なります。またグローバルテーブルやクロスリージョンレプリケーションは非対応です。認証情報はExtendDB独自の実装でAWS IAMとは別物のため、本番のAWSリソースと混在して使うことはできません。
開発・テスト・オンプレミス用途であれば、すぐに試せる面白いプロジェクトです。Apache 2.0ライセンスで公開されており、コントリビューションも歓迎されています。
さっそくやってみる
環境は Amazon Linux 2023 on Amazon EC2 を使います。
まずデータバックエンドとしてPostgreSQL16をインストールします。
sudo dnf update -y
sudo dnf install -y postgresql16 postgresql16-server
sudo postgresql-setup --initdb
sudo systemctl enable postgresql
sudo systemctl start postgresql
sudo systemctl status postgresql | head -5Active: active (running) と表示されていれば成功です。
次にPostgresへ接続するユーザーを作成します。そのままデフォルトにシェルへアクセスしている ec2-user を作成します
sudo -u postgres psql -c "CREATE USER \"ec2-user\" WITH SUPERUSER PASSWORD 'mypassword';"
sudo sed -i 's/^local all all peer/local all all md5/' /var/lib/pgsql/data/pg_hba.conf
sudo sed -i 's/^host all all 127.0.0.1\/32 ident/host all all 127.0.0.1\/32 md5/' /var/lib/pgsql/data/pg_hba.conf
sudo cat /var/lib/pgsql/data/pg_hba.conf | grep -v "^#" | grep -v "^$"
sudo systemctl restart postgresql次のステップではExtendDBの実装に使われているRustをインストールします。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 途中の選択肢は「1」を押してデフォルトインストールします
source ~/.cargo/env
# 1.85以上であることを念のため確認します
rustc --version必要な依存パッケージをインストールします
sudo dnf install -y git gcc openssl-devel pkg-configExtendDB のGitからパッケージをダウンロードしビルドを行います。
git clone https://github.com/ExtendDB/extenddb.git
cd extenddb
cargo build --releaseでは ExtendDB を初期化して、起動します。
./target/release/extenddb init --pg-pass mypassword
./target/release/extenddb serve --config extenddb.toml以下で表示される部分を保存しておきます。
--- Creating default account '909818950741'...
Account ID: 909818950741
<snip>
┌─────────────────────────────────────────────────┐
│ Admin credentials (shown once, save them now) │
│ │
│ Username: admin │
│ Password: n6cvY90YjtCQD9fQKuceDiJA │
└─────────────────────────────────────────────────┘extendDBへアクセスするためのシークレットを発行します。 <admin-passowrd> と <account-id>は環境ごとに異なりますので置き換えて下さい。
>./target/release/extenddb manage \
--user admin --password '<admin-password>' \
create-user --account-id <account-id> --user-name myuser
./target/release/extenddb manage \
--user admin --password '<admin-password>' \
put-user-policy --account-id <account-id> --user-name myuser \
--policy-name full-access \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"dynamodb:*","Resource":"*"}]}'
./target/release/extenddb manage \
--user admin --password '<admin-password>' \
create-access-key --account-id <account-id> --user-name myuserそうするとダミーのIAMクレデンシャルが発行されます。これはAWSアカウントとは紐づいていませんので注意してください。ただし環境を切り替えればそのままDynamoDBへ接続できるのがExtendDBの特徴ですので、本物と同じ構造をしています。
IAM user created
{
"access_key_id": "AKIAEXTENDDBE3K2Y6FY",
"secret_access_key": "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"
}発行されたクレデンシャルを環境変数にセットします。
export AWS_ACCESS_KEY_ID="AKIAEXTENDDBE3K2Y6FY"
export AWS_SECRET_ACCESS_KEY="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"
export AWS_CA_BUNDLE=~/.extenddb/tls/cert.pemでは AWS CLI でDynamo DBと同じ操作を行います。
# テーブル作成
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions AttributeName=PK,AttributeType=S AttributeName=SK,AttributeType=S \
--key-schema AttributeName=PK,KeyType=HASH AttributeName=SK,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST \
--endpoint-url https://127.0.0.1:8000 \
--region us-east-1
# アイテムの書き込み
aws dynamodb put-item \
--table-name Orders \
--item '{"PK":{"S":"CUSTOMER#123"},"SK":{"S":"ORDER#2026-001"},"total":{"N":"49.99"}}' \
--endpoint-url https://127.0.0.1:8000 \
--region us-east-1
# クエリで取得
aws dynamodb query \
--table-name Orders \
--key-condition-expression "PK = :pk" \
--expression-attribute-values '{":pk":{"S":"CUSTOMER#123"}}' \
--endpoint-url https://127.0.0.1:8000 \
--region us-east-1{
"TableDescription": {
"AttributeDefinitions": [
{
"AttributeName": "PK",
"AttributeType": "S"
},
{
"AttributeName": "SK",
"AttributeType": "S"
}
],
"TableName": "Orders",
"KeySchema": [
{
"AttributeName": "PK",
"KeyType": "HASH"
},
{
"AttributeName": "SK",
"KeyType": "RANGE"
}
],
"TableStatus": "CREATING",
"CreationDateTime": "2026-05-23T02:32:54.944013+00:00",
"ProvisionedThroughput": {
"NumberOfDecreasesToday": 0,
"ReadCapacityUnits": 0,
"WriteCapacityUnits": 0
},
"TableSizeBytes": 0,
"ItemCount": 0,
"TableArn": "arn:aws:dynamodb:us-east-1:909818950741:table/Orders",
"TableId": "dd6c0856-48ae-4519-a793-45118e33b44c",
"BillingModeSummary": {
"BillingMode": "PAY_PER_REQUEST",
"LastUpdateToPayPerRequestDateTime": "2026-05-23T02:32:54.944013+00:00"
},
"DeletionProtectionEnabled": false
}
}
{
"Items": [
{
"PK": {
"S": "CUSTOMER#123"
},
"SK": {
"S": "ORDER#2026-001"
},
"total": {
"N": "49.99"
}
}
],
"Count": 1,
"ScannedCount": 1,
"ConsumedCapacity": null
}環境構築完了です!
PostgreSQL の中身
psql "postgresql://ec2-user:mypassword@localhost:5432/extenddb"\dt
List of relations
Schema | Name | Type | Owner
--------+-------------------------------------------+-------+----------
public | _ddb_dd6c0856-48ae-4519-a793-45118e33b44c | table | extenddb
public | idempotency_tokens | table | extenddb
public | stream_records | table | extenddb
public | stream_shards | table | extenddb
(4 rows)SELECT * FROM "_ddb_dd6c0856-48ae-4519-a793-45118e33b44c";
pk | sk_s | sk_n | sk_b | item_data
--------------+----------------+------+------+---------------------------------------------------------------------------------------
CUSTOMER#123 | ORDER#2026-001 | | | {"PK": {"S": "CUSTOMER#123"}, "SK": {"S": "ORDER#2026-001"}, "total": {"N": "49.99"}}
(1 row)DynamoDBのアイテムではそのままjsonとして格納されているようです。このため検索などにおけるパフォーマンスは注意が必要です。

