ViteplusVsTurborepo

Could Vite+ replace Turborepo as this repo's monorepo task runner? Research from 2026-07-24, part of TechHousekeeping.

Scope: this page only evaluates Vite+'s monorepo-aware task runner (vp run / "Vite Task") as a potential replacement for Turborepo in the contentsgarten repo. Vite+ is not being evaluated as a replacement for Astro on wiki.creatorsgarten.org — the team is keeping Astro; Vite+ would sit underneath as the task orchestrator/tool wrapper, the same role Turborepo plays today.

1. What Vite+ actually is

Vite+ is VoidZero's unified JavaScript toolchain — described as "a single entry point to web development" that bundles Vite, Vitest, Rolldown, tsdown, Oxlint, Oxfmt and a built-in monorepo-aware task runner ("Vite Task") into one tested stack, with commands like vp dev, vp check, vp test, vp build, vp pack, vp run (voidzero.dev/posts/announcing-vite-plus-beta).

It is explicitly not a fork or a rename of Vite/Vitest — the original announcement describes it as "a separate, additive layer built on top of the open source projects we maintain," while "all existing projects — Vite, Vitest, Rolldown, and Oxc — will remain open source under MIT forever" (voidzero.dev/posts/announcing-vite-plus). So: Vite and Vitest keep existing as independent OSS projects; Vite+ is the integration/orchestration layer wrapping them (and other tools) into one CLI.

Licensing changed between announcements (see §5) — worth flagging up front because it affects the "is this a paid product" question: the original Oct 2025 announcement said Vite+ "will be commercially licensed, it will be source-available," with a free tier for individuals/OSS/small business and paid tiers for startups/enterprise (voidzero.dev/posts/announcing-vite-plus). By the July 2026 beta announcement this had changed: "Vite+ is fully open-source under the MIT license" (voidzero.dev/posts/announcing-vite-plus-beta), a claim also stated on the GitHub repo.

2. Monorepo-aware task running: how it works, vs. Turborepo

Turborepo, as configured in this repo today

turbo.json defines three tasks under pipeline:

{
  "pipeline": {
    "build": {
      "outputs": ["build/**", "public/build/**", ".netlify/**", "dist/**"],
      "dependsOn": ["^build"],
      "env": ["NETLIFY"]
    },
    "dev": { "cache": false, "persistent": true },
    "lint": {}
  }
}
  • build depends on ^build (the build task of every workspace dependency must finish first) — Turbo's explicit dependency-graph syntax, declared once centrally in turbo.json.
  • build's cacheable outputs are explicitly listed (build/**, public/build/**, .netlify/**, dist/**), and NETLIFY is declared as an env var that should bust the cache.
  • dev is marked persistent: true and cache: false (long-running dev servers, not cacheable).
  • lint has no config (defaults apply); only one workspace package (wiki.wonderful.software) actually defines a "lint" script (next lint) — the others have no lint script, so Turbo just skips them.

Vite+'s "Vite Task" runner

Vite+'s task runner is invoked via vp run (alias vpr). It executes either scripts already defined in each package's package.json, or tasks declared explicitly in a vite.config.ts under a run.tasks block (viteplus.dev/guide/run):

import { defineConfig } from 'vite-plus'

export default defineConfig({
  run: {
    tasks: {
      build: {
        command: 'vp build',
        dependsOn: ['lint'],
        env: ['NODE_ENV'],
      },
    },
  },
})

Key mechanics, per viteplus.dev/guide/run:

  • Task dependency ordering across the workspace is resolved primarily through ordinary package.json dependency relationships between workspace packages, not a separate, hand-declared task graph the way Turbo's dependsOn: ["^build"] requires. A task can also depend on a specific task in a specific package via dependsOn: ['@my/core#build'].
  • Package targeting: vp run build (current dir), vp run @my/app#build (specific package).
  • Workspace-wide execution flags: -r/--recursive (every workspace package, in dependency order), -t/--transitive (one package + its deps), --filter (pnpm-style name/dir/glob filter), -w (workspace root).
  • Concurrency defaults to 4 parallel tasks, tunable via --concurrency-limit / VP_RUN_CONCURRENCY_LIMIT; --parallel ignores the dependency graph entirely.
  • Tasks can also come from plain package.json scripts with no vite.config.ts entry at all — but per the caching section (§3), those only get caching if invoked with --cache.

