Fix: Heroku H10 App Crashed Error
Quick Answer
Fix the Heroku H10 App Crashed error by fixing your Procfile, PORT binding, missing dependencies, and build scripts with step-by-step solutions.
The Error
You deploy to Heroku and your app shows:
Application error
An error occurred in the application and your page could not be served.In the logs (heroku logs --tail), you see:
heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" status=503
heroku[web.1]: State changed from starting to crashed
heroku[web.1]: Process exited with status 1The H10 error code means your application process crashed immediately after starting.
Why This Happens
Heroku starts your app by running the command in your Procfile. If the process exits for any reason — missing dependencies, incorrect start command, uncaught exceptions, or failure to bind to the assigned port — Heroku marks it as crashed and returns H10 to all incoming requests.
Unlike local development, Heroku assigns a dynamic port via the PORT environment variable. Hardcoding a port like 3000 causes the app to start but become unreachable, which Heroku interprets as a crash.
Fix 1: Create or Fix Your Procfile
The Procfile tells Heroku how to start your app. It must be in the root directory with exact capitalization (Procfile, not procfile or PROCFILE):
web: node server.jsFor common frameworks:
# Node.js / Express
web: node server.js
# Node.js with npm script
web: npm start
# Python / Django
web: gunicorn myproject.wsgi
# Python / Flask
web: gunicorn app:app
# Ruby / Rails
web: bundle exec rails server -p $PORT
# Java / Spring Boot
web: java -jar target/myapp.jar --server.port=$PORTIf you don’t have a Procfile, Heroku tries to detect your framework automatically. This often fails or runs the wrong command. Always create an explicit Procfile.
Verify the Procfile is tracked by Git:
git ls-files Procfile
# Should output: ProcfilePro Tip: Heroku ignores files not tracked by Git. If your
Procfileis in.gitignoreor was never committed, Heroku won’t see it. Rungit add Procfile && git commit -m "Add Procfile".
Fix 2: Bind to the Correct PORT
Heroku assigns a dynamic port through the PORT environment variable. Your app must listen on this port:
// Node.js / Express
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});# Python / Flask
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)# Python / Django (gunicorn handles this automatically)
# In Procfile:
web: gunicorn myproject.wsgi --bind 0.0.0.0:$PORTCommon mistakes:
// Wrong - hardcoded port
app.listen(3000);
// Wrong - listening on localhost only
app.listen(PORT, '127.0.0.1');
// Correct - listen on all interfaces
app.listen(PORT, '0.0.0.0');Heroku expects your app to bind to $PORT within 60 seconds of starting. If it takes longer, Heroku kills the process with an R10 error.
Fix 3: Fix Missing Dependencies
Dependencies listed in devDependencies are not installed by default on Heroku. If your app needs them at runtime, move them to dependencies:
{
"dependencies": {
"express": "^4.18.0",
"dotenv": "^16.0.0"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}If you need devDependencies installed (e.g., for TypeScript compilation during build):
heroku config:set NPM_CONFIG_PRODUCTION=false
# Or for newer Node.js buildpacks:
heroku config:set NODE_ENV=developmentFor Python, ensure your requirements.txt is complete:
pip freeze > requirements.txtCheck for native dependencies that need buildpacks:
# Add buildpack for apps needing specific system libraries
heroku buildpacks:add --index 1 heroku-community/aptFix 4: Fix Build Scripts
If your app requires a build step (TypeScript compilation, frontend bundling), configure it properly:
{
"scripts": {
"build": "tsc && webpack --mode production",
"start": "node dist/server.js",
"heroku-postbuild": "npm run build"
}
}Heroku runs scripts in this order:
heroku-prebuild(if exists)npm installbuildscript (automatically, since Heroku 2023+)heroku-postbuild(if exists)- Prunes devDependencies
- Runs
Procfilecommand
If your build creates output in dist/ but your Procfile points to src/server.js, the app crashes because the compiled files don’t exist:
# Wrong - source file, not compiled
web: node src/server.js
# Correct - compiled output
web: node dist/server.jsCommon Mistake: Forgetting to commit the build output or expecting Heroku to compile TypeScript without the
buildscript. Heroku doesn’t install TypeScript globally — it must be in your dependencies and invoked through a script.
Fix 5: Fix Dyno Startup Issues
Check the actual crash reason in the logs:
heroku logs --tail --app your-app-nameLook for the error message before the crash line:
Error: Cannot find module './config/database'
heroku[web.1]: Process exited with status 1
heroku[web.1]: State changed from starting to crashedCommon startup errors:
# Missing module
Error: Cannot find module 'express'
# Fix: npm install express --save
# Syntax error
SyntaxError: Unexpected token 'export'
# Fix: Use CommonJS or configure ESM properly
# Missing environment variable
TypeError: Cannot read properties of undefined (reading 'split')
# Fix: Set config vars on HerokuRestart the dyno after making changes:
heroku restart --app your-app-nameFix 6: Handle Memory Limits
Heroku free/hobby dynos have 512 MB memory. If your app exceeds this, it’s killed with an R14 (memory quota exceeded) or R15 error, which can appear as H10 on the next restart:
# Check memory usage
heroku logs --tail | grep "memory"Reduce memory usage:
// Node.js - limit heap size
// In Procfile:
web: node --max-old-space-size=460 server.js# Python - use fewer Gunicorn workers
# In Procfile:
web: gunicorn myapp:app --workers 2 --threads 2For Node.js memory issues, common culprits are:
- Loading large datasets into memory
- Not closing database connections
- Memory leaks from event listeners
- Large npm packages
Fix 7: Configure Environment Variables (Config Vars)
Missing config vars are a silent killer. Your app starts, can’t find required configuration, and crashes:
# Set config vars
heroku config:set DATABASE_URL=postgres://...
heroku config:set SECRET_KEY=your-secret-key
heroku config:set NODE_ENV=production
# View current config
heroku config
# Remove a config var
heroku config:unset DEBUGDon’t commit .env files. Use Heroku config vars instead:
# Copy from .env to Heroku
while IFS='=' read -r key value; do
heroku config:set "$key=$value"
done < .envVerify your app handles missing variables gracefully:
const requiredVars = ['DATABASE_URL', 'SECRET_KEY', 'API_KEY'];
for (const varName of requiredVars) {
if (!process.env[varName]) {
console.error(`Missing required environment variable: ${varName}`);
process.exit(1);
}
}Fix 8: Fix Buildpack Issues
Wrong or missing buildpacks cause the app to build incorrectly:
# Check current buildpacks
heroku buildpacks
# Set the correct buildpack
heroku buildpacks:set heroku/nodejs
heroku buildpacks:set heroku/python
# Multiple buildpacks (order matters)
heroku buildpacks:add --index 1 heroku/nodejs
heroku buildpacks:add --index 2 heroku/pythonIf Heroku auto-detects the wrong language (e.g., it sees both package.json and requirements.txt), set the buildpack explicitly.
For monorepos where the app isn’t in the root:
heroku config:set PROJECT_PATH=packages/apiClear the build cache if you changed buildpacks:
heroku plugins:install heroku-repo
heroku repo:purge_cache --app your-app-name
git push heroku mainStill Not Working?
Run the app locally with production settings. Use
NODE_ENV=production npm startorheroku localwith your Procfile to reproduce the issue.Check for Heroku-specific limitations. Heroku has an ephemeral filesystem — files written to disk are lost on dyno restart. Use S3 or similar for file storage.
Try scaling down and up.
heroku ps:scale web=0thenheroku ps:scale web=1forces a fresh start.Check your Git remote. Ensure you’re pushing to the correct Heroku app:
git remote -v.Look for port binding race conditions. If your app performs async initialization before calling
listen(), it might time out. Bind the port first, then initialize.Review the release phase. If you have a
releasecommand in your Procfile that fails, it prevents the new release from deploying:release: python manage.py migrate.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Vercel Deployment Failed - Common Causes and Solutions
Fix Vercel deployment failures caused by build errors, environment variables, serverless function limits, and dependency issues with step-by-step solutions.
Fix: ASP.NET 500 Internal Server Error
Fix ASP.NET 500 Internal Server Error by enabling developer exception pages, fixing DI registration, connection strings, and middleware configuration.
Fix: Celery Task Not Received or Not Executing
Fix Celery tasks not being received or executed by resolving broker connections, autodiscovery issues, task name mismatches, and worker configuration.
Fix: Elasticsearch Cluster Health Red Status
Fix Elasticsearch cluster health red status by resolving unassigned shards, disk watermark issues, node failures, and shard allocation problems.