# Vitest Contributing Guide Hi! We are really excited that you are interested in contributing to Vitest. Before submitting your contribution, please make sure to take a moment and read through the following guide: ## Repo Setup The Vitest repo is a monorepo using pnpm workspaces. The package manager used to install and link dependencies must be [pnpm](https://pnpm.io/). We recommend installing [ni](https://github.com/antfu/ni) to help switching between repos using different package managers. `ni` also provides the handy `nr` command which running npm scripts easier: - `ni` is equivalent to `pnpm install` - `nr test` is equivalent to `pnpm run test` To develop and test `vitest` package: 1. Run `pnpm install` in `vitest`'s root folder 2. Run `pnpm run build` to build all monorepo packages - after this, you can use `pnpm run dev` to rebuild packages as you modify code 3. Run - `pnpm run test` to run core tests - `pnpm run test:ci` to run all the suite - `cd test/(dir) && pnpm run test` to run a specific test suite > 💡 If you use VS Code, you can hit `⇧ ⌘ B` or `Ctrl + Shift + B` to launch all the necessary dev tasks. ### UI Development If you want to improve Vitest Browser Mode, see the [Browser Mode development guide](./packages/ui/README.md) for setup instructions and development workflow. ## Debugging ### VS Code If you want to use break point and explore code execution you can use the ["Run and debug"](https://code.visualstudio.com/docs/debugtest/debugging) feature from vscode. 1. Add a `debugger` statement where you want to stop the code execution. 2. Click on the "Run and Debug" icon in the activity bar of the editor. 3. Click on the "Javascript Debug Terminal" button. 4. It will open a terminal, then type the test command: `pnpm run test` 5. The execution will stop and you'll use the [Debug toolbar](https://code.visualstudio.com/docs/debugtest/debugging#_debug-actions) to continue, step over, restart the process... ## Testing Vitest against external packages You may wish to test your locally-modified copy of Vitest against another package that is using it. For pnpm, after building Vitest, you can use [`overrides`](https://pnpm.io/settings/dependency-resolution#overrides). Please note that `overrides` must be specified at the root of the project, in `pnpm-workspace.yaml`: ```yaml overrides: vitest: 'link:../path/to/vitest/packages/vitest' ``` You must also first list the package as a dependency in the root `package.json`: ```json { "dependencies": { "vitest": "*" } } ``` And re-run `pnpm install` to link the package. Add a `.npmrc` file with following line next to the `package.json`: ```sh VITEST_MODULE_DIRECTORIES=/node_modules/,/packages/ ``` ## Using Unreleased Commits Each commit on the main branch and PRs with a `cr-tracked` label are published to [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new). You can install a specific commit with: ```bash npm i https://pkg.pr.new/vitest@{commit} ``` ## Pull Request Policy The team accepts pull requests only from members of the Vitest team and [approved contributors](https://github.com/vitest-dev/vitest/blob/approved-contributors/APPROVED_CONTRIBUTORS). Any other pull request is closed automatically as soon as it is opened. We know this is unfortunate, and it is not a judgement of your work. The number of pull requests grew beyond what the team can review, and this policy gives maintainers the space to triage and prioritize issues at their own pace. Please describe the bug or the feature in an [issue](https://github.com/vitest-dev/vitest/issues/new/choose) instead, so the team and the community can discuss it first. Your work is not lost: a maintainer can reopen a closed pull request if the team decides to go forward with the change. Maintainers add contributors they trust to the list of approved contributors. ## Pull Request Guidelines - Checkout a topic branch from a base branch, e.g. `main`, and merge back against that branch. - If adding a new feature: - Add accompanying test case. - Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it. - When adding cli options, run `pnpm -C docs run cli-table` to update the cli-generated.md file - If fixing bug: - If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `fix: update entities encoding/decoding (fix #3899)`. - Provide a detailed description of the bug in the PR. Live demo preferred. - Add appropriate test coverage if applicable. - It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging. - Make sure tests pass! - Commit messages must follow the [commit message convention](./.github/commit-convention.md) so that changelogs can be automatically generated. - Use `pnpm run lint:fix` to format files according to the project guidelines. ## AI Contributions Please read our [AI Contribution Policy](./AI_POLICY.md) before using AI tools to contribute to Vitest. Issues and pull requests entirely generated by AI with no human involvement (e.g. by an automated agent) will be labeled "maybe automated" by the maintainers and closed automatically after 1 day unless a real person responds. Pull requests from accounts that are flagged as bots are closed immediately. ## Maintenance Guidelines > The following section is mostly for maintainers who have commit access, but it's helpful to go through if you intend to make non-trivial contributions to the codebase. ### Release Branches Public support ranges are documented in [Releases](./docs/releases.md). This section describes how maintainers map those ranges to Git branches for releases and backports. These names refer to branches, not release tags; release tags always include the full version, for example `v4.1.8`. - `main` is the active development branch for the next release line. - `vN` is the latest maintained minor line for non-main major version `N`. - `vN.M` is an older minor line for major version `N`, kept when that exact minor still needs releases or backports. As a hypothetical example, if `v5.1.2` is the latest Vitest release, and the latest releases for older majors are `v4.1.7` and `v3.2.4`, the branch shape can be: - `main` is the active development branch for `5.1.x`. - `v5.0` is an older minor line for Vitest 5. - `v4` is the latest maintained minor line for Vitest 4, so it is the `4.1.x` line. - `v4.0` is an older minor line for Vitest 4. - `v3` is the latest maintained minor line for Vitest 3, so it is the `3.2.x` line. - `v3.1` and `v3.0` are older minor lines for Vitest 3. The `v5` branch does not exist yet. It will be created from the latest v5 minor only after `main` moves on to a newer release line, such as `6.0.0` or often `6.0.0-beta.x`. For backports, first use the public support policy to decide which version ranges are supported, then map them to branches: - Changes can land as usual on the `main` branch first. - If the fix targets the latest maintained minor of major version `N`, target `vN`. This is the default backport target for a supported non-main major. - If the fix also needs an older maintained minor `N.M`, target `vN.M`. For example, using the hypothetical `v5.1.2` release above, the public support policy covers regular fixes for `5.1.x` and important fixes or security patches for `5.0.x` and `4.1.x`: - fixes for `5.1.x` target `main` - backports to `5.0.x` target `v5.0` - backports to `4.1.x` target `v4` No backport is made to `v3` unless the support policy changes or maintainers decide on an explicit exception. Backport PR titles should include the target branch in a `[backport to x]` marker, for example `fix: [backport to v5.0] ...` or `fix: [backport to v4] ...`. Branch names never include patch versions. #### Documentation Branches The release branches are also linked with the documentation site releases: - `main` is the source for unreleased documentation at . - `release` points to the latest stable release line used for . Stable releases from `main` promote it automatically after publishing. Release managers can also run the [`Promote Stable Docs`](./.github/workflows/promote-docs.yml) workflow to include documentation follow-ups. The workflow only accepts stable, tagged, fast-forward updates, and it is not run for older-line backports. - `vN` branches are used for old major documentation sites. For example, uses `v3`. ### Release process Releases — publishing the npm packages, creating the git release tag, and generating the associated GitHub release — are driven by a pull request and carried out by GitHub Actions, not from a maintainer's machine. The release PR holds the version bump, and merging it kicks off the actual publish. 1. **Prepare the release PR.** Run the [`Prepare Publish`](./.github/workflows/prepare-publish.yml) workflow with two inputs: - `target_branch` — the branch matching the [release branch](#release-branches) convention for the release line. The Actions menu's separate "Use workflow from" selector should point at the same branch, to keep the workflow definition and release target aligned. - `release` or `version` — the version bump. The default `release: next` bumps to the next patch for stable releases (`4.1.2 -> 4.1.3`), or the next prerelease when already on one (`4.2.0-beta.2 -> 4.2.0-beta.3`). Otherwise set `release` to a specific bump type, or pass an exact `version` for pre-releases. The workflow pushes the bump to a branch and opens the release PR. To preview what a `release` input resolves to, run `pnpm release` locally first — it lets you browse release types and versions interactively (cancel before confirming so nothing is committed). 2. **Review and merge the PR.** Check the version bump, then merge so the `chore: release v*` commit lands on the release branch — that commit is what triggers publishing. 3. **Approve the publish workflow.** Merging triggers the [`Publish Package`](./.github/workflows/publish.yml) workflow, which builds the packages and then pauses for `Release` environment approval. Open the workflow run in GitHub Actions and approve the `Release` environment deployment; the workflow then stages the packages on npm, pushes the release tag, generates the GitHub release, and promotes stable documentation released from `main`. 4. **Approve the npm staged publish.** Review the staged packages on npm, then approve them with 2FA so the release becomes installable. Afterwards, confirm npm, the tag, and the GitHub release all look right. ### Release Protections A few settings outside this repository guard the release process above: GitHub rulesets that keep release branches and tags from being changed by hand, a `Release` environment that requires a maintainer to approve each publish, and npm settings that decide how packages are published. - **Protect releases** — branch ruleset on `main` and the `v*` lines, so release branches only change through reviewed pull requests. - required pull request with at least one approval, stale approvals dismissed on push; the reviewed PR merge is the single auditable entry point for changes to a release line. - squash-only merges; keeps release-branch history to one commit per PR, so `chore: release v*` lands as a clean, identifiable trigger commit. - force-push and branch deletion blocked; release history cannot be silently rewritten or dropped. - code scanning must pass; workflow-security findings block the merge before they can reach a release branch. - **Protect tags** — tag ruleset on the `v*` release tags, so a tag always maps to a real publish run. - manual creation, update, and deletion blocked; nobody can hand-craft or move a release tag. - only the [`vitest-release-bot`](https://github.com/organizations/vitest-dev/settings/apps/vitest-release-bot) GitHub App may bypass; the publish workflow is the sole way a `v*` tag gets pushed. - **Release environment** — deployment gate on the [`Publish Package`](./.github/workflows/publish.yml) workflow, so a human approves each publish. - required reviewer; publishing pauses until a maintainer approves the `Release` environment deployment. - self-review disabled; the maintainer who triggered the release cannot approve their own publish. - deployment restricted to `main` and the `v*` branches; a publish can only run from a real release branch, never from an arbitrary or feature branch. - **release-bot environment** — holds the `vitest-release-bot` credentials for [`Prepare Publish`](./.github/workflows/prepare-publish.yml) and [`Promote Stable Docs`](./.github/workflows/promote-docs.yml); the `Release` environment holds its own copy for the tag push. - deployment restricted to `main` and the `v*` branches; a workflow pushed to any other branch cannot use the app, which can bypass the tag ruleset and push to the `release` docs branch. - **npm publishing** — npm settings control how packages are authenticated and released. - trusted publishing (OIDC); each package's trusted publisher on npm pins the source repository (`vitest-dev/vitest`), workflow file (`publish.yml`), and environment (`Release`), so publishes use short-lived tokens from that workflow alone with no long-lived npm token to leak, and they carry provenance attestation automatically so users can trace a package back to the exact workflow run that produced it. - staged publishing; a publish run only stages the packages, and they go live only after a maintainer reviews and approves them on npm with 2FA, so a bad or accidental publish can be discarded before it becomes installable. ### Issue Triaging Workflow ```mermaid flowchart TD start{Followed issue
template?} start --NO--> close1[Close and ask to
follow template] start --YES--> dupe{Is duplicate?} dupe --YES--> close2[Close and point
to duplicate] dupe --NO--> repro{Has proper
reproduction?} repro --NO--> close3[Label: 'needs reproduction'
bot will auto close if no update has been made in 3 days] repro --YES--> real{Is actually a bug?} real --NO--> intended{Is the intended
behaviour?} intended --YES--> explain[Explain and close
point to docs if needed] intended --NO--> open[Keep open for discussion
Remove 'pending triage' label] real --YES--> real2["1. Remove 'pending triage' label
2. Add related feature label if
applicable (e.g. 'feat: browser')
3. Add priority and meta labels (see below)"] real2 --> unusable{Does the
bug make Vitest
unusable?} unusable --YES--> maj{Does the bug
affect the majority
of Vitest users?} maj --YES--> p5[p5: urgent] maj --NO--> p4[p4: important] unusable --NO--> workarounds{Are there
workarounds for
the bug?} workarounds --YES--> p2[p2: edge case
has workaround] workarounds --NO--> p3[p3: minor bug] ``` ### Pull Request Review Workflow ```mermaid flowchart TD start{Bug fix
or
feature} start --BUG FIX--> strict_bug{"Is a 'strict fix'
i.e. fixes an obvious
oversight with no
side effects"} start --FEATURE--> feature[- Discuss feature necessity
- Is this the best way to address the need
- Review code quality
- Add feature labels
- Approve if you feel strongly
that the feature is needed] feature --> merge strict_bug --YES--> strict[- Verify the fix locally
- Review code quality
- Require test case if applicable
- Request changes if necessary] strict_bug --NO--> non_strict[- Discuss the potential side
effects of the fix, e.g.
- Could it introduce implicit
behavior changes in other
cases?
- Does it introduce too much
changes?] non_strict --> label["Add priority labels
(see issue triaging workflow)"] strict --> label label --> approve approve --> merge["Merge if approved by 2 or
more team members
- Use 'Squash and Merge'
- Edit commit message to follow convention
- In commit message body, list relevant issues being fixed
e.g. 'fix #1234, fix #1235'"] ``` ### Pull Request Redirect The [`AI Policy`](./.github/workflows/ai-policy.yml) workflow applies the [pull request policy](#pull-request-policy) when a pull request is opened or reopened. It comments on the pull request, pointing to the linked issues or asking to open a new one, and closes it. It never touches pull requests from members of the `vitest-dev` organization, from repository collaborators, or from apps that push branches to this repository (for example, Renovate). Users with write access to the repository control the rest: - Reopen a pull request to keep it open. The workflow closes it again only if someone without write access reopens it. - Comment `/approve-user` on an issue or a pull request to add its author to the approved contributors. Comment `/approve-user username` to add a specific user. It must be a regular comment, not a review, and it must contain nothing but the command. The [`Approve Contributor`](./.github/workflows/approve-contributor.yml) workflow reacts to it with 🚀 when the user is on the list. - The list is the `APPROVED_CONTRIBUTORS` file on the [`approved-contributors`](https://github.com/vitest-dev/vitest/blob/approved-contributors/APPROVED_CONTRIBUTORS) branch. Each line is an account id followed by the login as a comment, for example `12345 # username`. Only the id counts, so a renamed account stays approved and nobody else can take its place; the login is there for people to read. Delete a line to remove a contributor. Both workflows fail, and no pull request is closed, if the branch or the file is missing. - Run the [`PR Redirect All`](./.github/workflows/pr-redirect-all.yml) workflow manually to close every open pull request that the policy would close. It skips pull requests that a maintainer reopened after they were closed. Keep the `dry-run` option on first to see which pull requests it would close. ## Notes on Dependencies Vitest aims to be lightweight, and this includes being aware of the number of npm dependencies and their size. ### Think before adding a dependency Most deps should be added to `devDependencies` even if they are needed at runtime. Some exceptions are: - Type packages. Example: `@types/*`. - Deps that cannot be properly bundled due to binary files. - Deps that ships its own types and its type is used in vitest's own public types. Avoid deps that has large transitive dependencies that results in bloated size compared to the functionality it provides. If there are libraries that are needed and don't comply with our size requirements, a fork can be tried to reduce its size while we work with them to upstream our changes. ### Think before adding yet another option We already have many config options, and we should avoid fixing an issue by adding yet another one. Before adding an option, try to think about: - Whether the problem is really worth addressing - Whether the problem can be fixed with a smarter default - Whether the problem has workaround using existing options - Whether the problem can be addressed with a plugin instead