Where the models are similar: both let one task declare it depends on another task (in the same or another workspace package) before running, and both support a "run in every package, in dependency order" mode.

Where they differ:

  • Turbo's dependency direction is declared once, centrally, in turbo.json ("dependsOn": ["^build"] means "my build needs every upstream workspace dependency's build"), and applies uniformly to every package that has a build script. Vite+ instead resolves this from the real package.json dependencies/workspace:* graph by default, with per-task dependsOn overrides only where you write them (in vite.config.ts, optionally per-package) — there is no single "pipeline" file listing all task types up front.
  • Turbo's outputs field is a first-class, per-task declaration of what to cache/restore. Vite+'s cache instead advertises "automatic data tracking" of files read/written per command rather than a hand-authored allow-list (see §3) — conceptually similar goal (know what changed → know what to invalidate), different mechanism (declared vs. inferred).
  • The dedicated Monorepo Guide focuses mainly on sharing lint/format config across packages via lint.overrides / fmt.overrides globs in a root vite.config.ts, and does not itself discuss dependsOn or graph semantics in depth — that material lives on the run page instead. It does not state which workspace managers it detects (pnpm/npm/yarn) or spell out discovery mechanics beyond assuming a root vite.config.ts with optional per-package vite.config.ts files.
  • Vite+'s CLI defers package-manager operations (vp install, vp add, vp remove) to whatever package manager the project's packageManager field declares (viteplus.dev/guide/migrate), which is a good sign for pnpm-workspace compatibility, but no page fetched here explicitly confirms pnpm-workspace.yaml (as opposed to npm/yarn/pnpm workspaces declared purely via packageManager) is read for package discovery.

3. Caching: local and (GitHub Actions) remote

Local cache (viteplus.dev/guide/cache):

  • On a successful task run, Vite Task "saves terminal output (stdout/stderr) and all written files (output files)." On a later run with a matching fingerprint it "replays the cached terminal output, restores saved output files, and skips the command."
  • The cache key/fingerprint is built from three inputs: (1) additional CLI arguments passed to the task, (2) "fingerprinted env vars" — only vars explicitly listed in a task's env: [...] array participate; by default only a small allow-list (PATH, HOME, CI, etc.) is passed through at all — and (3) "any input file that the command reads," tracked via automatic data tracking rather than a hand-written glob list.
  • Local cache storage location: node_modules/.vite/task-cache at the project root; clearable via vp cache clean.
  • Cache-miss diagnostics are explicit, e.g. cache miss: 'src/utils.ts' modified, executing or cache miss: env 'VITE_GREETING' changed, executing.
  • The cache guide page itself contains no mention of a hosted/remote cache service — no token, no account, no "team" concept comparable to Vercel's remote cache backing Turbo. The guide index confirms "Task Caching" and "GitHub Actions Cache" are the only two caching-related guide pages; there's no separate "remote cache" doc (viteplus.dev/guide/).

GitHub Actions cache (viteplus.dev/guide/github-actions-cache):

  • Not automatic — it's wired by hand with GitHub's native actions/cache/restore + actions/cache/save steps pointed at node_modules/.vite/task-cache, no VoidZero account or token involved:

    - name: Restore Vite Task cache
      id: vite-task-cache
      uses: actions/cache/restore@v6
      with:
        path: node_modules/.vite/task-cache
        key: vite-task-$-$-$-$
        restore-keys: |
          vite-task-$-$-
    
    - run: vp run lint
    - run: vp run build
    
    - name: Save Vite Task cache
      if: success()
      uses: actions/cache/save@v6
      with:
        path: node_modules/.vite/task-cache
        key: $
    
  • Restore must happen after vp install, since dependency installation can itself modify node_modules.

  • "GitHub Actions cache" here really means: reuse GitHub's per-run cache storage as a shared drop-in for the same local on-disk cache format — functionally closer to how many teams already wire up Turbo's cache directory to actions/cache themselves than to Turbo's own hosted Remote Cache product.

