---
title: Switching from nvm to nodejs_version in DDEV
date: 2026-07-12T14:18:00+01:00
author: John Henry Donovan
canonical_url: "https://johnhenry.ie/blog/2026/07/switching-from-nvm-to-nodejs-version-in-ddev"
section: Blog
---
Categories 

Categories

[](https://johnhenry.ie/blog/category/web-development)

### Share this link via

Or copy link

Copy

12th July, 2026

# Switching from Nvm to Nodejs\_​version in DDEV

I opened up WSL2 this morning and ran a `ddev` command the way I always do, and there was a tip of the day sitting there that changed how I set my projects up

> TIP OF THE DAY: These days it makes more sense to use nodejs\_version with a full version than using ddev nvm, which is more complex and error-prone. You can now set nodejs\_version to any major or minor version, not just currently supported major versions. So nodejs\_version: 21.2.0 or nodejs\_version: 6 will work.

That’s a small enough message, but it does away with a workaround I’ve been carrying in half my projects for years. So I sat down for the hour and took `nvm` out of the whole lot of them, and here’s how it went.

## Why we were using nvm at all

For a long time, `nodejs_version` in `.ddev/config.yaml` would only take a short list of the currently supported major versions. That’s grand until you’re minding an older site whose front-end tooling is pinned to Node 14, or some old npm lockfile that only behaves with the npm version that came with one particular minor release. The major-only setting couldn’t say that, so people reached for the [`ddev-nvm` add-on](https://github.com/ddev/ddev-nvm) or wrote their own post-start hooks to get the exact version they were after.

It worked, but it was fiddly. The heart of the problem is that `nvm` is a shell function, not a proper standalone binary, so it can’t change the environment inside the DDEV container the way you’d expect it to. What that means in practice is that `ddev nvm use <version>` doesn’t hold. It looks like it took, and then the next `ddev npm` call quietly goes back to the old version. You end up going around in circles with `ddev nvm alias default <version>` and post-start hooks just to make it stick from the one command to the next. And anyone new on the team had to learn that same carry-on.

## What actually changed

The main thing from that tip is this: `nodejs_version` now takes any major, minor or full patch version, not only the majors DDEV officially tracks. Underneath, DDEV uses [`n`](https://www.npmjs.com/package/n) to install whatever you ask it for, and it understands the same version specifiers `n` does. Having a read through the DDEV issue queue, one of the maintainers lays out the full range of what’s allowed:

```yaml
nodejs_version: "21.2.0"   # an exact, pinned version
nodejs_version: "v20"      # the latest 20.x
nodejs_version: "6"        # yes, even an ancient major
nodejs_version: "latest"   # whatever the newest release happens to be
```

.ddev/config.yaml

That one line covers just about every reason I ever put the nvm add-on in. It’s plain to read, it lives in version control, and it does the same thing for me, for CI, and for anyone who clones the repo. No `nvm install` step in a hook, and no surprises depending on the shell session you happen to be in.

## Moving a project over

Here’s the switch, start to finish. It took me about two minutes a project.

**1. Take out the old machinery.** If you had the add-on in, remove it:

```bash
ddev add-on remove nvm
```

If you were using post-start hooks to install Node, take those lines out of `.ddev/config.yaml`. They’d usually look something like this:

```yaml
hooks:
  post-start:
    - exec-host: ddev nvm install 14.21.3 && ddev nvm alias default 14.21.3
```

**2. Set the version you actually want.** Either put it straight into the config:

```yaml
nodejs_version: "14.21.3"
```

Or let DDEV write it for you:

```bash
ddev config --nodejs-version=14.21.3
```

**3. Restart and check it.**

```bash
ddev restart
ddev exec node -v
```

That last command should print exactly what you asked for. One thing worth knowing: if the version won’t budge, a cached build is often the reason. A `ddev debug refresh` or a `ddev restart --no-cache` will clear it out.

**4. Commit** `<strong>.ddev/</strong>`**.** However you set the version, commit the change so the whole team gets it without having to think about it.

## Two extra bits I was glad to find

While I was in there, I came across a couple of things I wish I’d known a long time ago.

If you already keep your Node version in a file, a `.nvmrc`, a `.node-version`, or the `engines.node` field in `package.json`, you can point DDEV at it instead of writing the number out twice:

```yaml
nodejs_version: auto
```

With `auto`, DDEV reads the version from `.n-node-version`, `.node-version`, `.nvmrc`, then `engines.node`, in that order (`nodejs_version: engine` locks it to `engines.node` only). It does away with the old mess where the Node version drifts apart across production, staging, CI and local, all because it’s written down in four separate config files. Put it in the one file, point every environment at that file, and the container and every non-DDEV tool are finally reading off the same page.

And if the reason you were wrestling with nvm was really about getting a newer `yarn` or `pnpm`, you can skip the whole lot of it with corepack:

```bash
ddev config --corepack-enable && ddev restart
```

## But I still use nvm on Ubuntu, does that break anything?

No, it doesn’t. And this is the bit that caught me out for a second, so it’s worth saying plainly.

The nvm on your Ubuntu (or WSL2) host and the Node inside DDEV are two separate installations in two separate places, and neither one knows the other is there. Host nvm looks after the `node` and `npm` you get when you type `node` at your Ubuntu prompt. `nodejs_version` looks after the `node` and `npm` inside the container, the ones you reach with `ddev npm`, `ddev exec node`, or after `ddev ssh`. That tip that started all this was only ever about `ddev nvm`, which is nvm running inside the container. Your host nvm isn’t touched at all, so carry on using it exactly as you do now.

The one thing to be clear about isn’t breakage, it’s consistency. For a given project, decide where you’re running your Node tooling and stick with it.

- Running `npm install` / `npm run build` straight in your Ubuntu shell uses host nvm’s Node, and the container’s `nodejs_version` has nothing to do with that work.
- Running `ddev npm install` / `ddev npm run build` uses the container’s Node, the one set by `nodejs_version`.

Where you can run into bother is mixing the two on the one project. A native module built against host Node 20 landing in a `node_modules` that the container’s Node 18 then tries to load, say, or lockfiles written by different npm versions. That’s not a DDEV quirk, it’s just what happens with any two Node environments that don’t match. So don’t build half of it in the one place and half in the other.

If you want the two of them to agree, there’s a handy way to do it. Keep your `.nvmrc` for host nvm, then set `nodejs_version: auto` in DDEV so it reads that same file. Host and container land on the one version, out of the one source.

## Was it worth it?

For me, yes, no question about it. The nvm approach was a clever way around a real limitation, but a way around is all it ever was, and it brought complexity into onboarding, into keeping CI in line, and into my own habits. Now the Node version is the one honest line in a YAML file that means the same thing everywhere.

If you’re still carrying `ddev-nvm` or post-start Node hooks in your projects, the only real reason left to keep them is if you genuinely need more than one Node version inside the one container while it’s running, and the add-on is still there for you if you do. For everyone else, take the workaround out, set `nodejs_version`, restart, and you’re done.

For once a tip of the day meant taking code out instead of putting more in, and I was glad of it.

More like this

[![A logo featuring interconnected blue hexagonal lines on the left and the stylized text “DDeEV” in black and blue on the right. The design is minimalistic with a focus on geometric shapes and clean lines.](https://assets.johnhenry.ie/transforms/2a2ed2821aeabed46a41f2462bc21676/13980/ddev_logo_348beeca2483f5cd26f49a2e1211a0cc.jpg)](https://johnhenry.ie/blog/2022/12/16-reasons-ddev-will-be-your-new-favorite-development-environment)

8 Dec 2022

[### 16 Reasons DDEV Will Be Your New Favorite Development Environment](https://johnhenry.ie/blog/2022/12/16-reasons-ddev-will-be-your-new-favorite-development-environment)DDEV is a container-based local development environment. Randy Fay, the creator, gives a few reasons to try it. Not…

[Read post ](https://johnhenry.ie/blog/2022/12/16-reasons-ddev-will-be-your-new-favorite-development-environment)

[![A logo featuring interconnected blue hexagonal lines on the left and the stylized text “DDeEV” in black and blue on the right. The design is minimalistic with a focus on geometric shapes and clean lines.](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAASCAIAAAC1qksFAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACkElEQVQ4jZWU647cNgyFvyPJ9s60G/Q5ir7/WwVIsjtjW+KlPzyzyE4nBUIQsECRPDo0Senvf0jIwB0fjE5f2X5wMZzfkHrXAgIBIBp1ugFQACKpTn2hvv8GgH7KXkD6uGksr5DEnUHpqJEFd/X1/9Pm8ZlhmqiNUpBEQkCQAdnK+QuZRBCODbWdMkmVhNG1PmGRH6ep8PIn00KtlIKOSgTphCuN9FZPXwDCcZMN6iw1UYjU2Fm/6lfZT+c8vTIv1IlakCCVQdhdywFwK5HMsK7SpKJEbix/aP5Kf1aclxPnv3g5MS1ZK6XoQA8nDB+KgkOo1eV8MFAdlCqkTLlrdE0Ly1n9+shAcHrN5cR8YpqpFRUAgjB5QWBJBtDK/EIm4VK5ZzdaV5vUJrUFrg/PZ55zWphmpjnbAXAQCH0cipOVjKY6kclRlgjVqtpUmkpVqZT25B+0WbVlbZSqWimVUsgkgUIUqaACQmoHuCRJSB8XSIf54fUCSsm7f3LzRJDSfcZuYZmNDDIzg0wd/ZpJxs0e8YTBLST5UALybgxlZgQRRLS0cZsDH/jADbd0k7vc5CP5j1hPN9xwz2JwjG6SrsPoJnfccWvR96O9ZIPRNXaNXaPLumzQ1ycM9s7Ys82UCkmNG0AEYbLBTTvem2+XO4BhXX1XX9U39Y191fZ0Csj1jdIAwrMcc3ADOFLLNsaK783Xt3uJTNY5ALYL21XrG8nzSd5WUIZhy20LAREKwwe2M1bGhtP88v2+7AwbGjv7pu3C9TvvPx576BPGlbGynDlqJcjEDe/YxkglQIvrt1vbuGOD0dlX1nfeHrfQEyRPrhe4UEGQkCg++TTWt0/ruu/sVy7fMJ70z6/kp537EPUvx9rwPePypIYAAAAASUVORK5CYII=)](https://johnhenry.ie/blog/2022/10/ddev-v1-21-2-is-out)

11 Oct 2022

[### DDEV v1.21.2 Is Out](https://johnhenry.ie/blog/2022/10/ddev-v1-21-2-is-out)DDEV v1.21.2 is out. PHP8.2, Craft CMS explicit support, TYPO3 v12, global project\_tld, and loads of other improvements…

[Read post ](https://johnhenry.ie/blog/2022/10/ddev-v1-21-2-is-out)
