vlt / docs

  • PricingBenchmarks (opens in new window)Community (opens in new window)Feedback
  • Overview
  • From npm
  • From yarn
  • From pnpm
  • Quick Start
  • Command Mapping
  • Shorthand Script Execution
  • Configuration
  • .npmrc + pnpm-workspace.yaml → vlt.json
  • Registry Configuration
  • Scoped Registries
  • Named Registry Aliases
  • Authentication
  • CI Environments
  • Lockfile
  • Install Script Protection
  • pnpm onlyBuiltDependencies vs vlt build --target
  • Workspaces
  • pnpm
  • vlt
  • Workspace Commands
  • Catalogs
  • Overrides → Graph Modifiers
  • node_modules Layout
  • Features Not in vlt
  • Migration Checklist
  1. Client
  2. /
  3. Migration
  4. /
  5. From pnpm

Migrating from pnpm to vlt

Quick Start

Terminal
# Install vlt globally
$ npm install -g vlt

# Configure a registry -- vlt has no default

$ vlt config set registry=https://registry.npmjs.org/

# In your existing project, run:

$ vlt install $ vlt build

Unlike pnpm, vlt has no default registry — commands that resolve or fetch packages fail with a config error until one is set. The snippet above points it at the public npm registry; if you have a vlt.io account, run vlt setup instead to configure your account's registry aliases. See Registries.

vlt reads your existing package.json files and resolves dependencies. The pnpm-lock.yaml file is not migrated — vlt performs a fresh resolution and creates vlt-lock.json.


Command Mapping

pnpmvltNotes
pnpm installvlt installDoes not run lifecycle scripts
pnpm add <pkg>vlt install <pkg>
pnpm add -D <pkg>vlt install -D <pkg>
pnpm remove <pkg>vlt uninstall <pkg>
pnpm run <script>vlt run <script>
pnpm <script>vlt run <script>See fallback-command
pnpm dlx <pkg>vlx <pkg>Run remote packages
pnpm exec <cmd>vlt exec <cmd>
pnpm initvlt init
pnpm packvlt pack
pnpm publishvlt publish
pnpm loginvlt login
pnpm whoamivlt whoami
pnpm listvlt list
pnpm why <pkg>vlt query '#<pkg>'DSS query; see Selectors
pnpm install --frozen-lockfilevlt install --frozen-lockfile
pnpm auditvlt query ':malware'More powerful; see Security
pnpm config set <key> <val>vlt config set <key>=<val>

Shorthand Script Execution

pnpm lets you run scripts without run (e.g., pnpm build). vlt supports this via the fallback-command config:

Terminal
$ vlt config set fallback-command=run-exec

After setting this, vlt build will first check for a vlt command named build, and if none matches, look for a package.json script.


Configuration

.npmrc + pnpm-workspace.yaml → vlt.json

pnpm reads registry config from .npmrc and workspace config from pnpm-workspace.yaml. vlt consolidates everything into vlt.json.

pnpm configuration:

.npmrc
# .npmrc (pnpm)
registry=https://registry.internal.company.com/
@mycompany:registry=https://npm.mycompany.com/
auto-install-peers=true
pnpm-workspace.yaml
# pnpm-workspace.yaml
packages:
- "packages/*"
- "apps/*"

vlt equivalent (single file):

vlt.json
{
  "registry": "https://registry.internal.company.com/",
  "scoped-registries": {
    "@mycompany": "https://npm.mycompany.com/"
  },
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}

Registry Configuration

Scoped Registries

pnpm's scoped registries (from .npmrc) map directly to vlt's scoped-registries:

vlt.json
{
  "scoped-registries": {
    "@mycompany": "https://npm.mycompany.com/"
  }
}

Named Registry Aliases

vlt also supports named registry aliases which remove the ambiguity of scope-based mapping:

vlt.json
{
  "registries": {
    "internal": "https://npm.mycompany.com/"
  }
}

Then reference packages explicitly in package.json:

package.json
{
  "dependencies": {
    "@mycompany/utils": "internal:@mycompany/utils@^2.0"
  }
}

Authentication

pnpm stores auth tokens in .npmrc, same as npm. vlt stores them in an XDG-compliant keychain file, keeping secrets out of project config files.

Terminal
# Log in to default registry
$ vlt login

# Log in to custom registry

$ vlt login --registry=https://npm.mycompany.com/

CI Environments

Terminal
# pnpm
NPM_TOKEN=abc123 pnpm install

# vlt

VLT_TOKEN=abc123 vlt install

See Authentication for full details.


Lockfile

pnpm uses pnpm-lock.yaml. vlt uses vlt-lock.json.

When you first run vlt install, vlt creates vlt-lock.json from a fresh resolution of your package.json files. The pnpm-lock.yaml is not read.

What to do:

  1. Run vlt install to generate vlt-lock.json
  2. Commit vlt-lock.json
  3. Optionally remove pnpm-lock.yaml once you've fully switched

Install Script Protection

pnpm runs lifecycle scripts by default during install (same as npm). pnpm v9+ added onlyBuiltDependencies in package.json as an allowlist, but scripts still run by default for listed packages.

vlt takes a different approach: vlt install runs no scripts at all by default. Building is a separate, explicit step:

Terminal
# Phase 1: Install (no code executes)
$ vlt install

