「AIにカラム追加させたいだけなのに、マイグレーション地獄…」
AI開発が日常になった2026年、こんな経験はありませんか?
バイブコーディングでサクサク書いてもらった機能、いざDBに保存しようとしたら「カラムが足りない、マイグレーションを書かなきゃ」となって急ブレーキ。AIが「ALTER TABLE文を書きました」と言ってくるけど、本番に当てるには手順を踏む必要があるし、開発・ステージング・本番の3環境で順番にマイグレーションを実行して…と、テンポが完全に止まる。
そんな時、ふと思うわけです。「スキーマレスのDBなら、カラムを後から追加できるんでしょ?」と。具体的に名前が浮かぶのが DynamoDB。AWSのフルマネージドNoSQLで、スキーマレスが売りの一つ。これってバイブコーディング時代に最適なんじゃない?
結論を先に言うとこうです。
- 確かに相性は良い:属性追加が即時できる、マイグレーション不要、AIが書いた変更がそのまま動く
- ただし万能じゃない:「自由」の裏には「責任」がある。データ品質はアプリ側で担保する必要
- 使い分けが正解:プロトタイプ・MVP段階は最強、機能が固まったら要件次第で再評価
本記事では、「DynamoDBとは何か?」「スキーマレスの本当の意味は?」「AI開発・バイブコーディングと本当に相性いいのか?」を、Next.jsでの実装例も交えて検証します。AWS縛りでDB選びに悩んでる人、AIで爆速開発したい人にぴったりの内容です。
そもそもDynamoDBって何?
Amazon DynamoDBは、AWSが提供するフルマネージドのNoSQLデータベースサービスです。シンプルに言うと、「サーバー管理なし・無限スケール・低レイテンシ」が売りのキーバリュー型DB。
主な特徴
- フルマネージド:サーバーのプロビジョニング、パッチ適用、バックアップが全自動
- 無限スケール:数十万リクエスト/秒でも自動でスケールアウト
- ミリ秒応答:基本的なクエリは一桁ミリ秒で返ってくる
- 従量課金:使った分だけ(オンデマンド)または事前予約(プロビジョンド)
- サーバーレス親和性:Lambdaとの相性が最高、IAMで認証完結
- マルチリージョン対応:グローバルテーブルでクロスリージョンレプリケーション可能
RDBとの根本的な違い
PostgreSQLやMySQLのようなRDB(リレーショナルDB)とは、思想が根本的に違います。
| 項目 | RDB(PostgreSQLなど) | DynamoDB |
|---|---|---|
| データ構造 | テーブル・行・列(固定スキーマ) | テーブル・アイテム・属性(柔軟) |
| スキーマ | 事前定義必須 | キー以外は自由 |
| クエリ言語 | SQL(柔軟) | 専用API(限定的) |
| JOIN | 得意 | 苦手(基本不可) |
| スケール | 垂直スケール中心 | 水平スケール無限 |
| 料金 | インスタンス時間課金 | リクエスト数+ストレージ課金 |
RDB派の人は psqlとは?PostgreSQLをコマンドラインで操作する基本コマンド あたりが馴染み深いと思いますが、DynamoDBは思想が違うので、SQL感覚で触ろうとすると戸惑います。
「スキーマレス」の本当の意味
「DynamoDBはスキーマレス」とよく言われますが、これは「なんでもアリ」ではありません。誤解されがちなので、正確に整理しておきましょう。
必須なものと自由なもの
- 必須:パーティションキー(テーブル作成時に決める。これがないとデータ取得できない)
- 任意:ソートキー(複合キーにしたい時に追加で指定)
- 自由:その他の属性(後からいくらでも追加・削除できる)
つまり、「キーは厳密、それ以外はめちゃくちゃ自由」というのがDynamoDBのスキーマレス。例えるなら、図書館の本棚みたいな構造。
[DynamoDBのテーブル:Users]
パーティションキー: email(必須)
各アイテムの中身(属性)は自由:
─────────────────────────────────
{
email: "alice@example.com", ← 必須キー
name: "Alice",
age: 30
}
{
email: "bob@example.com", ← 必須キー
name: "Bob",
age: 25,
hobby: "釣り", ← 突然追加されてもOK
preferences: { theme: "dark" } ← ネストした構造もOK
}
{
email: "charlie@example.com", ← 必須キー
name: "Charlie"
← age属性すら無くてもOK
}
─────────────────────────────────1つのテーブルの中で、アイテムごとに持っている属性が違っても問題ない。これがスキーマレスの本質です。
RDBの「行」とDynamoDBの「アイテム」の決定的な違い
[RDB(PostgreSQL):usersテーブル]
カラム定義: id, email, name, age(NOT NULL含む)
─────────────────────────────────
| id | email | name | age |
| 1 | alice@... | Alice | 30 |
| 2 | bob@... | Bob | 25 |
| 3 | charlie@... | Charlie | NULL | ← ageはNULL許可必要
新しい属性を入れたい?
→ ALTER TABLE users ADD COLUMN hobby VARCHAR(50);
→ マイグレーション必要、ダウンタイムや調整必要
[DynamoDBのアイテム]
属性は各アイテムが持ちたいものだけ持つ
新しい属性を入れたい?
→ そのまま属性付きでPUTすればOK
→ 即時、ダウンタイムなし、マイグレーション不要この差が、AI開発・バイブコーディングと相性がいいと言われる最大の理由です。
RDBのマイグレーションとの比較
「カラム追加が即できる」って、具体的にどれくらい違うのか。実際のフローを比較してみましょう。
RDBの場合(PostgreSQL + Prisma)
# 1. schema.prisma を編集
# User モデルに hobby フィールド追加
# 2. マイグレーションファイル生成
npx prisma migrate dev --name add_hobby_to_user
# 3. 生成されたSQLをレビュー
# - prisma/migrations/xxx_add_hobby_to_user/migration.sql
# 4. ステージングで適用
npx prisma migrate deploy # in staging
# 5. 動作確認(既存データのNULL影響、デフォルト値など)
# 6. 本番でメンテ枠を取って適用
npx prisma migrate deploy # in production
# 7. ロールバック計画もセットで用意慎重にやるなら、ここまでで数時間〜数日かかることも。AIに「カラム追加して」と頼んでも、AIはこの全工程を踏ませてくる(むしろちゃんと踏ませないと事故る)。
DynamoDBの場合
// 既存のPutCommand に hobby を追加するだけ
await docClient.send(new PutCommand({
TableName: 'Users',
Item: {
email: 'alice@example.com',
name: 'Alice',
age: 30,
hobby: '釣り', // ← 突然追加してもOK
},
}))
// マイグレーション不要
// テーブル定義の変更不要
// デプロイは普通にコードPushだけ所要時間:30秒。AIにコード変更を頼んで、そのまま本番にデプロイできる。これが「スキーマレスは爆速」と言われる所以です。
AI開発・バイブコーディングとの相性を検証
ここからが本記事の山場。実際にAI開発と相性がいいのか、メリットとデメリットを正直に整理します。
メリット1:AIが書いたコードがそのまま動く
AIに「ユーザー情報に趣味フィールドを追加して」と頼むと、コードが返ってくる。RDBだとここから「マイグレーション書いて」「適用して」という追加工程が必要だけど、DynamoDBだとコードが返ってきたらそのまま動く。「思考のテンポ」が止まらないのが最大のメリット。
メリット2:プロトタイプ速度が圧倒的
MVP段階の「とりあえず作って動かしたい」フェーズでは、データモデルが日々変わります。「やっぱりこの項目も保存しよう」「ユーザー設定をネスト構造にしたい」といった変更が秒単位で発生する。
RDBだとマイグレーションの嵐になる場面でも、DynamoDBなら属性を増やすだけ。プロトタイプの速度が文字通り桁違いになります。
メリット3:サーバーレス構成と相性最高
AIで書いたコードを動かす先は、たいてい Lambda + API Gateway のようなサーバーレス構成。DynamoDBはこの構成に完璧にハマります。
- IAMロールで認証完結(接続文字列不要)
- Lambdaとの低レイテンシ通信
- RDBにありがちな「コネクション枯渇問題」が起きない
- 料金もリクエスト単位で揃ってるので予測しやすい
デメリット1:「型がない」ことの裏返しの混乱
スキーマレスは自由だけど、その分「データの一貫性をアプリ側で守る責任」が増えます。AIに任せて開発すると、こんなことが起きがち。
- あるアイテムは
age: 30(数値)、別のアイテムはage: "30"(文字列) - 項目名のtypoで
hobbyとhobbieが混在 - ある時期から急に新しい属性が増えて、既存アイテムには無い
デメリット2:クエリの柔軟性がRDBに劣る
「ageが20以上で、趣味が釣りで、登録日が3ヶ月以内のユーザー」みたいな複合条件のクエリは、DynamoDBでは事前にインデックス(GSI)を設計しないと厳しい。SQLの WHERE 句の自由度には全然及びません。
対処法:型定義とバリデーションで守る
デメリットは対処可能。TypeScriptの型 + Zodなどのバリデーションライブラリで、アプリ側でスキーマを担保するのが現代の鉄板。
import { z } from 'zod'
// アプリ側で「期待するスキーマ」を定義
const UserSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
age: z.number().int().nonnegative().optional(),
hobby: z.string().optional(),
preferences: z.object({
theme: z.enum(['light', 'dark']),
}).optional(),
})
type User = z.infer
// 書き込み前に必ずバリデーション
async function createUser(input: unknown) {
const validated = UserSchema.parse(input) // 不正なデータはここで弾かれる
await docClient.send(new PutCommand({
TableName: 'Users',
Item: validated,
}))
} これで「DBはスキーマレス、アプリは厳密」というハイブリッド構成に。柔軟性と安全性のいいとこ取りができます。
DynamoDBが向くケース・向かないケース
万能じゃないので、向き不向きをハッキリさせておきます。
向くケース
- プロトタイプ・MVP段階:データモデルが流動的で、AIで爆速開発したい
- サーバーレス構成:Lambda + API Gatewayで全部AWS完結
- 高スループット要件:秒間数千〜数万リクエストでもスケールしてほしい
- シンプルなクエリ中心:「IDでGET」「ユーザーごとの一覧取得」など
- 地理的に分散:マルチリージョンでグローバル対応
- セッション管理・キャッシュ:TTL機能で自動削除
向かないケース
- 複雑なJOINが多い業務系:会計、ERP、在庫管理など
- レポーティング・分析中心:集計クエリが日常的に走る
- 柔軟な検索が必要:「あらゆる条件で絞り込みたい」要件
- 厳密なトランザクション重視:DynamoDBのTransactWriteは制約あり
- RDBに慣れたチーム:学習コストが高い、設計の発想転換が必要
AI時代の現実解:使い分け戦略
「DynamoDBか、RDBか」の二択じゃなく、フェーズや用途で使い分けるのが現代の現実解です。
フェーズ別のおすすめ構成
| フェーズ | おすすめ構成 | 理由 |
|---|---|---|
| プロトタイプ・MVP | DynamoDB単体 | スキーマ流動、AI爆速開発、運用コスト低 |
| 初期リリース | DynamoDB(要件次第) | シンプルなクエリで足りるならそのまま |
| 機能拡大期 | DynamoDB + PostgreSQL併用 | 主データはDynamoDB、分析・複雑クエリはPG |
| 分析・レポート | DynamoDB → BigQuery等にエクスポート | 分析特化のサービスに任せる |
もしPostgreSQLに移行を検討するなら 無料で使えるPostgreSQLサービス8選 も参考に。Supabase、Neon、AWS RDSなど無料で始められる選択肢も豊富です。
AIに任せるならスキーマレス+型定義
バイブコーディング前提なら、「DBはDynamoDBで柔軟に、TypeScriptとZodで型安全」というセットが最適解。AIが新機能を追加するたびに、型定義も一緒に更新してもらえばOK。マイグレーションのストレスから解放されます。
Next.js + DynamoDB 実装例
具体的にコードがどんな感じか、Next.js (App Router) + AWS SDK v3 で見ていきましょう。
セットアップ
# 必要なパッケージをインストール
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb zod// lib/dynamodb.ts
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'
const client = new DynamoDBClient({ region: 'ap-northeast-1' })
export const docClient = DynamoDBDocumentClient.from(client)CRUD実装
// app/api/users/route.ts
import { docClient } from '@/lib/dynamodb'
import {
PutCommand,
GetCommand,
UpdateCommand,
DeleteCommand,
} from '@aws-sdk/lib-dynamodb'
import { z } from 'zod'
const UserSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
age: z.number().int().nonnegative().optional(),
})
// CREATE
export async function POST(req: Request) {
const body = await req.json()
const user = UserSchema.parse(body)
await docClient.send(new PutCommand({
TableName: 'Users',
Item: user,
ConditionExpression: 'attribute_not_exists(email)', // 重複防止
}))
return Response.json({ user })
}
// READ
export async function GET(req: Request) {
const email = new URL(req.url).searchParams.get('email')
const result = await docClient.send(new GetCommand({
TableName: 'Users',
Key: { email },
}))
return Response.json({ user: result.Item })
}
// UPDATE(属性を後から追加もこれでOK)
export async function PATCH(req: Request) {
const { email, ...updates } = await req.json()
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { email },
UpdateExpression: 'SET #h = :hobby', // hobbyフィールドを追加
ExpressionAttributeNames: { '#h': 'hobby' },
ExpressionAttributeValues: { ':hobby': updates.hobby },
}))
return Response.json({ ok: true })
}
// DELETE
export async function DELETE(req: Request) {
const email = new URL(req.url).searchParams.get('email')
await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { email },
}))
return Response.json({ ok: true })
}AIに「ユーザーに趣味フィールドを追加して」と頼んだ時の差分はこれだけ。UserSchema に hobby を追加して、PATCH処理に反映するだけで完了。マイグレーション一切なし。AWS CLIで実際にテーブル状態を見ながら開発する場合は AWS CLIで開発が爆速になる を参考にどうぞ。
DynamoDB活用の落とし穴3選
使い始めると必ずぶつかる罠を、先回りで紹介しておきます。
落とし穴1:パーティションキー設計を後悔する
属性は自由でも、パーティションキーは後から変更不可。「とりあえずID使っとくか」で進めると、後で「メールアドレスでも検索したい」と思った時に困る。
対処法:GSI(グローバルセカンダリインデックス)を後から追加するか、最初から想定アクセスパターンを洗い出して設計する。
落とし穴2:「全件取得」が罠
RDB感覚で SELECT * FROM users 的なことをやると、Scan操作になって全データ走査される。データ量が増えると料金もレイテンシも爆発。
対処法:基本はQuery(パーティションキー指定)で取得、Scanは管理画面など限定的に使う。
落とし穴3:トランザクションの制約
DynamoDBにもトランザクション機能(TransactWriteItems)はあるけど、1リクエストで最大100アイテム、4MBまでなどの制約あり。RDBほど自由ではない。
対処法:そもそもトランザクションが頻発する設計はDynamoDB向きじゃない。シンプルなアクセスパターンを意識する。
まとめ:スキーマレスは「自由」と「責任」のセット
本記事のポイントを整理します。
- DynamoDBはAWSのフルマネージドNoSQL:サーバー管理不要、無限スケール、サーバーレス親和性◎
- スキーマレス=キーは厳密、それ以外は自由:「なんでもアリ」ではない
- マイグレーション不要:属性を追加したいなら、PUTするだけで即時
- AI開発・バイブコーディング相性◎:思考のテンポを止めずに開発できる
- 万能じゃない:複雑クエリ・JOIN・厳密トランザクションは苦手
- 型定義 + Zodでハイブリッド:DBは柔軟、アプリは厳密が現代の鉄板
- 使い分けが正解:プロトタイプはDynamoDB、機能成熟期はPostgreSQL併用も検討
「AIにマイグレーションさせるのダルい」と思っているなら、DynamoDBは間違いなく試す価値があります。「DBがボトルネックになって思考が止まる」体験から解放されるのは、AI時代の開発において想像以上に大きい。
ただし、自由には責任がセット。型定義を雑にしたまま進めると、後で「データの整合性が崩れていた」「項目名がバラバラ」みたいな悲劇が起きます。DBを柔軟にする分、アプリ側で守りを固める。これがバイブコーディング × スキーマレスの黄金パターンです。
まずはプロトタイプで一度試してみて、テンポ感の違いを体感してみてください。AIとペアプロするとき、マイグレーションが消えるだけで開発体験が一段階上がるはずです。
DB設計・AI開発をさらに磨く関連記事
DynamoDB × スキーマレス × AI開発の感触をつかんだら、次はDB選択の幅やセキュリティ設計、AI開発の安全運用まで広げていきましょう。実装力が一段階上がる関連記事を厳選しました。
DB選択・実装の幅を広げる
- Firebase Auth + DynamoDB のDB分断地獄から抜け出した話|write-throughで段階移行する設計パターン – DynamoDBに認証データを統合する実例。本記事の応用編として、DB統一のリアルな事例が学べます
- psqlとは?PostgreSQLをコマンドラインで操作する基本コマンドと実践的な使い方 – RDB側の代表格、PostgreSQLの基礎。DynamoDBとの対比で「使い分け」の判断軸が研ぎ澄まされます
- 無料で使えるPostgreSQLサービス8選を比較!2025年版おすすめ – DynamoDBが向かないケースで併用するPostgreSQLの選び方。ハイブリッド構成を検討する人へ
AI開発・サーバーレス構成を強化
- リリース前に必ず確認!バイブコーディング&非エンジニア向けWebアプリ安全チェックリスト – AI開発で爆速リリースする前の必読チェックリスト。スキーマレス×AI開発の落とし穴を補完できます
- AWS Lambda + API Gatewayで始めるサーバーレスAPI開発|実装手順から運用まで – DynamoDBの本領が発揮されるサーバーレス構成。Lambda+DynamoDBは現代のAI開発の王道セットです
- AWS CLIで開発が爆速になる!セットアップからCloudWatch・Lambda活用まで実用コマンド付き – DynamoDBテーブル操作にもAWS CLIは必須。マネジメントコンソールに頼らず爆速で開発する土台です
セキュリティ実装の引き出しを増やす
- bcryptでハッシュ化する|初心者エンジニア向けセキュリティ実装入門 – DynamoDBにパスワードや機密情報を保存する際の必修知識。スキーマレスでも、保存方法は厳密に
