Why Elastic Beanstalk for a Next.js app
Elastic Beanstalk is one of the more pragmatic ways to run a server-rendered Next.js app on AWS. It provisions EC2 instances behind an Application Load Balancer, handles scaling and health checks, and still leaves room to drop in custom nginx config, ALB rules, and CloudWatch monitoring through .ebextensions and .platform, without having to hand-build all of that from scratch.
This isn’t the only way to run Next.js on AWS, and it’s worth saying that upfront. Depending on the project, App Runner, ECS/Fargate, a container on EKS, or even a plain EC2 Auto Scaling Group behind an ALB can all be reasonable choices. Elastic Beanstalk sits in a specific spot: it gives you a real server (so next start, ISR, and API routes behave exactly as they do locally) while still automating most of the infrastructure plumbing.
The deploy script
Here’s the actual script used to ship a Next.js app to Elastic Beanstalk:
# Read env variables
ENV=${1:-production}
trap "exit" INT
echo "[$ENV] - Loading env variables..."
export $(xargs < .env.$ENV)
echo "[$ENV] - Installing npm packages..."
npm install
echo "[$ENV] - Removing old build..."
rm -rf .next
echo "[$ENV] - Building the app..."
CI=true npm run build
if [ $? -ne 0 ]; then
echo "[$ENV] - Build failed, exiting..."
exit 1
fi
echo "[$ENV] - Removing build cache folder..."
rm -rf .next/cache
echo "[$ENV] - Deploy to EB..."
eb deploy nexjs-app -l $(date +%s)
Walking through it:
- Load environment variables for the target environment (
.env.production,.env.staging, etc.) so the build has access to the right config. npm installto make sure localnode_modulesmatchespackage.jsonbefore building.rm -rf .nextto clear out any previous build output, so nothing stale leaks into the new one.CI=true npm run buildrunsnext build. TheCI=trueflag makes the build fail loudly instead of prompting interactively, which matters for a script that might run unattended in CI.rm -rf .next/cache, this is the one worth explaining properly (see below).eb deploy nexjs-app -l $(date +%s)deploys to the named EB environment, labeling the application version with a Unix timestamp so every deploy has a unique, sortable version label.
Why .next/cache gets removed, and whether the size limit still applies
The build cache under .next/cache is Next.js’s incremental build cache. It speeds up local rebuilds by reusing work from the previous build, but it isn’t read by next start at runtime. On a project with a large number of pages (which is exactly the shape of an app with thousands of dynamically rendered routes), that cache folder can balloon to hundreds of megabytes of dead weight in a production deploy bundle. Stripping it before eb deploy keeps the uploaded source bundle to roughly just the compiled app and source, no build-time artifacts that production never touches.
On the size limit itself: worth checking rather than assuming, since AWS limits change over time. As of the current Elastic Beanstalk documentation, the source bundle limit is 500 MB (some deployments report the practical ceiling closer to 512 MB). On a project with a large number of pages, an uncleared .next/cache folder can genuinely put a build within reach of that ceiling, enough for a deploy to fail outright if it’s left in.
Removing .next/cache keeps the bundle comfortably under that limit and has a second benefit regardless of how close to 500 MB a given build actually gets: a leaner bundle means faster uploads, faster eb deploy runs, and less S3 storage spent on old application versions over time.
Trimming the bundle further with .ebignore
The .next/cache removal isn’t the only thing keeping the deploy bundle small. An .ebignore file (same syntax as .gitignore) controls exactly what eb deploy zips up and uploads:
.cache
.elasticbeanstalk
.serverless
.serverless_nextjs
.vscode
node_modules
scripts
src
.env.development
.git
deploy_eb.sh
docker-compose.yml
README.md
serverless-post-build.js
serverless.yml
Two exclusions do most of the heavy lifting:
node_modules: Elastic Beanstalk’s Node.js platform runsnpm installon the instance itself as part of its own deploy hook whennode_modulesisn’t present in the bundle, so there’s no need to ship it.src: oncenext buildhas compiled everything into.next, the original source files aren’t needed to runnext start. Only.next,public,package.json, and the Next.js config are actually required at runtime.
Combined with the .next/cache cleanup, this is what keeps the upload small: source code that would otherwise sit around as unused weight in every single deploy is stripped out before it ever reaches EB.
Other ways to deploy a Next.js app to Elastic Beanstalk
The deploy_eb.sh + eb deploy approach is a solid default for a small team that wants a one-command deploy from a local machine or a simple CI job. It’s not the only option:
- EB console upload: zip the source bundle manually and upload it through the Elastic Beanstalk console. Useful for a one-off deploy or debugging, not something to rely on day to day.
- CI/CD pipelines (GitHub Actions, CodePipeline + CodeBuild, GitLab CI): run the same build steps in CI and use an action or the EB CLI to deploy, so every merge to a branch ships automatically instead of relying on someone running a local script.
- Docker on Elastic Beanstalk: instead of the Node.js platform, package the app as a container with a
Dockerfile(orDockerrun.aws.jsonfor multi-container setups). This trades some of the “it just works” platform automation for more control over the runtime environment. - Infrastructure as code: provisioning the EB application/environment itself with Terraform or the AWS CDK, then handling only the code deploy step with
eb deployor the EB API. Worth it once the environment configuration itself needs to be reproducible and version-controlled, not just the app code.
Which of these makes sense depends mostly on team size and how much deploy automation is already in place. A solo script is fine until “someone needs to remember to run it” becomes the bottleneck, at which point moving the same steps into CI is a small change with a real payoff.
Conclusion
Deploying Next.js to Elastic Beanstalk doesn’t require much beyond what next build and next start already do. The real work is in trimming what gets shipped. Clearing .next/cache and excluding node_modules and src via .ebignore keeps every deploy fast, lean, and comfortably inside the 500 MB source bundle limit.
Keep reading
Web Developer @ Wingravity, turning ideas into clean, working code. Curious about what we do, or want to team up? Say hi through our contact form.