Contrast with how this repo wires Turbo's cache today. This repo does not use Vercel's hosted remote cache (no TURBO_TOKEN/TURBO_TEAM appear anywhere in the workflows or package.json). Instead, both .github/workflows/playwright.yml and .github/workflows/release.yml use a third-party action, dtinth/setup-github-actions-caching-for-turbo@v1, which transparently proxies Turbo's local cache protocol through the GitHub Actions cache. So the actual caching architecture already in use here (local-cache-format piggybacked on GH Actions cache, no paid remote-cache account) is conceptually the closest possible match to what Vite+'s GitHub Actions cache guide describes — this repo isn't currently using the part of Turbo (hosted remote cache) that Vite+ has no equivalent for.

4. Maturity, licensing, pricing

  • Status: beta, as of the July 2026 announcement: "Vite+ is stable, but not yet complete." The post explicitly recommends adopting "only if it covers your needs," warns complex projects "may require manual follow-up during migration," and says to "read the migration guide before adopting Vite+ in a production project" (voidzero.dev/posts/announcing-vite-plus-beta). This is roughly three weeks old relative to this research (2026-07-24).
  • Before that, Vite+ went through an alpha stage and the original October 2025 unveiling (voidzero.dev/posts/announcing-vite-plus) — roughly nine months of public iteration (alpha → beta) by the time of this research, short next to Turborepo's multi-year history.
  • Licensing/pricing history is not static. At the October 2025 launch, VoidZero stated Vite+ itself (as distinct from Vite/Vitest/Rolldown/Oxc) "will be commercially licensed, it will be source-available," with a free tier for individuals/OSS/small business, flat pricing planned for startups, and custom enterprise pricing. By the beta announcement (July 2026) and on the current GitHub repo, the position had changed to fully MIT-licensed, no commercial tier stated (github.com/voidzero-dev/vite-plus). Practical read: as of this research, Vite+ (including the task runner/caching evaluated here) is free and MIT-licensed with no signup required — but the licensing model already changed once in nine months, so today's free/MIT terms aren't safe to assume permanent. VoidZero is a funded commercial company.
  • No page fetched in this research states any known-limitations list, deprecation notices, or explicit compatibility matrix beyond the general "not yet complete" caveat — specific gaps (e.g. exact parity with Turbo's outputs globbing, or behavior under pnpm-workspace.yaml package discovery) aren't independently confirmed either way.

5. Repo-grounded migration-cost estimate

Everything that currently touches turbo in this repo:

FileTurbo-related content
turbo.jsonDefines pipeline.build (outputs, dependsOn: ["^build"], env: ["NETLIFY"]), pipeline.dev (cache: false, persistent: true), pipeline.lint ({})
package.json (root)"build": "turbo build", "dev": "turbo dev"; "turbo": "^1.8.3" in devDependencies
.github/workflows/playwright.ymluses: dtinth/setup-github-actions-caching-for-turbo@v1; run: pnpm run build (invokes turbo build via the root script)
.github/workflows/release.ymluses: dtinth/setup-github-actions-caching-for-turbo@v1; run: pnpm build
.github/workflows/creatorsgarten-wiki-cicd.ymlNo turbo usage — pure Docker build/push, unaffected either way
packages/*/package.json (5 packages)None invoke turbo directly — each just has "build": "tsup ..."
App package.jsons (contentsgarten.netlify.app, wiki.creatorsgarten.org, wiki.wonderful.software)None invoke turbo directly either — these are the leaf apps Turbo's ^build dependency graph builds up to

Notably: no TURBO_TOKEN/TURBO_TEAM env vars exist anywhere in this repo — it never adopted Vercel's hosted remote cache, only the GH Actions-proxied local-cache trick above. That removes one migration variable entirely (no remote-cache credential to replace).

Concrete replacement steps, if migrating to Vite+:

  1. Add a root vite.config.ts with run.tasks for build (relying on Vite+'s default package.json-dependency-graph resolution, since none of this repo's inter-package deps are unusual) and lint (currently only meaningfully defined for wiki.wonderful.software); dev can most likely stay as an uncached/persistent invocation since Vite+ tasks from plain package.json scripts don't cache unless --cache is passed, which naturally matches Turbo's "dev": {"cache": false, "persistent": true}.
  2. Replace root package.json scripts: "build": "turbo build""build": "vp run -r build" (or similar recursive/filtered form); "dev": "turbo dev""dev": "vp run dev" (needs verification against Vite+'s persistent/dev-task handling, not explicitly documented on the fetched pages). Remove turbo from root devDependencies; add Vite+ (vite-plus/vp CLI) as a dependency.
  3. Delete turbo.json, or keep it briefly as documentation during a transition (not required by Vite+, no conflict either way).
  4. In both CI workflows, replace the dtinth/setup-github-actions-caching-for-turbo@v1 step with either the recommended voidzero-dev/setup-vp action (which per viteplus.dev/guide/ci also handles Node/package-manager setup and dependency-install caching) or hand-rolled actions/cache/restore + actions/cache/save steps around node_modules/.vite/task-cache per §3. Both workflows' pnpm run build/pnpm build steps keep working unmodified since they still just invoke the root build script.
  5. creatorsgarten-wiki-cicd.yml needs no changes.
  6. Verify outputs parity: Turbo's build task explicitly lists build/**, public/build/**, .netlify/**, dist/** as cacheable outputs. Vite+'s automatic data tracking is inferential rather than declared, per §3 — needs empirical verification per package (tsup-built packages emit to dist/**; the Remix app emits to build/**/public/build/**/.netlify/**) before trusting cache correctness, since none of the fetched Vite+ docs describe an explicit output-allowlist mechanism equivalent to Turbo's outputs field.

Effort/risk sizing: small-to-medium, low urgency.

  • Small because the actual turbo surface area in this repo is genuinely thin: one turbo.json with three simple task entries, two root scripts, and two CI workflow steps referencing a third-party GH Actions caching action — no remote-cache tokens, no complex multi-stage pipeline, no package invoking turbo directly.
  • Medium/elevated risk, not because of the size of the change, but because of what the primary sources leave unconfirmed: none of the fetched pages give a worked example of a dev/persistent long-running task, nor an explicit output-globbing mechanism comparable to Turbo's outputs, nor a stated pnpm-workspace.yaml discovery guarantee — all of which this repo relies on today (Remix dev, astro dev, next dev -p ${PORT} are all long-running persistent processes; build outputs differ per app type). Combined with Vite+'s own "beta... not yet complete" self-description and a licensing model that already changed once in nine months, this is not a change to make purely for its own sake right now.
  • Nothing blocks migration outright (Vite+ is free/MIT today per §4, and none of the CI workflows depend on a paid remote-cache account) — but nothing forces it either, since the current Turbo setup is small, cheap, and already working without a hosted-cache dependency.

6. Top-line recommendation

Wait. Vite+'s task runner and caching model are architecturally close enough to what this repo already asks of Turborepo (a thin ^build dependency graph, GH Actions-proxied local caching, no hosted remote cache) that migration would likely be mechanically small — but Vite+ is three weeks into a beta that self-describes as "not yet complete," its licensing terms already shifted once in nine months from paid/source-available to free/MIT, and the fetched primary docs leave open exactly the two things this repo depends on most (persistent dev tasks across three different frameworks, and explicit multi-directory build outputs). None of that is disqualifying, but there is no active pain with the current 15-line turbo.json + one GH Actions caching action to justify migrating onto a beta product now. Revisit once Vite+ reaches a stable (non-beta) release and its docs explicitly cover dev-task/persistent-process semantics and output-tracking guarantees.


Sources consulted

Secondary/community sources (VoidZero's own X/Twitter post on pricing, third-party recap articles surfaced via web search) were used only to locate the primary posts above and are not cited as the basis for any factual claim on this page.