groundy
developer tools

Vercel CLI Now Scopes Commands to the Local Directory: Audit Your CI Scripts

Vercel CLI v50.40.0 scopes read-only commands like vc project ls to the local directory's team, so CI scripts that cd between projects now return different output.

8 min · · · 7 sources ↓

vc project ls and vc domains ls now resolve against the team of the locally linked project instead of the global team. The Vercel changelog documenting v50.40.0, dated 2026-04-06, is short and narrow in surface area, but the change widens the blast radius of every script that changes directories or assumed a single linked target. Teams auto-bumping vercel@latest have already inherited it without a version check.

What actually changed in Vercel CLI v50.40.0

Before v50.40.0, running vc project ls inside a linked repository returned results from your global team, producing what the Vercel changelog calls “an unexpected disconnect between your immediate working environment and the CLI output.” From v50.40.0 onward, read-only commands like vc project ls and vc domains ls automatically use the scope of your linked local directory rather than defaulting to the global team. The override still exists: pass the --scope flag to target a specific team, and the changelog scopes the change to read-only commands explicitly. Update with pnpm i -g vercel@latest to at least v50.40.0.

Coverage of the release has been thin. Beyond Vercel’s own changelog, a host-hunters forum thread reproduces the changelog verbatim, so it is not independent reporting. Neither source addresses what the change does to CI scripts or where the audit line actually falls.

Scope (team) versus project targeting: the two resolution paths

The CLI resolves two independent things, and conflating them is the most common mistake when auditing for this change.

Scope answers which team’s data a command sees. The global options documentation defines --scope (shorthand -S) as executing a command from a scope that is not currently active, and --team (-T) as targeting a specific team slug or ID. Both are team-selection levers, distinct from which project a command targets. The v50.40.0 change moved the default for these levers on read-only commands from global to local.

Project targeting answers which project a command mutates, and follows a strict precedence. According to the global options docs, the chain is the --project flag, then the VERCEL_PROJECT_ID environment variable, then the .vercel/project.json file written by vercel link. This precedence is what determines where a vercel deploy lands, and v50.40.0 does not touch it.

The practical consequence is asymmetric. A read-only command can now list a different set of projects or domains after a version bump because the team changed, while a deploy still ships to the project that .vercel/project.json or VERCEL_PROJECT_ID names. A script that reads vc project ls to derive a project ID, then feeds that ID to a deploy, can now read from a team-scoped list that excludes the project it then tries to deploy. The two steps no longer share a resolution basis by default.

Resolution axisWhat it answersLeversChanged in v50.40.0?
Scope (team)Which team’s data a command sees--scope (-S), --team (-T), local-directory defaultYes, for read-only commands
Project targetingWhich project a command mutates--project > VERCEL_PROJECT_ID > .vercel/project.jsonNo

Why monorepos and CI pipelines are most exposed

The local-directory default is only safe to assume if the working directory is stable. Two common setups break that assumption.

