Doesn't this code create TWO servers?
No, the code you show only creates one http server.
Here's an annotated version of your code that explains what each line does:
// load the express module
const express = require('express')
// create an Express app object
const app = express()
// create an http server object and pass it the Express app object as a request handler
// this is a server object, but is not yet a running server
const server = require('http').createServer(app)
// decide what port we're going to use for the http server
const port = process.env.PORT || 3000
// create one Express route handler on the Express app object
app.get('/', (req, res) => {
res.status(200).send('Working')
})
// start up the server on the desired port so it is now actually running
// and log to the console when the server has finished starting up and is ready
// for incoming http requests
server.listen(port, () => {
console.log(`Server running on port: ${port}`)
})
I mean, if Express can handle the requests and the responses, why do I need to use the 'http' module?
Express is a framework for handling incoming http requests. Express itself does not contain any http server code and the app object in your code is not a server itself. It is an object that is used to coordinate and organize request handlers for incoming http requests. The incoming http requests come from an http server that must be created separately from Express.
Some code somewhere has to create an http server and then connect your Express app object with it. There are multiple ways to create the http server that you're going to use with Express. Your code using http.createServer(app) followed by server.listen() shows one such way to do that.
There are other ways to create the http server to use with Express. For example, the app.listen() method can create an http server and automatically bind the app object to it.
If you look at the source code for app.listen(), you see this:
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
All it does is create an http server with the app object as a listener and then call .listen() on that new server. This is essentially the same thing you're doing yourself with http.createServer(app) and then server.listen(...).
But, in all cases here some code somewhere is using http.createServer(...) to create a server object and then server.listen(port) to start it.