wingetnodejsjavascripttutorialsetup

Setting Up Node.js, pnpm, and Bun with winget (2026)

Modern JavaScript dev stack on Windows in 10 minutes. Node.js LTS, fnm for version management, pnpm, Bun, VS Code — all via winget.

· 5 min read · updated May 29, 2026
Setting Up Node.js, pnpm, and Bun with winget (2026)

The modern Windows JavaScript stack is fast, snappy, and entirely scriptable. Here's how to get from clean Windows to a working Node + pnpm + Bun setup in 10 minutes using winget.

TL;DR — install everything

Open Terminal as Administrator:

winget install --id Schniz.fnm -e --accept-package-agreements --accept-source-agreements
winget install --id pnpm.pnpm -e
winget install --id Oven-sh.Bun -e
winget install --id Microsoft.VisualStudioCode -e
winget install --id Git.Git -e
winget install --id Microsoft.WindowsTerminal -e
winget install --id Microsoft.PowerShell -e
winget install --id GitHub.cli -e

Then install Node via fnm:

fnm install --lts
fnm use lts-latest

You're ready to ship.

Step 1 — fnm or direct Node?

Two approaches:

Direct install (simpler, single Node version):

winget install --id OpenJS.NodeJS.LTS -e

Good if you only work on one Node version.

fnm (recommended for working on multiple projects):

winget install --id Schniz.fnm -e

fnm is a fast Node version manager. It reads .nvmrc or .node-version files and auto-switches Node version when you cd into a project.

This guide uses fnm. If you prefer direct install, skip Step 2.

Step 2 — Configure fnm in your shell

After install, add fnm to your PowerShell profile:

notepad $PROFILE

Paste:

# fnm
fnm env --use-on-cd | Out-String | Invoke-Expression

Save, restart Terminal. Now cd into a project with a .nvmrc and fnm switches Node version automatically.

Install Node versions

fnm install --lts
fnm install 22
fnm install 20

fnm list
# * v22.10.0 (default)
#   v20.18.0 (lts-latest)

Switch:

fnm use 22
fnm default 22

Step 3 — pnpm

winget install --id pnpm.pnpm -e

pnpm is faster than npm, uses 80% less disk space (symlinked store), and has stricter dependency resolution. Verify:

pnpm --version

Make it the default for new projects:

pnpm config set store-dir ~/.pnpm-store

Step 4 — Bun

winget install --id Oven-sh.Bun -e

Bun is an all-in-one runtime + package manager + bundler + test runner, written in Zig. Replaces Node + npm + webpack + jest for many workflows.

bun --version
bun init     # creates a starter project in current dir
bun add react
bun run dev

For Next.js / Vite / SvelteKit etc., Bun works as a drop-in npm replacement:

bun install   # like npm install
bun run dev   # like npm run dev

For server-side, Bun's runtime is 4× faster than Node for hot paths:

bun server.ts

Step 5 — VS Code + extensions

winget install --id Microsoft.VisualStudioCode -e

Install JS/TS essentials:

code --install-extension dbaeumer.vscode-eslint
code --install-extension esbenp.prettier-vscode
code --install-extension biomejs.biome
code --install-extension yoavbls.pretty-ts-errors
code --install-extension bradlc.vscode-tailwindcss

Biome is a modern alternative to ESLint + Prettier — a single tool, 10× faster.

VS Code settings for JS/TS

Ctrl+, → Open JSON:

{
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": { "source.fixAll": "explicit" },
  "typescript.tsserver.experimental.enableProjectDiagnostics": true,
  "typescript.preferences.preferTypeOnlyAutoImports": true
}

Step 6 — Git + GitHub CLI

winget install --id Git.Git -e
winget install --id GitHub.cli -e
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase true

gh auth login

A real example: Next.js + pnpm

cd ~/projects
mkdir my-app
cd my-app

# Use Node 22
fnm use 22

# Bootstrap Next.js with pnpm
pnpm create next-app@latest . --typescript --tailwind --eslint --app

pnpm dev

Open http://localhost:3000.

A real example: Bun + Hono API

cd ~/projects
mkdir my-api
cd my-api

bun init   # accept defaults
bun add hono

# Replace index.ts with:
@"
import { Hono } from 'hono'

const app = new Hono()
app.get('/', (c) => c.json({ hello: 'world' }))

export default app
"@ | Out-File -Encoding utf8 src/index.ts

bun --hot src/index.ts

Open http://localhost:3000.

Lockfile, ".nvmrc", and team standardisation

If you're on a team, commit a .nvmrc:

22

…and an .npmrc to pin pnpm:

engine-strict=true

In package.json:

{
  "engines": {
    "node": ">=22.0.0",
    "pnpm": ">=9.0.0"
  },
  "packageManager": "pnpm@9.12.0"
}

Now anyone cloning the repo gets the right Node + pnpm via fnm + Corepack automatically.

Pin runtimes with winget

If you've direct-installed Node (not via fnm), pin the LTS line:

winget pin add --id OpenJS.NodeJS.LTS --version "22.*"

Now winget upgrade --all won't accidentally bump you to Node 24. See winget pin guide.

Save your setup

winget export -o nodejs-dev.json --include-versions

Future you, on a new machine:

winget import -i nodejs-dev.json

Common pitfalls

Multiple Node versions confused — use fnm. Stop installing Node directly.

pnpm not found after install — close + reopen Terminal. PATH refresh.

Corepack vs pnpm-installed-via-winget — pick one. Either:

corepack enable
# Now `pnpm` comes from package.json's packageManager field

Or:

winget install --id pnpm.pnpm -e
# Now `pnpm` comes from winget

Both works fine; just don't mix.

Bun on Windows fails to install some packages — Bun on Windows is still maturing. For complex projects with native dependencies, fall back to pnpm. Bun for greenfield, pnpm for legacy.

More dev bundles
winget.tech has the Developer bundle pre-built with VS Code, Git, Node, Docker, Terminal.
Developer Bundle →

What's next?

Continue reading