What are the differences between compile, provided, and runtime scopes in Maven?
Table of Contents
- Introduction
- Understanding Maven Dependency Scopes
- Key Differences Between Compile, Provided, and Runtime Scopes
- Practical Examples of Using Each Scope
- Conclusion
Introduction
In Maven, the concept of dependency scopes plays a critical role in defining how and when dependencies are made available during the build lifecycle and at runtime. The three most commonly used scopes are compile, provided, and runtime. Each scope determines the visibility and availability of dependencies during different build phases (e.g., compiling, testing, packaging, runtime). In this article, we'll explore the key differences between these scopes and discuss when to use each one in your Maven projects.
Understanding Maven Dependency Scopes
1. Compile Scope
The compile scope is the default scope for dependencies in Maven. If no scope is specified in the pom.xml
file, Maven treats the dependency as having a compile scope. Dependencies with this scope are available in all phases of the build lifecycle: compilation, testing, packaging, and runtime. These dependencies are included in the final artifact (e.g., JAR, WAR, EAR) because they are necessary for the application to compile and run.
Key Characteristics of Compile Scope:
- Available in compile, test, runtime, and package phases.
- Included in the final artifact (JAR, WAR, etc.).
- The most commonly used scope for dependencies directly needed by the application.
Example Usage:
2. Provided Scope
The provided scope is used when a dependency is required to compile and test the application, but it is provided at runtime by the external environment or container. This is commonly used for dependencies like Servlet API or Java EE APIs, which are already available in the application server or servlet container (e.g., Tomcat, JBoss). Since these dependencies are provided by the runtime environment, they are not included in the final packaged artifact.
Key Characteristics of Provided Scope:
- Available during compile and test phases.
- Not included in the final artifact (e.g., WAR or JAR).
- Assumes the dependency will be provided at runtime by the environment (e.g., servlet container or application server).
Example Usage:
In this example, the Servlet API is typically provided by a web server like Tomcat, so you don't need to include it in the final WAR file.
3. Runtime Scope
The runtime scope is used for dependencies that are not required during compilation but are needed at runtime. These dependencies are necessary for the application to function, but they do not impact the compilation process. For example, a JDBC driver is only required when the application runs and connects to a database, but it is not necessary for compiling the code.
Key Characteristics of Runtime Scope:
- Available during runtime and test phases.
- Not included in the final artifact for compilation.
- Used for dependencies required only at runtime, not during compilation.
Example Usage:
In this case, the PostgreSQL JDBC driver is required at runtime but not during the compilation phase, so it is marked with the runtime scope.
Key Differences Between Compile, Provided, and Runtime Scopes
Scope | Available During | Included in Final Artifact | When to Use |
---|---|---|---|
compile | Compile, Test, Runtime, Package | Yes | Use for dependencies that are needed for compiling, testing, and running the application (e.g., core libraries). |
provided | Compile, Test | No | Use for dependencies that are already provided by the runtime environment (e.g., servlet API, Java EE libraries). |
runtime | Runtime, Test | No | Use for dependencies required only at runtime (e.g., database drivers, logging libraries). |
Practical Examples of Using Each Scope
Example 1: Compile Scope (Spring Core Dependency)
In a Spring-based project, the Spring Core library is required both at compile time and runtime. Therefore, you would use the compile scope:
This dependency will be included in the final JAR or WAR file and will be available throughout the application’s lifecycle.
Example 2: Provided Scope (Servlet API)
If you are building a web application that will be deployed to a servlet container, the Servlet API is already provided by the container (e.g., Tomcat or Jetty). Therefore, you can use the provided scope to ensure it’s available during compilation but excluded from the final artifact:
This prevents the dependency from being bundled into the WAR file, as it will be provided by the servlet container at runtime.
Example 3: Runtime Scope (JDBC Driver)
If your application needs a JDBC driver (e.g., PostgreSQL) to connect to the database, but it is not needed at compile time, you can use the runtime scope:
This ensures that the JDBC driver is available when the application runs but does not clutter the compile-time classpath.
Conclusion
Maven’s dependency scopes—compile, provided, and runtime—are essential tools for managing dependencies effectively during the build lifecycle. Choosing the right scope ensures that your project is optimized for both performance and maintainability.
Summary:
- compile scope: Available throughout all build phases and included in the final artifact.
- provided scope: Available during compile and test phases but not included in the final artifact, as it’s provided by the runtime environment.
- runtime scope: Available at runtime but not required at compile time, and not included in the final artifact for compilation.
By understanding and utilizing these scopes, you can ensure that your Maven project is clean, efficient, and easy to manage