"Skip Unaffected Projects" treats all non-workspace changes as global – Make it configurable

Problem

In a monorepo with multiple Vercel projects (each mapped to a workspace package, e.g., apps/web, apps/storybook), the “Skip unaffected project” feature treats any change outside the workspace definition as a global trigger and deploys every connected project.

For a mixed-language/polyglot monorepo, this is most changes. My repo has Python backends, that are deployed outside of Vercel, that aren’t in pnpm-workspace.yaml. A PR touching only those, or even a root README.md, rebuilds and redeploys all my Vercel projects.

This is documented, by-design behaviour, not a bug (docs):

“Changes that are not a part of the workspace definition will be considered global changes and deploy all applications in the repository.”

Repro

The mismatch is that Turborepo’s own analysis already gets this right:

  • Change only README.mdturbo query affected reports zero affected packages → but Vercel deploys everything.
  • Change a .tsx in apps/web → correctly reports @ayo/web affected → Vercel deploys only that.
// turbo query affected, after a README-only or Python  change
{ "data": { "affectedTasks": { "items": [], "length": 0 } } }

I understand that this is hard to replicate on a platform level due to many variables, but I believe the solution below would be a nice one.

Workaround; that doesn’t fit

A custom Ignored Build Step (with turbo query affected) can replicate the precise decision, but it’s not equivalent. Native Skip (docs):

“does not occupy concurrent build slots… reducing build queue times.”

An Ignored Build Step (docs):

“canceled builds… still count towards your deployment quotas and concurrent build slots.”

So the workaround materialises a CANCELED deployment on every PR and burns a slot; exactly what native Skip avoids.

Solution

I think users should have control over how non-workspace changes are evaluated, rather than always falling back to “deploy everything.” I’m not tied to a mechanism. For example:

  • a configurable glob list of root paths that count as global triggers
  • an opt-in to defer the decision to Turborepo’s graph (turbo query affected)

I’d be interested to hear if anyone else bumps into this, so please share.

Thanks for the feedback! Yes, this is something others have also run into. It’s expected behavior for now, as you saw in the docs.

Changing that behavior is more complex than it might seem at first glance, so we don’t have an immediate solution. But I shared this thread with the team and I’ll keep it open so others can share their experience and suggestions :smiley:

Also want to share another workaround I’ve seen. You can build a custom workflow to have more control over exactly what gets deployed and avoid the canceled deployments. There’s a basic script template and setup steps for GitHub Actions in this guide:

That’s obviously a bit more work than the standard automatic deployments. But once you’ve got it set up it just works. I hope that helps!

Thanks for the suggestion! I’ll probably end up going with GitHub actions for now.

I definitely would love to see some work on the skip unaffected deployments feature to be a bit more controlled, especially since polyglot monorepos are more and more popular these days. I do think some more control based on these environments would be welcome.