If you are running NestJS inside Docker and your code changes are not reflecting, you are not alone. This is one of the most common pain points developers hit when combining NestJS, Docker, and macOS or Windows.
You save a file.
Nothing happens.
You rebuild the container.
Still confused.
Sidenote: I have actually fixed this exact problem before on another project. But when I hit it again on a new NestJS setup, I realized I could not remember all the details. That was the moment I decided to document it properly this time.
At some point, you install webpack because someone on the internet said it fixes the issue.
This article explains what is really going on, why Docker behaves this way, when webpack is actually needed, and what the correct setup looks like for NestJS development.
The core misunderstanding
Docker does not watch your files.
Docker only sees what exists inside the container. Whether changes reflect or not depends entirely on how files get into the container and how NestJS is running.
There are two very different worlds that often get mixed up.
- Development mode
- Production mode
If you confuse the two, hot reload will never work.
How NestJS hot reload works without Docker
When you run NestJS locally using
npm run start:dev
The Nest CLI uses a file watcher. When a file changes, the process restarts automatically.
No Webpack is involved here.
No HMR.
Just process a restart.
This works because your filesystem events are available directly to Node.
What changes when you introduce Docker
Once NestJS runs inside a container, file watching depends on three things.
- How files get into the container
- How NestJS is started
- Whether filesystem events propagate correctly
If any of these is wrong, hot reload breaks.
The only setup that works reliably for development
For NestJS changes to reflect instantly inside Docker, all of the following must be true.
Your source code is mounted into the container using volumes
NestJS runs in watch mode using start dev
File watching works inside Docker
If even one is missing, you will be rebuilding images unnecessarily.
Volumes are non-negotiable in development
If your Dockerfile copies files like this
COPY . .
Then your container has a snapshot of your code. Docker has no idea when you edit files locally.
That setup is correct for production but wrong for development.
In development, your compose file must mount the project into the container.
Example conceptually:
Local files
Shared into the container
Changes appear instantly
This is exactly what your compose file already does.
.:/usr/src/app
That line is the backbone of hot reload.
Why node_modules must be excluded
This line is subtle but important.
/usr/src/app/node_modules
It prevents your local node_modules from overwriting the container dependencies. Without it, you get native module issues and random crashes.
This is a best practice, and you got it right.
start dev is not optional
NestJS will only watch files if you explicitly run it in watch mode.
This means your command must be
npm run start:dev
and not
node dist/main.js
or
nest start
The moment you run compiled JavaScript, hot reload is gone. That is expected behavior.
The macOS and Windows file watching problem
Even with volumes and start dev, many developers still see no reload.
This is not a NestJS bug.
On macOS and Windows, Docker Desktop runs Linux containers inside a virtual machine. Native filesystem events often do not propagate correctly into the container.
That is why NestJS does not detect changes.
The fix is polling.
These environment variables force Node-based watchers to actively check for changes instead of relying on filesystem events.
CHOKIDAR_USEPOLLING=true
WATCHPACK_POLLING=true
This is not a hack. It is a known workaround and widely used.
Once enabled, NestJS reliably restarts when files change.
The webpack confusion explained
This is where most people go wrong.
NestJS supports two different reload strategies.
- Process restart using the Nest CLI watcher
- Hot Module Replacement using webpack
Webpack is only required for HMR.
If you never enabled HMR, you don't need Webpack at all.
So why do people install it?
Because they accidentally enable HMR.
If you see any of these, Webpack becomes mandatory.
-
module.hotin main.ts -
webpack: truein nest cli config - Custom HMR setup
At that point, NestJS expects Webpack and Webpack CLI to exist.
Many developers install Webpack, thinking it fixes Docker reload issues, when in reality, polling was the missing piece.
When webpack actually makes sense
Webpack HMR can be useful if:
- Your application startup time is slow
- You want instant reload without restarting the process
- You know you enabled HMR intentionally
But it adds complexity and is not required for most backend APIs.
For many projects, a simple restart on change is stable and good enough.
Development versus production mental model
This simple rule will save you hours.
In development:
- Use volumes
- Run start dev
- Enable polling
- Never rebuild
In production:
- Do not use volumes
- Copy files during build
- Run compiled JavaScript
- Rebuild on every change
If you mix these two worlds, things break.
Final thoughts:
- Docker is not broken.
- NestJS is not broken.
- Hot reload is not magic.
Once you understand how files enter the container and how NestJS watches them, everything becomes predictable.
If you ever find yourself rebuilding Docker images just to see a console log update, something in your setup is wrong.
And if you installed Webpack just to make file watching work, you probably did not need it.
If this article saved you time, chances are it will save someone else hours of frustration too.
Top comments (0)