Node.js

How Anvil runs Next.js, Nuxt, Vite and other Node.js projects, installs Node.js versions and package managers, and picks a version per project.

What Anvil detects

TypeDetected byStarted with
Next.jsnext in package.jsonnpm run dev -- --hostname 127.0.0.1
Nuxtnuxt in package.jsonnpm run dev
Vitevite or vite-plus in package.jsonnpm run dev -- --port $PORT --strictPort --host 127.0.0.1
Node.jspackage.jsonnpm run dev, or npm run start without a dev script

PHP, Rust, Go, .NET and Django projects are recognized first, as are FastAPI and Flask projects with a main.py, app.py, wsgi.py or app/main.py. A Laravel application with a package.json stays Laravel; see the detection table.

Anvil starts the dev server on a private port passed in $PORT and proxies <name>.test (and <name>.localhost) to it. Vite gets the port on its command line, Next.js reads $PORT; other servers must listen on $PORT, or set their fixed port: anvil app port myapp 3000, or Port in the Settings tab.

Installing Node.js

Settings › Languages › Node.js › Install, or:

anvil runtime list
anvil runtime install node 24

Every major from 18 up that nodejs.org lists. Anvil installs the newest release of the major, checked against its SHASUMS256.txt, into ~/.anvil/runtimes/node/<major>.

Package managers

The Package managers list in Settings › Languages › Node.js shows which npm, pnpm, yarn and bun your applications and your terminal get, and from where. Install adds a missing one:

  • pnpm and yarn: installed with the newest Anvil Node.js's npm into ~/.anvil/runtimes/pm (needs a Node.js installed).
  • bun: official release, checked against its SHA-256, into ~/.anvil/runtimes/bun.

Processes Anvil runs, and scripts run via Anvil's npm/npx, get Anvil's copies first. Typed in a terminal, pnpm, yarn and bun are whatever your own PATH finds.

Choosing the version

There is no default version. Your pin wins: anvil app runtime myapp 22, or Node.js version in the Settings tab. Otherwise the first of these that names an installed version:

  1. node in .anvil.toml (a major):

    node = "22"

    If it isn't installed, the Overview offers to install it.

  2. .nvmrc, then .node-version. Only the major counts (v22.11.0 and 22 both mean 22); lts/iron matches nothing.

  3. The newest installed version.

anvil app runtime myapp without a version goes back to automatic.

The pin lives in Anvil's settings and applies to the dev server and to node/npm/npx in a terminal inside the folder. Dev processes and one-off scripts ignore it and use the list above; to give them a version, set it in .anvil.toml or .nvmrc.

Running an application

Before a command that runs a package script or binary (npm run, pnpm, yarn, bun run, npx and the like), Anvil installs dependencies if node_modules is missing:

Lock fileInstall command
pnpm-lock.yamlpnpm install --config.strict-dep-builds=false
yarn.lockyarn install
bun.lockb or bun.lockbun install
nonenpm install

pnpm and yarn come through Corepack when not on the application's PATH. Output goes to the application's log; a failed install stops the start.

The dev server doesn't start on its own: Start in the Dev tab, or anvil app start myapp while the desktop app is open (this also starts dev processes marked Dev start). To start it with Anvil, turn on Start with Anvil in Settings or run anvil app autostart myapp true (off by default; with the CLI alone, restart anvil start). It runs until stopped or Anvil quits; while stopped, <name>.test shows a "not running" page.

Start command and port: Start command and Port in Settings, or:

anvil app command myapp 'pnpm dev --port $PORT'
anvil app port myapp 41500
anvil app command myapp      # default command
anvil app port myapp         # automatic port

The automatic port is derived from the name, in 41000–44999, moving up on collision.

Dev server environment:

