What are the dependency scopes in Maven, and what is each one used for?
answer
- compile = default, everywhere, transitive
- provided = compile+test, container supplies it
- runtime = run/test but not compile (JDBC driver)
- test = JUnit only, not packaged
- system+systemPath discouraged; import = BOM only
basics
~20 sMaven has six scopes: compile (default, everywhere), provided (compile/test only, supplied at runtime by the container), runtime (not for compiling, needed to run), test (only for tests), system (like provided but you give a local jar path), and import (only for BOMs in dependencyManagement).
solid answer
~40 sMaven defines six dependency scopes that control when a dependency is on the classpath and whether it is transitive. compile is the default and is available on all classpaths (compile, test, runtime) and is transitive. provided means it is needed to compile and test but the runtime environment (e.g. a servlet container or the JDK) supplies it, so it is not packaged or transitive. runtime is not needed to compile your code but is required to run/test it (e.g. a JDBC driver). test is only on the test compile and execution classpath (e.g. JUnit). system is like provided but you point to a jar with <systemPath>; it is discouraged. import is special: it only applies to a pom-typed dependency inside <dependencyManagement> to pull in a BOM's managed versions.
code
xml · 6 lines<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>go deeper
List all six scopes and give one example per scope.
Map each scope to compile/test/runtime classpaths and state which are packaged/transitive.
Reason about which scope minimizes footprint and coupling, e.g. runtime for drivers, provided for container-supplied APIs.
Set org-wide conventions (no system scope, BOMs via import) and explain scope semantics to teams.
## What a scope is A Maven **dependency scope** answers two questions: (1) on which **classpaths** is this dependency visible — compiling your main code, compiling/running your tests, or running the packaged app — and (2) is it **transitive** (does it flow to projects that depend on yours). A *classpath* is just the set of jars the Java compiler or JVM is allowed to see. Maven builds three of them: the **compile classpath**, the **test classpath**, and the **runtime classpath**. ## The six scopes - **compile** — the default if you omit `<scope>`. Available on all three classpaths and is transitive. Use for normal libraries you call directly (e.g. Guava, Jackson). - **provided** — available to compile and test, but **NOT** packaged into your artifact and **NOT** transitive. You promise the runtime environment will provide it. Classic example: the Servlet API, supplied by Tomcat; or Lombok (compile-time only). - **runtime** — **NOT** on the compile classpath, so you cannot `import` and call it directly, but it IS on the test and runtime classpaths. Classic example: a JDBC driver loaded by name/reflection. - **test** — only on the test compile and test execution classpaths. Not packaged, not transitive. Example: JUnit, Mockito, AssertJ. - **system** — like `provided` but Maven does not look in any repository; you must give an absolute (or property-based) `<systemPath>` to a jar on disk. It is **deprecated/discouraged** because it breaks portability. - **import** — only valid for a dependency of `<type>pom</type>` inside `<dependencyManagement>`. It does not put anything on a classpath; it merges another POM's `<dependencyManagement>` (a **BOM**, Bill Of Materials) into yours so you inherit managed versions. ## Transitive scope narrowing When dependency A pulls in B (a *transitive* dependency), B's effective scope in your project is **narrowed** by a combination table. The key intuition: a transitive dependency is never *wider* than the path that brought it in. - If your direct dependency is **compile** and it brings a **compile** transitive → stays **compile**. - If your direct dependency is **compile** and it brings a **provided** transitive → becomes **none** (omitted). - If your direct dependency is **test** → the transitive is **test** (or omitted). - If your direct dependency is **runtime** and the transitive is **compile** → becomes **runtime**. - **provided** and **system** transitives are essentially never propagated. So `compile -> provided` becomes **none**: you must redeclare it yourself if you need it. ## settings/POM example ```xml <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>33.0.0-jre</version> <!-- scope omitted => compile --> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.7.3</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> </dependencies> ``` You can inspect the effective scopes with `mvn dependency:tree`.
- Which scope is the default?compile — if you omit <scope>, Maven uses compile, which is on all classpaths and is transitive.
- Why use runtime instead of compile for a JDBC driver?You code against the JDBC API (java.sql), not the driver's classes, so it does not need to be on the compile classpath; runtime keeps it off compile but available to run, reducing accidental coupling to driver internals.
Scopes are like backstage passes: compile gets into every area, test only into the rehearsal room, provided gets in but the venue already has its own gear, and import is just a guest list (versions) with no actual seat.
saying these in an interview costs you the question
- Saying there are only four scopes (forgetting system and import).
- Claiming provided dependencies are packaged into the final jar/war — they are not.
- Thinking import puts jars on the classpath; it only imports managed versions from a BOM.