Express Port Binding and Listen Explained
app.listen binds Express to a port. Here is how port binding works and how to do it right.
Express Port Binding and Listen Explained
app.listen is the line that turns your Express app from a definition into a running server. Here is how it works.
What app.listen Does
app.listen(port, callback) tells Node's HTTP module to listen on the given port. Express calls http.createServer(app) under the hood. When a request arrives on that port, Express's middleware chain runs.
The Code
const app = require('./app');
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Why Use process.env.PORT
Production environments (AWS, Heroku, Render) set their own port. Hardcoding 3000 means your server cannot bind in those environments. Always use process.env.PORT || 3000.
Why Split app.js and server.js
If app.js only creates the app (no listen), you can import it in tests without binding to a port. server.js is the only file that calls listen. This pattern is small but useful.
Binding to 0.0.0.0
By default, app.listen binds to all interfaces. If you want to restrict (e.g., localhost only for dev), pass a host: app.listen(PORT, '127.0.0.1', callback). In production, you usually let it bind to all and let Nginx handle the public side.
EADDRINUSE Error
You see "address already in use." Something is already running on that port. Either another server is up or your old process did not quit. Kill it or use a different port.
Graceful Shutdown
When the process gets SIGTERM (e.g., deploy), close the server cleanly:
const server = app.listen(PORT);
process.on('SIGTERM', () => {
server.close(() => {
console.log('Server closed');
process.exit(0);
});
});
This lets in-flight requests finish before exit.
The Takeaway
app.listen(port, callback) binds Express to a port. Use process.env.PORT || 3000. Split app.js and server.js so you can test the app without a port. Bind to all interfaces in production. Handle SIGTERM for graceful shutdown. Watch out for EADDRINUSE.
It tells Node's HTTP module to listen on a port. Express calls http.createServer(app) under the hood. When a request arrives on that port, Express's middleware chain runs and dispatches to the handler.
Production environments (AWS, Heroku, Render) set their own port. Hardcoding 3000 means your server cannot bind there. Always use process.env.PORT || 3000 so it works in dev and prod.
If app.js only creates the app (no listen), you can import it in tests without binding to a port. server.js is the only file that calls listen. This pattern is small but useful for testing.
Address already in use. Something is already running on that port. Either another server is up or your old process did not quit. Kill it or use a different port.
Listen on SIGTERM, call server.close to stop accepting new connections and let in-flight requests finish, then process.exit(0). This prevents dropped requests when deploying or scaling down.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

