Does Express Work With Vitest?
Express and Vitest work together seamlessly for testing Node.js web applications, with Vitest providing a modern, fast testing experience for Express route handlers, middleware, and business logic.
Quick Facts
How Express Works With Vitest
Express is a server framework and Vitest is a test runner—they operate in different layers and integrate naturally without conflicts. Vitest runs in Node.js and can import and test Express app instances, route handlers, and middleware directly. You create an Express app in your application code, then Vitest imports it and makes HTTP requests using libraries like `supertest` to verify behavior. The developer experience is excellent because Vitest's instant file watching and speed make TDD workflows enjoyable. No special configuration is needed; Vitest's default Node environment works out of the box. The main architecture consideration is keeping your Express app's instantiation separate from server startup—export an app instance that Vitest can import, and start the server separately in your entry point. This pattern is idiomatic and enables testing without port binding conflicts.
Best Use Cases
Quick Setup
npm install express vitest supertest --save-dev// app.js
import express from 'express';
export function createApp() {
const app = express();
app.use(express.json());
app.get('/hello', (req, res) => res.json({ message: 'Hello' }));
app.post('/users', (req, res) => res.status(201).json({ id: 1 }));
return app;
}
// app.test.js
import { describe, it, expect } from 'vitest';
import request from 'supertest';
import { createApp } from './app';
describe('Express App', () => {
it('GET /hello returns greeting', async () => {
const app = createApp();
const res = await request(app).get('/hello');
expect(res.status).toBe(200);
expect(res.body.message).toBe('Hello');
});
it('POST /users creates user', async () => {
const app = createApp();
const res = await request(app).post('/users').send({});
expect(res.status).toBe(201);
expect(res.body.id).toBe(1);
});
});Known Issues & Gotchas
Port conflicts when running multiple test files simultaneously
Fix: Use supertest which handles server lifecycle automatically, or bind to port 0 for ephemeral ports. Avoid calling app.listen() in test files.
Middleware execution order and state leakage between tests
Fix: Create a fresh Express app instance in beforeEach() hooks, or use app.use() only for stateless middleware. Reset global state between tests.
ESM vs CommonJS module format compatibility
Fix: Use type: 'module' in package.json and ESM syntax consistently, or configure Vitest with appropriate resolvers for mixed module systems.
Alternatives
- •Jest + Express: Mature combination with broader ecosystem, but slower test execution
- •Fastify + Vitest: Modern alternative with similar speed advantages if you need higher performance
- •Express + Mocha + Chai: Traditional Node.js testing stack, less ergonomic than Vitest
Resources
Related Compatibility Guides
Explore more compatibility guides