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": {}
}
}
builddepends on^build(thebuildtask of every workspace dependency must finish first) — Turbo's explicit dependency-graph syntax, declared once centrally inturbo.json.build's cacheable outputs are explicitly listed (build/**,public/build/**,.netlify/**,dist/**), andNETLIFYis declared as an env var that should bust the cache.devis markedpersistent: trueandcache: false(long-running dev servers, not cacheable).linthas no config (defaults apply); only one workspace package (wiki.wonderful.software) actually defines a"lint"script (next lint) — the others have nolintscript, 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.jsondependency relationships between workspace packages, not a separate, hand-declared task graph the way Turbo'sdependsOn: ["^build"]requires. A task can also depend on a specific task in a specific package viadependsOn: ['@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;--parallelignores the dependency graph entirely. - Tasks can also come from plain
package.jsonscripts with novite.config.tsentry 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 "mybuildneeds every upstream workspace dependency'sbuild"), and applies uniformly to every package that has abuildscript. Vite+ instead resolves this from the realpackage.jsondependencies/workspace:*graph by default, with per-taskdependsOnoverrides only where you write them (invite.config.ts, optionally per-package) — there is no single "pipeline" file listing all task types up front. - Turbo's
outputsfield 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.overridesglobs in a rootvite.config.ts, and does not itself discussdependsOnor graph semantics in depth — that material lives on therunpage instead. It does not state which workspace managers it detects (pnpm/npm/yarn) or spell out discovery mechanics beyond assuming a rootvite.config.tswith optional per-packagevite.config.tsfiles. - Vite+'s CLI defers package-manager operations (
vp install,vp add,vp remove) to whatever package manager the project'spackageManagerfield declares (viteplus.dev/guide/migrate), which is a good sign for pnpm-workspace compatibility, but no page fetched here explicitly confirmspnpm-workspace.yaml(as opposed to npm/yarn/pnpm workspaces declared purely viapackageManager) 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-cacheat the project root; clearable viavp cache clean. - Cache-miss diagnostics are explicit, e.g.
cache miss: 'src/utils.ts' modified, executingorcache 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/savesteps pointed atnode_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 modifynode_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/cachethemselves 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
outputsglobbing, or behavior underpnpm-workspace.yamlpackage discovery) aren't independently confirmed either way.
5. Repo-grounded migration-cost estimate
Everything that currently touches turbo in this repo:
| File | Turbo-related content |
|---|---|
turbo.json | Defines 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.yml | uses: dtinth/setup-github-actions-caching-for-turbo@v1; run: pnpm run build (invokes turbo build via the root script) |
.github/workflows/release.yml | uses: dtinth/setup-github-actions-caching-for-turbo@v1; run: pnpm build |
.github/workflows/creatorsgarten-wiki-cicd.yml | No 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+:
- Add a root
vite.config.tswithrun.tasksforbuild(relying on Vite+'s default package.json-dependency-graph resolution, since none of this repo's inter-package deps are unusual) andlint(currently only meaningfully defined forwiki.wonderful.software);devcan most likely stay as an uncached/persistent invocation since Vite+ tasks from plainpackage.jsonscripts don't cache unless--cacheis passed, which naturally matches Turbo's"dev": {"cache": false, "persistent": true}. - Replace root
package.jsonscripts:"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). Removeturbofrom rootdevDependencies; add Vite+ (vite-plus/vpCLI) as a dependency. - Delete
turbo.json, or keep it briefly as documentation during a transition (not required by Vite+, no conflict either way). - In both CI workflows, replace the
dtinth/setup-github-actions-caching-for-turbo@v1step with either the recommendedvoidzero-dev/setup-vpaction (which per viteplus.dev/guide/ci also handles Node/package-manager setup and dependency-install caching) or hand-rolledactions/cache/restore+actions/cache/savesteps aroundnode_modules/.vite/task-cacheper §3. Both workflows'pnpm run build/pnpm buildsteps keep working unmodified since they still just invoke the rootbuildscript. creatorsgarten-wiki-cicd.ymlneeds no changes.- Verify
outputsparity: Turbo'sbuildtask explicitly listsbuild/**,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 todist/**; the Remix app emits tobuild/**/public/build/**/.netlify/**) before trusting cache correctness, since none of the fetched Vite+ docs describe an explicit output-allowlist mechanism equivalent to Turbo'soutputsfield.
Effort/risk sizing: small-to-medium, low urgency.
- Small because the actual turbo surface area in this repo is genuinely
thin: one
turbo.jsonwith 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 invokingturbodirectly. - 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'soutputs, nor a statedpnpm-workspace.yamldiscovery guarantee — all of which this repo relies on today (Remixdev,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
- voidzero.dev/posts/announcing-vite-plus-beta
- voidzero.dev/posts/announcing-vite-plus
- viteplus.dev/guide/
- viteplus.dev/guide/run
- viteplus.dev/guide/cache
- viteplus.dev/guide/github-actions-cache
- viteplus.dev/guide/monorepo
- viteplus.dev/guide/migrate
- viteplus.dev/guide/ci
- github.com/voidzero-dev/vite-plus (license/status only)
- This repo (contentsgarten):
turbo.json,pnpm-workspace.yaml,package.json,packages/*/package.json,contentsgarten.netlify.app/package.json,wiki.creatorsgarten.org/package.json,wiki.wonderful.software/package.json,.github/workflows/playwright.yml,.github/workflows/release.yml,.github/workflows/creatorsgarten-wiki-cicd.yml
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.