feat(cli): generate per-table stacks for multiple DDB tables#14688
Open
9pace wants to merge 9 commits intogen2-migrationfrom
Open
feat(cli): generate per-table stacks for multiple DDB tables#146889pace wants to merge 9 commits intogen2-migrationfrom
9pace wants to merge 9 commits intogen2-migrationfrom
Conversation
Previously, all DynamoDB tables were placed in a single shared storage
stack, causing conflicts when multiple tables existed. Each DDB table
now gets its own nested stack via backend.createStack('storage<name>'),
matching the Gen1 nested stack naming convention.
Also fixes resolveOutputs() crash when a Gen2 storage stack has no
Outputs section (happens when no cross-stack references exist for a
table).
Closes #14608, #14597
…ture data Recapture discussions app snapshots from live deployments: - Gen1: amplify-discussionsblade-blade-4edfd (activity + bookmarks tables) - Gen2: amplify-d1skq8aomhb772-e2etest-branch (per-table stacks) Pre-generate inputs use real amplify-pull data for bookmarks resource. Pre-refactor templates fetched from deployed CloudFormation stacks. Post-generate and post-refactor regenerated by test framework. Also adds bookmarks to migration-config.json and fixes snapshot.ts to use TemplateStage: Original for unprocessed templates.
Replace raw app ID d1skq8aomhb772 with sanitized name 'discussions' in all snapshot file contents and filenames.
9pace
commented
Mar 18, 2026
| categoryCounts.set(r.category, (categoryCounts.get(r.category) ?? 0) + 1); | ||
| let stackName: string; | ||
| switch (r.key) { | ||
| case 'storage:DynamoDB': |
…er-table-stacks # Conflicts: # amplify-migration-apps/discussions/README.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-deployed discussions app with 3 storage types (activity DDB, bookmarks DDB, avatars S3) and captured fresh snapshots for all 4 stages. Per-table stacks refactor verified working for both DDB tables. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The S3 forward/rollback refactorers used findNestedStack with a bare
'storage' prefix, which matched DDB per-table stacks (e.g.
'storageactivity') before the S3 stack ('storage0EC3F24A'). Fixed by
using 'storage' + resourceName for Gen1 lookup and a new
findS3NestedStack method that distinguishes the CDK-hashed S3 stack
from lowercase-prefixed DDB stacks for Gen2 lookup.
Also refreshes discussions snapshots from a clean main/gen2-main deploy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
backend.createStack('storage<resourceName>'), instead of placing all DDB tables in a single sharedstoragestack. This matches Gen1's per-resource nested stack naming and enables independent refactor/rollback of each table.resourceNamethroughStorageDynamoForwardRefactorerandStorageDynamoRollbackRefactorer, using'storage' + resourceNamefor both Gen1 and Gen2 nested stack lookups viafindNestedStackprefix matching.findNestedStack(facade, 'storage')which ambiguously matched DDB per-table stacks (e.g.storageactivity) before the actual S3 stack (storage0EC3F24A). Fixed by using'storage' + resourceNamefor Gen1 lookup and a newfindS3NestedStackmethod that distinguishes the CDK-hashed S3 stack from lowercase-prefixed DDB stacks.validateSingleResourcePerCategorywithvalidateSingleResourcePerStack, which maps each resource (DDB and S3) to its own stack name and rejects only when multiple resources target the same stack.resolveOutputs()no longer crashes when a Gen2 storage stack has noOutputssection (CDK omits Outputs when there are no cross-stack references to a table).CFNTemplate.Outputsis now optional.Changes
Source (
packages/amplify-cli/src/commands/gen2-migration/)generate/amplify/backend.generator.ts— newcreateDynamoDBStack(resourceName)methodgenerate/amplify/storage/dynamodb.generator.ts— callscreateDynamoDBStackinstead ofensureStorageStackgenerate/amplify/storage/dynamodb.renderer.ts— acceptsscopeVarNameparameterrefactor/refactor.ts—validateSingleResourcePerStack, threadsresourceNameinto DDB and S3 refactorersrefactor/storage/storage-forward.ts— acceptsresourceName, usesfindS3NestedStackfor Gen2 lookuprefactor/storage/storage-rollback.ts— acceptsresourceName, usesfindS3NestedStackfor Gen2 lookuprefactor/storage/storage-dynamo-forward.ts— per-table stack lookuprefactor/storage/storage-dynamo-rollback.ts— per-table stack lookuprefactor/resolvers/cfn-output-resolver.ts— handles missing Outputs sectioncfn-template.ts—Outputsmade optionalTests
storageavatars,storage0EC3F24A) and passresourceName'storageavatars'in error messagecreateDynamoDBStack, custom scope variable, multi-DDB generate, no-Outputs templatesSnapshots (
amplify-migration-apps/discussions/)storageactivityA346F297,storagebookmarks210DAF62,storage0EC3F24A(S3)E2E Verification
Tested end-to-end on
discussionsapp (d2l28asetq9wsc, us-east-1):createStack('storageactivity')+createStack('storagebookmarks')+ S3 storagestorageactivityA346F297,storagebookmarks210DAF62,storage0EC3F24Anested stacksTest plan
Closes #14608, #14597