A few helpful articles have been written that discuss getting services from different Docker Compose files to communicate with one another during local development.
These solutions leverage Docker networking features, which makes sense since most of the use cases involve server-side network requests.
If the service is purely frontend, this isn't an issue at all. The browser would just use the local host machine's network to perform the requests. No need to go through Docker networking.
But NextJS makes things quite complicated. It is able to perform both server-side (SSR & SSG) and client-side (CSR) requests. It means that if we follow the articles above, server-side will work well, but client-side requests would break.
Allow me to demonstrate.
Let's say we have a NextJS app named
frontend.docker-compose.yml. And we provide it with an environment variable
API_URL=http://path-to-api for backend requests.
# frontend.docker-compose.yml services: next-client: environment: API_URL: http://path-to-api
We also have an API service named
api-gateway exposing port
backend.docker-compose.yml. That service will be available on the local machine network via localhost:3000.
next-client service's client-side (browser) requests will be totally fine with this (
# backend.docker-compose.yml services: api-gateway: expose: - 3000
But due to reasons already mentioned by the articles above, all server-side
next-client requests will break.
Now, if we follow the articles, we would need to set
next-client. Great, server-side requests are working now:
# backend.docker-compose.yml services: api-gateway: expose: - 3000 network: - backend-gateway networks: - backend-gateway
# frontend.docker-compose.yml services: next-client: environment: API_URL: http://api-gateway:3000 networks: - backend-project_api-gateway networks: backend-project_api-gateway: external: true
But wait, the client-side requests are now failing! That totally makes sense since the local host machine doesn't recognize
After fiddling around for hours, I found that the answer was actually so simple, add
api-gateway as a hostname alias inside your machine's hosts file. Here's how to do it in Linux:
127.0.0.1 localhost api-gateway
Voila! NextJS is happy!
What this does is to allow the host machine to route
http://api-gateway requests to all localhost network handlers, one of which is our Docker
api-gateway service! For client-side requests,
http://api-gateway:3000 is transformed to
http://127.0.0.1:3000 (localhost), and since
api-gateway is exposed at port
3000, it accepts the request.
NextJS server-side requests, meanwhile, are still exclusively handled from within Docker's Network. The local machine network are not aware of them.
Effectively, in NextJS point of view, both server- & client-side requests go through the same network. But with some juggling, the reality is they are handled by separate networks, Docker and local machine networks, respectively. But NextJS doesn't need to know about that anymore, does it? 😎