# Phase 2: Build (runs scripts, skipping known malware)

$ vlt build

By default, vlt build uses the target :scripts:not(:built):not(:malware) — it automatically skips packages flagged as malware by Socket.

pnpm onlyBuiltDependencies vs vlt build --target

package.json (pnpm)
{
  "pnpm": {
    "onlyBuiltDependencies": [
      "esbuild",
      "node-gyp"
    ]
  }
}
Terminal (vlt)
$ vlt build --target='#esbuild, #node-gyp'

You can persist the target:

Terminal
$ vlt config set "command.build.target=#esbuild, #node-gyp"

See vlt build for full details.


Workspaces

pnpm

pnpm defines workspaces in pnpm-workspace.yaml:

pnpm-workspace.yaml
packages:
- "packages/*"
- "apps/*"

vlt

vlt defines workspaces in vlt.json:

vlt.json
{
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}

vlt also supports named workspace groups:

vlt.json
{
  "workspaces": {
    "apps": "apps/*",
    "libs": [
      "packages/*",
      "shared/*"
    ]
  }
}

Workspace Commands

pnpmvlt
pnpm --filter <name> <cmd>vlt <cmd> -w <path> or cd <path> && vlt <cmd>
pnpm --filter ./packages/* <cmd>vlt <cmd> -w packages/*
pnpm -r <cmd>vlt <cmd> --recursive
pnpm -r run testvlt run test --recursive

Note: vlt's --workspace (-w) flag takes paths or glob patterns, not package names.

Terminal
# Run tests in a specific workspace
$ vlt run test -w packages/core

# Run build across a workspace group

$ vlt run build -g libs

See Workspaces for full details.


Catalogs

If you use pnpm's catalog feature (pnpm-workspace.yaml), vlt has direct support for catalogs with compatible syntax.

pnpm:

pnpm-workspace.yaml
# pnpm-workspace.yaml
packages:
- "packages/*"

catalog: typescript: "^5.0.0" eslint: "^8.0.0"

catalogs: testing: vitest: "^1.0.0"

vlt:

vlt.json
{
  "workspaces": [
    "packages/*"
  ],
  "catalog": {
    "typescript": "^5.0.0",
    "eslint": "^8.0.0"
  },
  "catalogs": {
    "testing": {
      "vitest": "^1.0.0"
    }
  }
}

The catalog: protocol in package.json works the same way:

package.json
{
  "devDependencies": {
    "typescript": "catalog:",
    "vitest": "catalog:testing"
  }
}

See Catalogs for full details.


Overrides → Graph Modifiers

pnpm uses pnpm.overrides in package.json. vlt uses Graph Modifiers in vlt.json.

package.json (pnpm)
{
  "pnpm": {
    "overrides": {
      "lodash": "^4.17.21",
      "express>qs": "6.10.0"
    }
  }
}
vlt.json
{
  "modifiers": {
    "#lodash": "^4.17.21",
    ":root > #express > #qs": "=6.10.0"
  }
}

Graph Modifiers use DSS selectors, giving you more precise control (e.g., target by path, workspace, or semver range).


node_modules Layout

pnpm uses a content-addressable store with symlinks to create a strict node_modules layout where packages can only access their declared dependencies.

vlt also creates a node_modules directory but uses a different internal layout (under node_modules/.vlt/). The result is similar in that packages resolve correctly at runtime — your application code doesn't need to change.


Features Not in vlt

Some pnpm-specific features don't have direct equivalents:

  • Side-effects cache — Not available in vlt
  • pnpm patch — Not yet available in vlt
  • pnpm deploy — Not available; use standard deployment tooling
  • pnpm.peerDependencyRules — vlt handles peer dependencies automatically with context isolation

Migration Checklist

  1. Install vlt: npm install -g vlt
  2. Create vlt.json combining your .npmrc registry config and pnpm-workspace.yaml workspace definitions
  3. Move scoped registry config from .npmrc to vlt.json
  4. Move catalogs from pnpm-workspace.yaml to vlt.json (catalog and catalogs fields)
  5. Move pnpm.overrides from package.json to modifiers in vlt.json
  6. Run vlt install then vlt build
  7. Commit vlt-lock.json
  8. Update CI scripts: replace pnpm install --frozen-lockfile with vlt install --frozen-lockfile && vlt build
  9. Update CI auth: replace NPM_TOKEN with VLT_TOKEN
  10. Update any pnpm dlx usage to vlx
  11. Remove pnpm-workspace.yaml and pnpm-specific .npmrc settings

PreviousFrom yarnNextOverview

On this page

  • Quick Start
  • Command Mapping
  • Shorthand Script Execution
  • Configuration
  • .npmrc + pnpm-workspace.yaml → vlt.json
  • Registry Configuration
  • Scoped Registries
  • Named Registry Aliases
  • Authentication
  • CI Environments
  • Lockfile
  • Install Script Protection
  • pnpm onlyBuiltDependencies vs vlt build --target
  • Workspaces
  • pnpm
  • vlt
  • Workspace Commands
  • Catalogs
  • Overrides → Graph Modifiers
  • node_modules Layout
  • Features Not in vlt
  • Migration Checklist
Edit this page

Deploy your package on vlt.io

Publish scoped and private packages, manage organizations and access, and give every developer and CI environment a consistent source for public and private JavaScript dependencies.

Publish now