Difference between junit-vintage-engine and junit-jupiter-engine?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
junit-jupiter-engine and junit-vintage-engine are both test engines that run on the JUnit Platform, but they serve different generations of tests. junit-jupiter-engine runs tests written with the JUnit 5 programming model. junit-vintage-engine exists to run older JUnit 3 and JUnit 4 tests on the same platform so projects can migrate gradually.
Understand the JUnit 5 Architecture
JUnit 5 is split into several parts:
- JUnit Platform: the launcher and engine infrastructure
- JUnit Jupiter: the API and engine for modern JUnit 5 tests
- JUnit Vintage: a compatibility engine for older JUnit tests
That architecture explains why these two artifacts are different. They are not competing assertion libraries. They are engine implementations for different test styles.
junit-jupiter-engine Runs Modern JUnit 5 Tests
If you write tests with annotations such as @Test, @BeforeEach, @Nested, @ParameterizedTest, or extensions via @ExtendWith, you are using Jupiter.
To execute that test on the JUnit Platform, the runtime needs junit-jupiter-engine.
In Gradle, that often looks like this:
The API gives you the annotations and assertions at compile time. The engine actually discovers and runs the tests at runtime.
junit-vintage-engine Runs JUnit 3 and 4 Tests
Vintage is for legacy test suites that still use JUnit 3 or JUnit 4 style tests.
To run this kind of test on the JUnit Platform, add Vintage at runtime.
This lets old and new tests run side by side during migration.
Choose Based on the Tests You Actually Have
Use Jupiter when you are writing or maintaining modern JUnit 5 tests. Add Vintage only if the project still contains legacy JUnit 3 or 4 tests that must run on the same platform.
Many teams keep both temporarily during migration, then remove Vintage once the old suite has been rewritten.
That is the usual lifecycle:
- start with legacy JUnit 4 tests
- adopt JUnit Platform in the build
- add Vintage so old tests still run
- add Jupiter for new tests
- remove Vintage once the legacy suite is gone
Do Not Confuse API With Engine
A frequent mistake is adding only junit-jupiter-api and expecting tests to execute. The API provides annotations and assertions, but the runtime still needs the engine. The same idea applies to Vintage: it is the runtime bridge for older tests, not the old JUnit library itself.
Understanding this API-versus-engine split makes build configuration much easier to debug.
Common Pitfalls
- Adding
junit-jupiter-apiwithoutjunit-jupiter-engine, so tests compile but do not run. - Thinking Vintage is for new JUnit 5 tests when it is actually for JUnit 3 and 4 compatibility.
- Keeping Vintage forever after migration is finished, which adds unnecessary legacy support.
- Mixing Jupiter and JUnit 4 annotations in the same test class without understanding which engine will execute it.
- Forgetting to enable the JUnit Platform in the build tool.
Summary
- '
junit-jupiter-engineruns tests written for the JUnit 5 programming model.' - '
junit-vintage-engineruns legacy JUnit 3 and JUnit 4 tests on the JUnit Platform.' - Projects often use both temporarily during migration.
- The API and the engine are different dependencies, and both matter.
- Once legacy tests are gone, Vintage can usually be removed.

