CREATE_FAILED exceeded the limit on the number of resources in a single stack operation
How did you install the Amplify CLI?
yarn
If applicable, what version of Node.js are you using?
22.18.0
Amplify CLI Version
14.0.0
What operating system are you using?
Windows
Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.
No manual changed made
Describe the bug
When trying to run a sandbox or deploy I always get the CREATE_FAILED because of the "exceeded the limit on the number of resources in a single stack operation"
I have about 65 models and 40 functions, and the sandbox worked before I had to delete it and recreate because of massive model changes.
Expected behavior
I expect the app to just deploy like it did before
Reproduction steps
- create many models
- create a few lambda function resolvers
- After a certain amount it will always feel
Project Identifier
No response
Log output
# Put your logs below this line
Additional information
No response
Before submitting, please confirm:
- [x] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
- [x] I have removed any sensitive information from my code snippets and submission.
Hi @michael-trinity,
Thank you for reporting this issue. You've encountered a well-known architectural limitation where AWS CloudFormation has a hard limit of 500 resources per stack operation, and your application with 65 models and 40 functions is exceeding this limit.
This is a recurring challenge for users with large-scale Amplify applications. While we've made improvements with the GraphQL Transformer v2, automatic resource limit handling is not yet implemented.
Immediate Workarounds:
- Reduce model complexity - Consider splitting your 65 models into smaller, more focused schemas
- Optimize Lambda functions - Combine related resolvers where possible
- Incremental deployment - Deploy in smaller batches
Long-term Solution: This issue highlights the need for automatic stack refactoring in Amplify CLI. The solution involves implementing intelligent resource distribution across multiple CloudFormation stacks with proper cross-stack references, similar to the approach documented in AWS CloudFormation stack refactoring.
We encourage community contributions to help implement automatic resource limit detection and stack splitting in the GraphQLResourceManager. This would benefit all users with large-scale applications.
Related Issues: #9762, #13536, #9511 - This is a known scaling challenge that affects many users with complex GraphQL schemas.
@pahud Thanks for the information,
unfortunately the models are needed as it's an ecommerce platform, I might be able to combine some of the models, but it would cause issues.
I have already combined quite a few of the resolvers and currently in the process of combining even more, but because of auth/rights issues not all of them can be combined.
I'll try a staggered approach after checking to see if lambda function reduction helps.
It's too bad the limit can't be lifted once or twice for a single stack so people can actually deploy larger apps.
@pahud
3. Incremental deployment - Deploy in smaller batches
Thank you for all the info. Do you happen to have an example of this? I don't get this issue on existing environments, it seems to happen when I deploy a new one (like previews), so I imagine maybe we could technically deploy first some parts and then the rest... However, I'm not sure how to deploy it in smaller batches.
I really appreciate your help. Thanks!
@Erid I can help a little with this, I do have to tell that I completely moved away from Amplify because of this issue and the amount of work it costs to fix this.
What I did is the following:
- Create a base where you only have 1 table, the auth and no custom functions ( I recommend a different branch for this)
- Create another where you add some more tables that are connected (and the functions that fit with that)
- Keep doing this until you have your full application
Then deploy the first branch, wait for completion, then second branch (on the same project), etc.
Keep deploying each branch first to check if it worked, if not remove some tables or functions.
I ended up with 5 branches before I could deploy the app, but every time I had edits, it just caused pain and tons of wasted time.
Fully converted my app to use a different system instead and will not use Amplify again for larger projects.
@michael-trinity Thanks a lot for the idea!
I ended up going a different, but similar route. I grouped my models by "batches", so on first deploy it only deploys the "core" ones, and then it would deploy all models by the second deploy, and it worked. The main challenge was that some "core" models had references to some non-core ones, so I kept those references conditional for the second batch.
I did something like:
export const DEPLOY_BATCH = parseInt(
process.env.AMPLIFY_INITIAL_BATCH ?? "1", // New environments would start with batch 0
10
)
/**
* Conditionally include a configuration/object fragment.
*
* At runtime, when the condition is falsy, an empty object is returned so that
* spreading the result (`...includeIf(...)`) adds nothing. For the type system,
* we always return `T` so callers do not need to cast at each use-site.
*/
export function includeIf<T extends object>(condition: boolean, value: T): T {
if (!condition) return {} as T
return value
}
I would set the env variable to "0" globally, and override existing environments (like staging and production) to be "10" to ensure they don't delete any models by accident (though I recommend having delete protection on those). This makes it so any new environment (like previews) starts as "0". Also, casting the empty {} is essential to keep the Schema type stable, so it knows to always expect the models to be part of the schema.
On the schema I have something like:
export const schema = a
.schema({
...coreModels,
...includeIf(DEPLOY_BATCH >= 1, secondaryModels),
})
And on any core model that references any secondary model:
const Author = a.model({
// ...
...includeIf(DEPLOY_BATCH >= 1, { books: a.hasMany("Book", "authorId") })
})
With this solution we could technically expand it to more than 2 batches if we were to need to.
This is not an ideal solution, since it adds an extra burden of being very aware of the cross-dependencies and order of deployment, the automation for this is complicated too, since it needs at least two deployments per new environment and a way to update the env value after the first deploy happens; however, I'm sharing this in case it can help someone else, too. This worked for me, with increased deployment times, but hopefully someone can come up with a more elegant solution.
Hopefully the Amplify team can have a proper solution for us, since it's an important requirement for big systems. Maybe something like this approach could be better adapted internally, and much more efficiently.
+1 on here :)