What is the difference between the provided and runtime scopes, and when would you choose each?
answer
- provided: compile+test, NOT packaged, NOT transitive
- runtime: NOT compile, IS test+run, IS packaged
- provided = container/JDK supplies (servlet, lombok)
- runtime = JDBC driver, SLF4J binding
- runtime off compile = enforces abstraction
basics
~20 sprovided is on the compile and test classpaths but NOT packaged or shipped, because something else (a container/JDK) supplies it at runtime. runtime is the opposite: NOT on the compile classpath but available (and packaged) for running and testing.
solid answer
~40 sThey sit on opposite ends. provided means you compile and test against the API but the deployment environment supplies the implementation at runtime, so Maven keeps it off the runtime/packaged classpath and it is not transitive — e.g. the Servlet API in a WAR deployed to Tomcat, or Lombok. runtime means your source never references the type directly (you code to an interface), so it is excluded from the compile classpath to prevent accidental coupling, but it IS on the test and runtime classpaths and IS packaged — e.g. a JDBC driver, a Logback binding behind SLF4J. Choosing correctly keeps the compile surface minimal (catching illegal direct references) and the runtime artifact correct (no missing or duplicated jars). A common mistake is defaulting everything to compile.
code
xml · 6 lines<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.3</version>
<scope>runtime</scope>
</dependency>go deeper
Recall that provided is supplied by the environment and runtime is not needed to compile.
Correctly map both to the classpath table and pick the right scope for servlet API vs JDBC driver.
Justify scope choices in terms of packaging correctness, transitivity, and enforcing abstractions.
Standardize scope usage across modules (e.g. all bindings runtime, all container APIs provided) and review fat-jar/WAR packaging implications.
## The core distinction Both scopes are about **separating what you compile against from what is available at runtime**, but they pull in opposite directions. | Scope | Compile classpath | Test classpath | Runtime/packaged | Transitive | |-------|------------------|----------------|------------------|-----------| | provided | YES | YES | NO | NO | | runtime | NO | YES | YES | YES (narrowed) | ## provided — "someone else brings it" Use `provided` when the **deployment environment already contains the jar** and shipping your own copy would be wrong (duplicate classes, version conflicts). You still need it to *compile* because your code calls its API. - Servlet/JSP API when deploying a WAR to Tomcat/Jetty (the container provides it). - Lombok — a compile-time annotation processor that generates code; nothing of it is needed at runtime. - A library marked `provided` by a parent application when you build a plugin for it. Because it is **not transitive**, downstream consumers must redeclare it. Because it is **not packaged**, it never lands in your jar/war's `WEB-INF/lib`. ## runtime — "needed to run, not to compile" Use `runtime` when your code does **not** reference the dependency's classes directly — it is loaded reflectively, via a service loader, or as an implementation behind an interface you do compile against. - A JDBC driver (`org.postgresql:postgresql`): you code to `java.sql`, the driver is discovered at runtime. - An SLF4J binding such as `logback-classic`: your code uses the SLF4J API (compile), the binding is wired at runtime. Keeping it off the compile classpath is a feature: it makes the compiler **fail** if a developer accidentally imports a driver-specific class, enforcing the abstraction. ## Choosing Ask: *Do I call its types in source?* If no -> probably `runtime`. *Will the environment supply it for me?* If yes -> `provided`. If both no/no, it is plain `compile`. ```xml <!-- compile against API, container supplies impl --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> <!-- never imported in source, needed only to run --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.7.3</version> <scope>runtime</scope> </dependency> ```
- Is a provided dependency included in the final WAR?No. provided is excluded from packaging; the container supplies it, so including it would risk duplicate or conflicting classes.
- Why put a JDBC driver in runtime rather than compile?Your code targets the java.sql API, not driver classes; runtime excludes it from compile so accidental driver-specific imports fail to compile, while it remains available to actually connect at run/test time.
saying these in an interview costs you the question
- Saying provided jars are bundled in the artifact.
- Saying runtime dependencies are available at compile time.
- Treating provided and runtime as interchangeable.