A Complete Guide to Vitest Global Setup and Teardown
By Ben Houston, 5 Minutes Read, 2025-11-19
When writing tests with Vitest, you often need to perform setup tasks before all tests run and cleanup tasks after all tests complete. This is where Vitest's globalSetup feature comes in handy. This guide will walk you through everything you need to know about setting up global test initialization and teardown. It has been tested on vitest 2.x to 4.x.
What is Global Setup?
Global setup allows you to run code once before all your tests execute, and optionally return a cleanup function that runs after all tests complete. This is perfect for:
- Setting up database connections
- Configuring environment variables
- Starting test servers
- Initializing shared resources
- Any one-time setup that all tests need
Setting Up the Global Setup File
Create a file that exports a default async function. This function will be called by Vitest before any tests run. The function receives a TestProject parameter that provides access to Vitest's project configuration.
Basic Structure
// src/test-utils/beforeTests.ts import type { TestProject } from 'vitest/node'; export default async function setup(project: TestProject): Promise<void> { console.log("Starting global setup for project:", project.name); // Your setup code here console.log("Global setup complete!"); }
With Cleanup Function
The setup function can return a cleanup function that will be executed after all tests complete:
// src/test-utils/beforeTests.ts import type { TestProject } from 'vitest/node'; import afterTests from "./afterTests.js"; // the method name doesn't matter, just that it is the default export export default async function beforeTests(project: TestProject): Promise<() => Promise<void>> { console.log("starting beforeTests for project:", project.name); // Perform setup tasks await new Promise((resolve) => setTimeout(resolve, 1000)); console.log("finished beforeTests"); // Return cleanup function that runs after all tests return afterTests; }
The Teardown File
Create a separate file for your cleanup logic (or you could combine it with the setup file):
// src/test-utils/afterTests.ts export default async function afterTests(): Promise<void> { console.log("starting afterTests"); // Perform cleanup tasks await new Promise((resolve) => setTimeout(resolve, 1000)); console.log("finished afterTests"); }
Configuring Vitest
Add the globalSetup option to your vitest.config.ts:
// vitest.config.ts import { defineConfig } from "vitest/config"; export default defineConfig({ test: { globals: true, environment: "node", globalSetup: ["./src/test-utils/beforeTests.ts"], }, });
The globalSetup option accepts an array of file paths. Vitest will execute these files in order before all tests run. If a setup file returns a cleanup function, Vitest will call it after all tests complete (cleanup functions are called in reverse order).
Passing Configuration to Tests
One of the most common use cases for global setup is configuring environment variables or other values that your tests need. The simplest way to do this is using process.env:
// src/test-utils/beforeTests.ts import type { TestProject } from 'vitest/node'; export default async function setup(project: TestProject): Promise<() => Promise<void>> { console.log("Starting global setup for project:", project.name); // Set environment variables that tests can access const DATABASE_URL = 'postgresql://localhost:5432/test'; process.env['DATABASE_URL'] = DATABASE_URL; console.log('DATABASE_URL', DATABASE_URL); // Set other configuration values process.env['API_KEY'] = 'test-api-key'; process.env['NODE_ENV'] = 'test'; // Your setup code here await new Promise((resolve) => setTimeout(resolve, 1000)); console.log("Global setup complete!"); return async () => { // Cleanup: optionally clear environment variables console.log("Cleanup complete!"); }; }
Using Configuration in Tests
Your tests can now access these environment variables:
// src/database.test.ts import { describe, it, expect } from "vitest"; describe("Database", () => { it("should connect using DATABASE_URL", () => { const dbUrl = process.env['DATABASE_URL']; expect(dbUrl).toBe('postgresql://localhost:5432/test'); // Use dbUrl in your test... }); });
Common Use Cases
Database Setup
export default async function setup(): Promise<() => Promise<void>> { // Connect to test database const db = await connectToDatabase(); process.env['DATABASE_URL'] = db.connectionString; // Run migrations await db.migrate(); return async () => { // Clean up test data await db.cleanup(); await db.close(); }; }
API Server Setup
export default async function setup(): Promise<() => Promise<void>> { // Start test server const server = await startTestServer(); process.env['API_URL'] = `http://localhost:${server.port}`; return async () => { // Stop server await server.stop(); }; }
Environment Configuration
export default async function setup(): Promise<() => Promise<void>> { // Set all test environment variables process.env['NODE_ENV'] = 'test'; process.env['LOG_LEVEL'] = 'error'; process.env['API_TIMEOUT'] = '5000'; return async () => { // Optionally restore original values delete process.env['NODE_ENV']; }; }
Conclusion
Vitest's globalSetup feature provides a clean and powerful way to handle one-time setup and teardown for your test suite. By following the patterns outlined in this guide, you can:
- Set up shared resources before tests run
- Configure environment variables for all tests
- Clean up resources after tests complete
- Keep your test code focused and maintainable
The key pattern is: export a default async function that optionally returns a cleanup function. Vitest handles the rest!