Dependency Scopes in Maven
Introduction
In Maven, managing the scope of dependencies plays a vital role in controlling how and when dependencies are included in your project. Scope defines not only the phase in which a dependency is available but also whether it will be included in the final build artifact. This article explores the six scopes available in Maven and provides examples for each.
What is Dependency Scope?
Dependency scope in Maven specifies the visibility and lifecycle of a dependency within the project. It determines which phases of the build process the dependency is available and whether it will be included in the final packaged application. Scopes help to ensure that dependencies are included appropriately without unnecessary overhead.
For instance:
1
2
3
4
5
6
7
8
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
In this example, the JUnit library is restricted to the test phase and is not included in the final build artifact.
Maven Dependency Scopes
Maven provides several dependency scopes to manage when and how dependencies are included during the build lifecycle. Understanding these scopes will help you configure your project dependencies more effectively.
1. Compile or Default Scope
The compile
scope is the default scope if none is explicitly defined. Dependencies with this scope
are available throughout all phases of the project lifecycle, including compile, test, and runtime.
- When to use: When the dependency is needed both during compilation and runtime.
- Example: A core framework like Spring or Hibernate that is used throughout the entire application lifecycle.
1
2
3
4
5
6
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.8</version>
<scope>compile</scope> <!-- This is implied even if scope is omitted -->
</dependency>
2. Provided Scope
The provided
scope indicates that the dependency is required for compiling and testing but should not be packaged
in the final artifact. This is because the library will be “provided” by the runtime environment,
such as a web container (e.g., Tomcat or Jetty).
- When to use: For libraries that are provided by the container or JDK at runtime, like Servlet API or JSP.
- Example: If your web application relies on the servlet API, which will be supplied by the web server.
1
2
3
4
5
6
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
3. Runtime Scope
Dependencies with the runtime
scope are not required for compiling the code but are needed at runtime.
They are included in the final build and become part of the classpath when the application is executed.
- When to use: For libraries like database drivers that are only needed when the application is running, not during the compilation process.
- Example: JDBC drivers.
1
2
3
4
5
6
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
<scope>runtime</scope>
</dependency>
4. Test Scope
The test
scope limits the dependency to the test phase.
Dependencies with this scope are only included in the classpath when running unit tests.
These dependencies do not appear in the final build.
- When to use: For testing libraries like JUnit and Mockito that are necessary only during the test phase of the project lifecycle.
- Example: JUnit and Mockito for unit testing.
1
2
3
4
5
6
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
5. System Scope
The system
scope behaves similarly to provided
, but with one key difference:
the dependency is not retrieved from a Maven repository but is manually specified as a file on the local filesystem.
- When to use: For dependencies not available in any remote repository and located on the local machine.
- Example: A custom library that exists only in a local directory.
1
2
3
4
5
6
7
<dependency>
<groupId>com.example</groupId>
<artifactId>custom-library</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/custom-library.jar</systemPath>
</dependency>
6. Import Scope
The import
scope is used exclusively with dependencies of type pom
.
This scope allows Maven to import the dependencies from another Maven project,
typically when working with a BOM
(Bill of Materials) file.
This is most often used in large multi-module projects or to manage version consistency across multiple projects.
- When to use: For importing dependency management from a parent project or a predefined BOM.
- Example: Importing a Spring Boot BOM to manage versions.
1
2
3
4
5
6
7
8
9
10
11
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Conclusion
Understanding and using the right scope in Maven ensures that dependencies are correctly included
or excluded at different phases of your project. It helps optimize the build process,
reduces the risk of bloated artifacts, and keeps the classpath organized.
By defining scopes like compile
, provided
, runtime
, test
, system
, and import
,
you can efficiently manage how dependencies are used and included in your Maven project.