Here are some use cases the we leverage 'provided' for:
We have the 'provided' conf set up in the Ivy default way. It is like 'compile', but 'runtime' does not inherit from it. When we setup the javac classpath for compiling, we include all jars from 'compile' and from 'provided'.
In use, there are 3 cases where we find it helpful:
1) When you have an API library that a module needs to compile against, but whose implementation may be provided by a totally different jar at runtime, either by the app in its war, or by the app container. Some examples of this might be servlet-api, ojdbc, etc.
2) Provided also gives you a way of having a general non-transitive compile-time conf. This is useful, for example, if your library needs a jar to compile against, but you know that downstream builds won't need it implicitly. For example, for compile-time-only annotation processing, or other compiler helper libs.
3) Another use case is for libraries that provide optional services, where each optional service requires runtime support only if it is enabled. The final app build gets to decide which services it will want, and adds the runtime conf on those in its build. This allows the apps to opt-in to these services, instead of the war task's (unmaintainable) approach of requiring apps to opt-out or suppress dependencies that they don't want.
A variation of the 3rd item is when you have giant fat 3rd party libraries like wlfullclient that bundle both the APIs needed for compiling and a bloated runtime that you might not actually need. Using 'provided' on these allows them to be skipped by apps that don't need them.