DEV Community

Stephen Akugbe
Stephen Akugbe

Posted on

Why NestJS Hot Reload Does Not Work in Docker and How to Fix It Properly

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.

  1. How files get into the container
  2. How NestJS is started
  3. 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.

  1. Process restart using the Nest CLI watcher
  2. 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.

  1. module.hot in main.ts
  2. webpack: true in nest cli config
  3. 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:

  1. Your application startup time is slow
  2. You want instant reload without restarting the process
  3. 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)