VariableValue
PORTThe application's private port
HOST, HOSTNAME127.0.0.1
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS.test (the domain suffix)
npm_config_cache~/.anvil/cache/npm
npm_package_config_node_gyp_devdir~/.anvil/cache/node-gyp
COREPACK_HOME~/.anvil/cache/corepack
XDG_CACHE_HOME, XDG_STATE_HOME~/.anvil/cache/xdg and ~/.anvil/cache/xdg-state, unless you set them
NEXT_TELEMETRY_DISABLED, NUXT_TELEMETRY_DISABLED1
PATHThe chosen Node.js, then Anvil's pnpm, yarn and bun, then the PATH Anvil started with and your login shell's

Next.js addresses

Next.js dev is only interactive at localhost and at allowedDevOrigins, so Anvil opens <name>.localhost until the config lists the domain suffix. Use <name>.test in the Overview adds allowedDevOrigins: ['**.test'] to next.config (or creates next.config.mjs). Anvil edits only a config with one plain top-level object; otherwise it shows the line to add. The dev server listens on 127.0.0.1 only.

In your terminal

Setup puts node, npm and npx on your PATH, running Anvil's Node.js:

  • Inside a Node.js application's folder: the application's version, pin included.
  • Elsewhere: the version .anvil.toml, .nvmrc or .node-version names, else the newest. Inside another application (e.g. Laravel) these files are read from its folder; outside any application, from the current folder.

They get the same cache variables and PATH as applications. anvil which node prints which node runs in the current folder.

Caches and files

Node.js tool caches go to ~/.anvil/cache: npm, node-gyp headers, Corepack, and tools following XDG_CACHE_HOME/XDG_STATE_HOME (giget, yarn, pnpm's state). ~/.npm is untouched. An existing shared store, like pnpm's in ~/Library/pnpm, stays put; moving it would make pnpm reject existing node_modules.

In the project, Anvil writes only node_modules (via the install above) and next.config (via Use <name>.test). node_modules and .next show as rebuildable in Storage.

New applications

anvil new next shop --ts --tailwind --pm pnpm --node 24
anvil new nuxt docs
anvil new vite ui --framework vue --no-ts
anvil new node api

A Next.js project with the CLI alone:

  1. anvil runtime install node 24, if needed.
  2. anvil new next shop. Created in your first parked folder (or --in); anvil start needn't be running.
  3. anvil app autostart shop true.
  4. Run anvil start, or restart it (Ctrl-C) if running.
  5. Open http://shop.localhost. For shop.test, add allowedDevOrigins: ['**.test'] to next.config (or Use shop.test in the app).

Or New… (⌘N) in the app, under JavaScript.

TemplateCreated withOptions
nextcreate-next-app@latest with the App Router--ts/--no-ts, --tailwind/--no-tailwind, --pm npm|pnpm|bun, --node
nuxtnuxi@latest init with the minimal template--pm, --node
vitecreate-vite@latest--framework react|vue|svelte|vanilla, --ts/--no-ts, --pm, --node
nodea package.json and a server.js that listens on $PORT (dev runs node --watch server.js)--node

--node takes an installed major; newest otherwise. Generators run through Anvil's npx, then dependencies install with the chosen package manager. All templates take --git/--no-git and --https/--no-https; see New applications.

Differences from production

  • The dev server runs, not a build. Next.js and Vite bind 127.0.0.1; others get HOST/HOSTNAME = 127.0.0.1, which most follow.
  • Next.js and Nuxt telemetry is off.
  • node-gyp takes Node.js headers from ~/.anvil/cache/node-gyp.

Removing a version

Hover the version in Settings › Languages › Node.js and click Uninstall, or anvil runtime uninstall node 22. This deletes ~/.anvil/runtimes/node/22; unpinned applications pick again on next start.

Anvil refuses while applications are pinned to it ("web uses Node.js 22 — switch it to another version first"); Settings then shows Pinned by with their names instead of Uninstall. Unpin: set Node.js version to Automatic or another version, or run anvil app runtime web without a version (with only one version installed the field is disabled; use the command). A version only .anvil.toml, .nvmrc or .node-version asks for doesn't block. pnpm and yarn installed from Settings stay; remove them with Uninstall in the Package managers list.

On this page