TLDR answer in 2023: the problem is that modern versions of Node starting with v17.0.0 default to IPv6 instead of IPv4 domain resolution, and you may be operating in an environment that doesn't support, restricts, or is misconfigured for IPv6 (most likely corporate or school).
Longer answer: If none of the answers in this thread are working for you in 2023 (there were 25 at the time I'm writing this, and none addressed WHY this is happening), and you are positive that your app is configured correctly, the problem is most likely due to Node defaulting to IPv6 instead of IPv4 when it's performing DNS resolution. This IPv6 default started in version 17.0.0 of Node -- you can read more about it here.
If you are working in a network environment that restricts or hasn't migrated to IPv6 support yet, this will break your app -- localhost
will resolve to ::1
(the IPv6 equivalent of 127.0.0.1
), and you'll get a connection refused error, like everyone is complaining about here. Try to visit http://[::1]:5000
in Chrome or whatever browser, and you will get the same error. But if http://127.0.0.1:5000
works, this is 100% your problem.
The fix is super easy. Just force Node to resolve with IPv4. There's many ways to do this depending on your setup, but you'll have to abandon the proxy
setting in package.json
, and rely on Node's own native dns
module. Given that this question is about a create-react-app
app, and my problem occurred in one too, I'll give an example of how I fixed it here. But you can do this with pretty much any Express server.
As mentioned, get rid of the proxy
setting in package.json
, and instead create a setupProxy.js
file in your /src
directory (like explained here). You'll also need to install the http-proxy-middleware
module via npm
. Then, you'll basically want to do your own IPv4-forced DNS lookup and create a proxy request using that IPv4 address. You can do this with the family
parameter set to 4
in the dns.lookup
method, as shown here:
const dns = require("dns");
const { createProxyMiddleWare } = require("http-proxy-middleware");
const targetHost = "localhost";
const targetPort = 5000;
const port = 3000;
module.exports = function (app) {
dns.lookup(targetHost, { family: 4 }, (err, address) => {
if (err) {
console.error('DNS lookup failed');
return;
}
const proxy = createProxyMiddleware("/api", {
target: `http://${address}:${targetPort}`,
changeOrigin: true,
});
app.use("/api", proxy);
});
};
Now if you hit http://localhost:3000/api/yourendpoint
, this will redirect to http://127.0.0.1:5000
instead of http://[::1]:5000
. Note that this is a very basic example and leaves out error handling and ignores the fact that dns lookup is an asynchronous operation, but overall this should work if you're in an environment where IPv6 doesn't work properly.