If you need to add npm to the WordPress Docker image, don’t bother with the old Stack Overflow answers—they use apt-get and it’s all broken now. The official image moved to Debian Bookworm and PHP 8, so the old way just throws errors. Here’s the damn fix.

Why the old way fails
The top answer on Stack Overflow tells you to run apt-get install nodejs npm. That was fine back in 2017 when the image was based on a different Debian version. Now, the WordPress image is on Debian Bookworm, and the default repos don’t have the right Node.js packages. You’ll get package not found or dependency hell. It’s a pain in the ass.
The actual fix: use NodeSource
You need to pull Node.js from NodeSource, not the Debian repos. I’d just use a custom Dockerfile like this—it’s less to undo later and works on the current WordPress image.
FROM wordpress:latest
# Install Node.js 20.x from NodeSource
RUN apt-get update && apt-get install -y curl &&
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - &&
apt-get install -y nodejs &&
apt-get clean
That gives you Node.js and npm in one shot. Build it and you’re done. No more stupid errors.

If you need a specific Node version
Just change the setup script version. setup_20.x, setup_22.x and setup_24.x are all live right now; swap the number and you’re done. Check NodeSource on GitHub for what they currently support. Honestly, the docs are a mess on this one, but the scripts themselves are solid.
One thing worth adding while you’re in there — clean up after apt, or you’re carrying the package lists around in every layer forever:
RUN apt-get update && apt-get install -y curl &&
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - &&
apt-get install -y nodejs &&
apt-get clean && rm -rf /var/lib/apt/lists/*
The better question: do you need npm in there at all?
Probably not. npm is a build tool. If you’re using it for @wordpress/scripts to compile blocks or theme assets, that compile happens once, and what WordPress actually serves is the built JS and CSS sitting in your theme folder. Baking Node into the runtime image means every container you ever start drags a toolchain around for a job that finished before the image was even pushed.
Two ways out. Build the assets on your own machine and bind-mount or COPY the theme in — the WordPress image stays stock, and stock means it upgrades cleanly. Or, if you want it reproducible, use a multi-stage build so the toolchain never reaches the final image:
FROM node:22 AS assets
WORKDIR /theme
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM wordpress:latest
COPY --from=assets /theme/build /var/www/html/wp-content/themes/mytheme/build
Same result, and the image you actually run is the official one plus your files. Nothing to patch when Node has its next CVE.
The single-image version at the top of this post is still the right answer if you’re doing theme work inside the container and want a shell where npm run start just works. That’s a real use case. Just don’t ship it to production and then wonder why the image is 400MB heavier than it needs to be.
My take
This is your personal project—keep it simple. Don’t overthink it, just use the Dockerfile above and move on. It is not worth hours of anyone’s time. And if you’re doing a bunch of theme development, you might also hit Node Sass version issues—I wrote about that here.
If you’d rather pay for this
Step back a second before you bake npm into a production image, because there is a decent argument you should not. A runtime image carrying a full Node toolchain is bigger, has more to patch, and gives an attacker a build environment if they ever get inside it. The alternative costs nothing: build your assets somewhere else and copy the output in — a multi-stage Dockerfile does this for free, and any CI service does it on a free tier for a project this size.
If the reason you are doing this is that a theme or plugin needs a build step on a host you do not control, that is the thing worth paying to remove. Managed WordPress hosting with a real deployment pipeline — Git push, build, atomic deploy — sits in the tens of dollars a month and takes the whole problem away rather than containerising it.
Bake npm in when it is a development image and you want the toolchain at hand. For anything serving traffic, build outside and ship the artifact.
Part of shared hosting, SSL and WordPress — the WordPress section.