The first is the monorepo. Vercel’s monorepo documentation states the CLI should not be invoked from a subdirectory: vercel link is run from the monorepo root, and switching to a different project in the same monorepo requires re-running vercel link. That means the locally linked project, and therefore the local team scope, depends entirely on where vercel link last ran. A script that cds into apps/web to run vc project ls will now resolve scope against whatever the root link established, which may not be the team the caller expected. This is a long-standing constraint that the local-scope default now makes consequential for read-only output. A community discussion on vercel/community (#5060) argues this root-only linking model locks each monorepo to one linked project at a time, creating friction for Turborepo setups where multiple apps each need their own .env.local pulled independently.

The second is the CI pipeline that steps across directories. The global options docs document a --cwd flag that runs the CLI against a different working directory, relative or absolute. That directly affects scripts that cd between subdirectories or execute from a parent directory: change the cwd and you may change the team scope that read-only commands inherit. Under v50.40.0, the same vc project ls invocation can return teams that differ by working directory, and a --cwd apps/marketing call can produce a different result than one run from the repo root.

How to make command resolution deterministic

Four flags and env vars cover the surface, and the right combination depends on whether each script reads inventory or mutates a project.

For team scope, pass --scope <scope> (or --team <slug>) explicitly on every read-only command instead of relying on the local default. This restores explicit targeting at the cost of one flag per invocation. It is the cheapest fix and the one that survives future scope-resolution changes, because it does not depend on which directory the command ran from.

For project targeting, the global options docs recommend setting VERCEL_ORG_ID and VERCEL_PROJECT_ID in CI/CD to skip project linking entirely. Because the precedence is --project over VERCEL_PROJECT_ID over .vercel/project.json, an environment variable beats the linked file. The project-linking docs note that vercel link writes a .vercel/project.json holding orgId and projectId, auto-detects a project by slugifying the current directory name, and that removing the .vercel directory unlinks the project. Relying on the file means relying on where the link last ran; relying on the env var means relying on CI configuration. The latter is grep-able and survives a fresh clone.

For directory, prefer the --cwd flag over in-script cd calls. An explicit --cwd apps/web is visible in logs and reviewable in a pull request; a shell cd is neither. If the script must cd, hold the directory constant per job and document which linked project it resolves to.

For linking, vercel link also accepts --repo (link all projects in a repository at once, which requires the Git integration), --project (set a project name or ID that does not match the cwd name), and --yes (skip setup prompts with defaults), per the vercel link docs. These matter when the directory name and the project slug diverge, which is the exact case the auto-slugify detection gets wrong.

Version pinning and rollout: what to check before the next deploy

The durable fix for “it worked before the bump” is to stop auto-bumping. Pin the CLI version in CI rather than resolving vercel@latest, so a scope-resolution change like v50.40.0 arrives when you choose it, not when a lockfile resolves. Then run three checks before the next deploy.

First, enumerate every vc and vercel invocation in the pipeline and record its working directory. Any read-only command, project ls, domains ls, and anything that lists inventory, is where the output changed. Second, for each of those, decide whether the output feeds a decision. If it gates a deploy, asserts a domain, or diffs an inventory, pin it with --scope. Third, confirm mutation commands still resolve the expected project by checking that VERCEL_PROJECT_ID or --project is set, rather than trusting a .vercel/project.json written from a different directory.

The honest read of this release is that it closes a real footgun while making the working directory matter more than before. Read-only commands returning global results inside a linked repo is genuinely surprising behavior, and aligning them with local context is a sensible default. The cost is that cwd is now a load-bearing input for any script that consumes read-only output. The team that runs every Vercel command from the repo root, with VERCEL_PROJECT_ID set in CI, will not notice the change. The team with a script that shells into three subdirectories and greps vc project ls will notice it as a shortened list, a missing project, or a misrouted decision weeks after the version that introduced it. Pin the version, audit the scripts, and prefer explicit flags over inherited defaults.

Frequently Asked Questions

Does the v50.40.0 change affect vercel env pull in a monorepo?

No. The changelog limits the change to read-only commands and team-scope resolution, so vercel env pull still targets a project through the --project over VERCEL_PROJECT_ID over .vercel/project.json chain. The related friction predates this release: the vercel/community #5060 discussion argues each monorepo resolves to one linked project at a time, so pulling .env.local for a second app requires re-running vercel link against that app first.

How do the --scope and --team flags actually differ?

--team (-T) targets a specific team by slug or ID. --scope (-S) runs the command from a scope that is not currently active, without requiring you to name a team identifier. Both override the active scope on read-only commands, but --team is the identifier-pinned form and --scope is the switch-context form.

What breaks if a linked directory is renamed?

The CLI auto-detects a project by slugifying the current directory name, so a renamed directory no longer matches the slug captured at link time. The committed .vercel/project.json still carries the original orgId and projectId, so commands keep resolving to the old project until you remove the .vercel directory or re-run vercel link.

vercel link --repo links all projects in a repository in one step, but only when the Vercel Git integration is already connected to that repository. Without the integration the flag is unavailable, and teams fall back to running vercel link per directory, which is exactly where the directory-name auto-slugify can mismatch the intended project slug.

What is the tradeoff of pinning the CLI version instead of tracking latest?

Pinning stops silent inheritance of scope-resolution changes, so a release like v50.40.0 lands when you schedule the bump. The cost is upgrade lag: security and bug fixes in later CLI versions wait until that scheduled bump, so the pinning pattern only holds up if a bump is actually on the calendar rather than deferred indefinitely.

sources · 7 cited

  1. Vercel CLI commands now scoped to local directory (host-hunters mirror) host-hunters.com community accessed 2026-06-23
  2. Vercel CLI Global Options vercel.com vendor accessed 2026-06-23
  3. Using Monorepos vercel.com vendor accessed 2026-06-23
  4. Linking Projects with Vercel CLI vercel.com vendor accessed 2026-06-23
  5. vercel link vercel.com vendor accessed 2026-06-23