Ivy: Overview

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against Apache Ivy 2.6.0 (announced on 15 July 2026) running inside Apache Ant 1.10.18. Every example marked as run was executed on JDK 26 on 2026-10-16, on macOS, in a scratch directory with its own Ivy cache; output that comes from a run is shown as printed, with the long scratch path shortened to <scratch>, the home directory to <home> and the machine name to <host>. Anything that could not be run here is labelled "not run here". The commands use a POSIX shell.

Ant has no idea what a dependency is. It compiles, copies and packages whatever sits in directories you name, and the JARs those directories need have to get there some other way: checked into version control, copied by hand, or fetched by a get task from a fixed URL. Ivy is the answer the Ant project itself gives to that gap. It is a dependency manager that runs inside Ant (and also on its own from the command line): given a description of what a module needs, it finds those modules in one or more repositories, follows their own dependencies, decides which revision wins when two parts of the graph disagree, downloads the files into a local cache and hands them to the build as a classpath or a directory of JARs. This page is the first of six on Ivy. It covers what Ivy is, how it is installed, and a complete first run; the other five go deep on each part, and are linked where they apply: module descriptors and configurations, settings and resolvers, conflicts and versions, the Ant tasks and publishing and multi-project builds. The other Ant dependency tool, the Resolver Ant Tasks that wrap Maven’s own resolver, has its own page: Maven Resolver Ant Tasks. The language-neutral ideas (coordinates, scopes, transitivity, mediation) are in Dependency Management Fundamentals. The running scenario (tidepool) is described on the section landing page.

What Ivy is, and its status

Ivy describes itself as a tool for managing (recording, tracking, resolving and reporting) project dependencies, characterized by flexibility and configurability and by tight integration with Ant. Three properties follow from that and shape everything else:

  • It is process agnostic. Nothing in Ivy says where files live, how modules are named in a repository, or what a build looks like. Those are settings you provide (or accept from the default settings that ship inside the JAR, which look like Maven Central).

  • It reads Maven metadata. A POM in a repository is a module descriptor to Ivy, so the whole of Maven Central is usable without any conversion. That is what makes the first example below work with no repository configuration at all.

  • Its model is richer than Maven’s scopes. A module can define any number of named configurations (views of itself), and every dependency says which configuration of the other module it needs in which of its own. That is the subject of the next page; this page only introduces the word.

As of the date of this page Ivy is an active subproject of Apache Ant, not in the Attic, and 2.6.0 is the current release. The facts worth knowing before adopting it:

  • Java. Ivy 2.6.0 needs Java 8 or later (the compatibility page gives the floors of every line, reproduced in the table below). Ivy does not require any particular Ant version beyond one that runs on that Java.

  • Not thread-safe. The compatibility page states that Ivy does not support multithreaded use and so should not be used with the Ant <parallel> task. Parallel builds that each run Ivy in a separate JVM are fine; two Ivy resolves inside one JVM are not.

  • IvyDE is archived. The Eclipse plugin, IvyDE, was archived by an Ant PMC vote: its home page says all resources are read only and no further development will be done. Ivy itself is unaffected. IDE support for Ivy-managed projects today means importing the resolved JARs, as the CI & IDE Integration page describes.

  • Security. The 2.6.0 release fixes CVE-2026-26032, a path traversal in the PackagerResolver, reachable only by someone able to add coordinates containing ../ to a packager repository. The release notes also say that if you resolved with a version before 2.6.0, you may need to remove your Ivy cache for some of the fixes to take effect. Earlier advisories (CVE-2022-37865, CVE-2022-37866, CVE-2022-46751) are listed on the same security page.

  • A new conflict manager. 2.6.0 added nearest, which resolves conflicts the way Maven does. The default stays latest-revision. Conflicts are the subject of their own page.

Release history

Ivy was created at Jayasoft and donated to the ASF: the software grant was received on 7 November 2006, the first Apache release (2.0.0-alpha1-incubating) came out on 26 April 2007, and Ivy graduated as a subproject of Ant in October 2007. The documentation you read for 2.x was migrated from the old Jayasoft site. The table lists the final releases; each line also had release candidates (for instance 2.5.0-rc1 in April 2018) that are not listed.

Release Announced What matters

2.0.0

2009-01-20

First final 2.x. Settings files renamed from ivyconf.xml to ivysettings.xml; override, exclude and conflict elements in ivy.xml.

2.1.0

2009-10-08

Final release of the 2.1 line (release candidates in March and July 2009).

2.2.0

2010-09-30

extends in info (descriptor inheritance); defaultconf and defaultconfmapping usable together.

2.3.0

2013-01-21

Last line that runs on Java 1.4.

2.4.0

2014-12-26

Needs Java 5.

2.5.0

2019-10-24

Needs Java 7; attributes inherited through extends added on delivery.

2.5.1

2022-11-04

Needs Java 8. Fixes CVE-2022-37865 and CVE-2022-37866 (file creation and path traversal).

2.5.2

2023-08-20

Fixes CVE-2022-46751 (XML external entity injection).

2.5.3

2024-12-23

No security fix listed on the security page.

2.6.0

2026-07-15

nearest conflict manager; override honoured by retrieve; deliver merges extension namespaces; CVE-2026-26032 fixed. The Ant news item for it is dated 14 July.

The "what matters" column is taken from the reference pages (their "since 2.x" remarks), the 2.6.0 release notes and the security page, all cited under the tables. The Maven Central listing of org.apache.ivy:ivy has exactly these versions plus the 2.0.0 betas and the release candidates, with 2.6.0 as latest and release.

Ivy line Minimum Java to run it

up to 2.3.x

Java 1.4

2.4.0

Java 5

2.5.0

Java 7

2.5.1 and later, including 2.6.0

Java 8

Ivy 2.6.0 has no Java ceiling documented; it ran on JDK 26 for every example on this page. Which JDK your builds target is a different question and is decided by the javac task, as the Compiling Java page explains.

Terminology

Ivy has a small vocabulary and uses it strictly; the reference pages and every error message assume it. The table maps each word to its Maven and Gradle counterpart, because that is the translation you will do in your head most often.

Ivy term Meaning Maven Gradle

organisation

The group that produces a module (flat name, usually an inverted domain).

groupId

group

module

A reusable unit with a chain of revisions.

artifactId

name

revision

One delivered state of a module: release, milestone, integration build.

version

version

branch

A line of development of a module; the trunk is also a branch. Optional.

none

none

status

How stable a revision is: integration, milestone or release by default (configurable).

none (the -SNAPSHOT suffix is the nearest idea)

status of a component (integration or release), used by latest.* selectors

module descriptor

The file that identifies a revision and lists its artifacts, configurations and dependencies: ivy.xml, or a POM.

pom.xml

.module file (Gradle Module Metadata), POM or ivy.xml

artifact

One file published with a revision (a JAR, a source ZIP, a signature).

artifact (type and classifier)

artifact (type and classifier)

type, extension

The purpose of an artifact (jar, source, doc) and its file name extension.

type (jar, pom) and classifier

type, extension and classifier

configuration

A view of a module: a named set of artifacts and dependencies for one way of using or building it.

scope (a fixed list)

configuration, variant

settings

The ivysettings.xml file saying where modules are found and how.

settings.xml

settings.gradle(.kts) and init scripts

repository

A location holding descriptors and artifacts, reached by a resolver.

repository

repository

Ivy writes a module coordinate as organisation#module;revision, which is what you see in every log line (io.tidepool#tidepool-engine;1.0.0). Maven writes the same thing as groupId:artifactId:version. In Ivy the pieces after the revision (branch, artifact type, extension) are separate attributes, not part of the coordinate string. The cross-tool table in Comparing Ant, Maven & Gradle adds the rest of the mapping.

Two differences from Maven are worth stating now because they surprise people. First, a dependency in Ivy is on a module, never on an artifact: you ask for commons-csv;1.14.1 and a mapping between configurations decides which of its files you get (the next page shows how that goes wrong with the default mapping). Second, the status of a revision is a first-class value that dynamic revisions such as latest.release use to choose; Maven has no counterpart.

The principle: configure, resolve, retrieve, report, publish

Every use of Ivy is one or more of five steps. They are the same whether you drive them from Ant tasks, as this page does, or from the command line.

flowchart LR S["configure: settings file or built-in default"] --> R["resolve: ivy.xml plus the resolvers"] R --> C[("Ivy cache: repository cache and resolution cache")] C --> T["retrieve: copy the JARs to a directory"] C --> P["cachepath: build a classpath from the cache"] C --> RP["report: HTML and GraphML"] R -.-> PB["publish: deliver ivy.xml and artifacts to a repository"]
  • Configure. Ivy needs a set of dependency resolvers, each able to find descriptors and artifacts given organisation, module, revision, artifact name, type and extension, and a rule saying which resolver serves which module. That is the settings file. When you give none, Ivy uses a built-in default that points an ibiblio resolver at Maven Central (details below). The settings and resolvers page covers everything you can put there.

  • Resolve. The resolve is the moment Ivy actually works out the dependencies of one module. It reads the module’s ivy.xml, asks the resolvers for each dependency’s descriptor, goes through the transitive graph depth first, applies conflict management while it goes so that a losing branch is never downloaded, and finally downloads the artifacts of the winners into the cache. It then writes an XML report per configuration, so that later steps do not walk the graph again. Resolve is also where dynamic revisions such as 1.+ become fixed ones.

  • Retrieve. Copy the resolved artifacts from the cache into a directory structure you choose with a pattern such as build/lib/[conf]/[artifact]-[revision].[ext].

  • Build a path from the cache. Instead of copying, use the files where they are: cachepath turns the resolve report into an Ant path. This is what you want for compiling, and what IDE integrations do. cachefileset does the same as a fileset.

  • Report. An XSL transformation of the resolve report gives an HTML page (and a GraphML file for graph tools) of who needed what.

  • Publish. Deliver a version of your own module, a resolved ivy.xml plus its artifacts, into a repository so others can depend on it. That is the subject of the publishing page; the dashed arrow in the figure marks that it is a separate step that starts from the same module, not part of a dependency resolve.

Installing Ivy

Ivy is one JAR, ivy-2.6.0.jar, 1,413,973 bytes, 889 entries, published as org.apache.ivy:ivy:2.6.0 on Maven Central. Its only job at install time is to be on Ant’s classpath so that the antlib:org.apache.ivy.ant tasks exist. The JAR has optional dependencies, such as Apache HttpClient and Jsch (the compatibility page names both) and Commons Compress for pack200 (the 2.6.0 release notes); their versions are in Ivy’s own descriptor, and you add them only when you use the feature that needs them.

Getting the JAR from Maven Central

mkdir -p lib
curl -fsSL -o lib/ivy-2.6.0.jar https://repo1.maven.org/maven2/org/apache/ivy/ivy/2.6.0/ivy-2.6.0.jar
curl -fsSL https://repo1.maven.org/maven2/org/apache/ivy/ivy/2.6.0/ivy-2.6.0.jar.sha1
shasum -a 1 lib/ivy-2.6.0.jar

Run here, the two digests are the same:

11a76d2e1d439170c61b47a7a13110a78c6c0824
11a76d2e1d439170c61b47a7a13110a78c6c0824  lib/ivy-2.6.0.jar

Central also serves an .asc PGP signature next to the JAR (it answers HTTP 200); checking it needs the Apache KEYS file and is not run here. The Ivy download page offers three distributions, each as a ZIP and a tar.gz with a PGP signature, a SHA-512 digest and a CycloneDX SBOM: bin, bin-with-deps (which adds the optional dependencies) and src. For a build you only need the JAR. The manual installation the documentation describes is "copy the JAR into ANT_HOME/lib", which works but ties every build on the machine to one Ivy version. The three ways below keep the version in the project instead.

Three ways to put the tasks on Ant’s classpath

Way How Use it when

-lib on the command line

ant -lib lib/ivy-2.6.0.jar resolve

One-off runs, CI jobs, and a quick check. The version is explicit in the command.

ANT_HOME/lib or <home>/.ant/lib

Copy the JAR as ivy.jar (any name) into either directory. Ant adds every JAR in both to its classpath.

A developer machine where every project uses the same Ivy. Not reproducible across machines.

taskdef in the build file

<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>, usually after downloading the JAR with get

A build file that must work from a fresh checkout, with the Ivy version stated in the file.

In all three the build file declares the namespace on its root element and then writes every task with the ivy: prefix:

<project name="tidepool-engine" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">

antlib:org.apache.ivy.ant is the Antlib URI: Ant looks for a resource named org/apache/ivy/ant/antlib.xml on its classpath, and the Ivy JAR contains one. Inside it are the declarations of the tasks and types, which is the quickest authoritative list of what the namespace holds:

settings, resources                                   (types)
configure, resolve, retrieve, deliver, publish, extract, cachepath, cachefileset,
report, repreport, var, check, artifactproperty, buildlist, install, convertpom,
makepom, artifactreport, info, addpath, listmodules, findrevision, buildnumber,
cleancache, buildobr, convertmanifest, fixdeps, dependencytree, checkdepsupdate
workspaceresolver                                     (type)

That listing was read from the JAR (unzip -p lib/ivy-2.6.0.jar org/apache/ivy/ant/antlib.xml) and condensed to one line per group; the task pages are in Ivy Ant Tasks. How Ant treats Antlib URIs in general, and how to declare your own, is in Antlibs & Namespaces.

If the tasks are not on the classpath, the first ivy: task fails, and the message tells you where Ant looked:

Buildfile: <scratch>/c/build.xml

resolve:

BUILD FAILED
<scratch>/c/build.xml:3: Problem: failed to create task or type antlib:org.apache.ivy.ant:resolve
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
No types or tasks have been defined in this namespace yet

This appears to be an antlib declaration.
Action: Check that the implementing library exists in one of:
        -<scratch>/tools/apache-ant-1.10.18/lib
        -<home>/.ant/lib
        -a directory added on the command line with the -lib argument

Total time: 0 seconds

This is by far the most common Ivy installation problem, and the three directories in the message are exactly the three ways above.

Letting the build file fetch Ivy

The documentation’s "automatic" installation is a self-contained snippet: download the JAR once into a directory under the user’s home, then taskdef from there. Its pinned version in the documentation is 2.5.0, which is out of date; below it is set to 2.6.0. This is the complete build file used for the compile example later on this page, so it is shown whole:

<project name="tidepool-engine" default="compile" xmlns:ivy="antlib:org.apache.ivy.ant">
  <property name="ivy.install.version" value="2.6.0"/>
  <condition property="ivy.home" value="${env.IVY_HOME}">
    <isset property="env.IVY_HOME"/>
  </condition>
  <property name="ivy.home" value="${user.home}/.ant"/>
  <property name="ivy.jar.dir" value="${ivy.home}/lib"/>
  <property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar"/>

  <target name="download-ivy" unless="offline">
    <mkdir dir="${ivy.jar.dir}"/>
    <get src="https://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
         dest="${ivy.jar.file}" usetimestamp="true"/>
  </target>

  <target name="init-ivy" depends="download-ivy">
    <path id="ivy.lib.path">
      <fileset dir="${ivy.jar.dir}" includes="*.jar"/>
    </path>
    <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
  </target>

  <target name="resolve" depends="init-ivy" description="resolve the dependencies">
    <ivy:resolve/>
  </target>

  <target name="compile" depends="resolve" description="compile the model and the engine">
    <ivy:cachepath pathid="compile.classpath" conf="compile"/>
    <mkdir dir="build/classes"/>
    <javac destdir="build/classes" release="21" includeantruntime="false" classpathref="compile.classpath">
      <src path="src/model"/>
      <src path="src/engine"/>
    </javac>
    <pathconvert property="cp.names" refid="compile.classpath" pathsep=" ">
      <mapper type="flatten"/>
    </pathconvert>
    <echo message="compiled against: ${cp.names}"/>
  </target>

  <target name="report" depends="resolve" description="write the HTML resolve reports">
    <ivy:report todir="build/report"/>
  </target>
</project>

How it works, line by line: ivy.home is IVY_HOME if that environment variable is set and <home>/.ant otherwise (the condition sets it only when the variable exists, and the later property is then ignored because properties are immutable). download-ivy fetches the JAR with get and usetimestamp, so it is downloaded again only when Maven Central has a newer file; -Doffline=true skips it through unless. init-ivy builds a path from every JAR in that directory and taskdef`s the Antlib resource under the Antlib URI. Because `<home>/.ant/lib is also one of the directories Ant puts on its own classpath, a JAR downloaded by the first run is picked up automatically by later runs; the explicit taskdef is what makes the first run work. For the run below the property ivy.home was set on the command line to a directory inside the scratch area, so that nothing is written outside it. The source tree is the tidepool model and engine source copied into src/model and src/engine; the ivy.xml is the one in the next section.

$ ant -Divy.home=<scratch>/ivyhome
Buildfile: <scratch>/b/build.xml

download-ivy:
    [mkdir] Created dir: <scratch>/ivyhome/lib
      [get] Getting: https://repo1.maven.org/maven2/org/apache/ivy/ivy/2.6.0/ivy-2.6.0.jar
      [get] To: <scratch>/ivyhome/lib/ivy.jar

init-ivy:

resolve:
[ivy:resolve] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::
[ivy:resolve] :: loading settings :: url = jar:file:<scratch>/ivyhome/lib/ivy.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:resolve] :: resolving dependencies :: io.tidepool#tidepool-engine;1.0.0
[ivy:resolve] 	confs: [compile, runtime]
[ivy:resolve] 	found org.apache.commons#commons-csv;1.14.1 in public
[ivy:resolve] 	found commons-io#commons-io;2.20.0 in public
[ivy:resolve] 	found commons-codec#commons-codec;1.19.0 in public
[ivy:resolve] :: resolution report :: resolve 42ms :: artifacts dl 2ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      compile     |   3   |   0   |   0   |   0   ||   3   |   0   |
	|      runtime     |   3   |   0   |   0   |   0   ||   3   |   0   |
	---------------------------------------------------------------------

compile:
    [mkdir] Created dir: <scratch>/b/build/classes
    [javac] Compiling 6 source files to <scratch>/b/build/classes
     [echo] compiled against: commons-csv-1.14.1.jar commons-io-2.20.0.jar commons-codec-1.19.0.jar

BUILD SUCCESSFUL
Total time: 0 seconds

(The Ivy cache was already warm from the example in the next section, which is why the resolution report shows nothing downloaded. A cold run is shown there.) Ivy printed its version and build stamp (2.6.0 - 20260712075753, the time the JAR was built) and then loaded the settings from inside its own JAR, which is the built-in default. The javac compiled six files against the three JARs Ivy had put on the path. report turns the resolution into HTML:

report:
[ivy:report] Processing <scratch>/ivyuser/cache/io.tidepool-tidepool-engine-compile.xml to <scratch>/b/build/report/io.tidepool-tidepool-engine-compile.html
[ivy:report] Processing <scratch>/ivyuser/cache/io.tidepool-tidepool-engine-runtime.xml to <scratch>/b/build/report/io.tidepool-tidepool-engine-runtime.html
[ivy:report] Processing <scratch>/ivyuser/cache/io.tidepool-tidepool-engine-compile.xml to <scratch>/b/build/report/io.tidepool-tidepool-engine-compile.graphml
[ivy:report] Processing <scratch>/ivyuser/cache/io.tidepool-tidepool-engine-runtime.xml to <scratch>/b/build/report/io.tidepool-tidepool-engine-runtime.graphml

The .html files open in a browser (with ivy-report.css next to them); the .graphml files open in a graph editor such as yEd. Both are generated from the per-configuration XML files that resolve wrote into the cache, which are shown below.

Source: Ant manual: Get

Running Ivy without Ant

The JAR also has a main class, so Ivy can resolve a descriptor without any build file. It is useful to check a descriptor or to print a version:

$ java -cp lib/ivy-2.6.0.jar org.apache.ivy.Main -version
Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/
$ java -Divy.default.ivy.user.dir=<scratch>/ivyuser -jar lib/ivy-2.6.0.jar -ivy a/ivy.xml -confs compile
:: loading settings :: url = jar:file:<scratch>/lib/ivy-2.6.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
:: resolving dependencies :: io.tidepool#tidepool-engine;1.0.0
	confs: [compile]
	found org.apache.commons#commons-csv;1.14.1 in public
	found commons-io#commons-io;2.20.0 in public
	found commons-codec#commons-codec;1.19.0 in public
:: resolution report :: resolve 53ms :: artifacts dl 2ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      compile     |   3   |   0   |   0   |   0   ||   3   |   0   |
	---------------------------------------------------------------------

The rest of this page stays with Ant, because the point of Ivy on this site is to give Ant builds dependency management.

A first resolve and retrieve

The smallest useful Ivy project is two files. ivy.xml says what the tidepool engine module needs; build.xml runs resolve and retrieve.

<ivy-module version="2.0">
  <info organisation="io.tidepool" module="tidepool-engine" revision="1.0.0"/>
  <configurations>
    <conf name="compile" description="needed to compile"/>
    <conf name="runtime" extends="compile" description="needed to run"/>
  </configurations>
  <dependencies>
    <dependency org="org.apache.commons" name="commons-csv" rev="1.14.1" conf="compile->default"/>
  </dependencies>
</ivy-module>
<project name="tidepool-engine" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
  <target name="resolve" description="resolve and retrieve the dependencies">
    <ivy:resolve/>
    <ivy:retrieve pattern="build/lib/[conf]/[artifact]-[revision].[ext]"/>
  </target>
</project>

Reading ivy.xml: info identifies the module (organisation, module, revision). configurations declares two views of it; runtime extends compile, which means everything required in compile is also required in runtime. The one dependency is commons-csv at an exact revision, and conf="compile->default" reads "in my compile configuration I need the default configuration of that module". Because the Maven POM of commons-csv is converted to Ivy configurations on the fly, default there means its own JAR plus its runtime dependencies. The ivy:resolve task with no attributes reads ivy.xml from the project directory, and ivy:retrieve copies into the pattern, where [conf], [artifact], [revision] and [ext] are tokens Ivy replaces. The next page, Ivy: Module Descriptors & Configurations, explains every part of that file.

The first run, with an empty cache, using the JAR from -lib:

$ ant -lib lib/ivy-2.6.0.jar
Buildfile: <scratch>/a/build.xml

resolve:
[ivy:resolve] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::
[ivy:resolve] :: loading settings :: url = jar:file:<scratch>/lib/ivy-2.6.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:resolve] :: resolving dependencies :: io.tidepool#tidepool-engine;1.0.0
[ivy:resolve] 	confs: [compile, runtime]
[ivy:resolve] 	found org.apache.commons#commons-csv;1.14.1 in public
[ivy:resolve] 	found commons-io#commons-io;2.20.0 in public
[ivy:resolve] 	found commons-codec#commons-codec;1.19.0 in public
[ivy:resolve] downloading https://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.jar ...
[ivy:resolve] ............... (59kB)
[ivy:resolve] .. (0kB)
[ivy:resolve] 	[SUCCESSFUL ] org.apache.commons#commons-csv;1.14.1!commons-csv.jar (123ms)
[ivy:resolve] downloading https://repo1.maven.org/maven2/commons-io/commons-io/2.20.0/commons-io-2.20.0.jar ...
[ivy:resolve] ...................................... (550kB)
[ivy:resolve] .. (0kB)
[ivy:resolve] 	[SUCCESSFUL ] commons-io#commons-io;2.20.0!commons-io.jar (166ms)
[ivy:resolve] downloading https://repo1.maven.org/maven2/commons-codec/commons-codec/1.19.0/commons-codec-1.19.0.jar ...
[ivy:resolve] ........................ (365kB)
[ivy:resolve] .. (0kB)
[ivy:resolve] 	[SUCCESSFUL ] commons-codec#commons-codec;1.19.0!commons-codec.jar (125ms)
[ivy:resolve] :: resolution report :: resolve 1563ms :: artifacts dl 419ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      compile     |   3   |   3   |   3   |   0   ||   3   |   3   |
	|      runtime     |   3   |   3   |   3   |   0   ||   3   |   3   |
	---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: io.tidepool#tidepool-engine
[ivy:retrieve] 	confs: [compile, runtime]
[ivy:retrieve] 	6 artifacts copied, 0 already retrieved (1952kB/5ms)

BUILD SUCCESSFUL
Total time: 2 seconds

Reading the output, in order:

  • loading settings :: url = jar:file:...!/org/apache/ivy/core/settings/ivysettings.xml means no settings were configured, so Ivy loaded its built-in default from inside the JAR. When a project has its own ivysettings.xml this line says file = ... instead.

  • resolving dependencies :: io.tidepool#tidepool-engine;1.0.0 and confs: [compile, runtime]: the module and the configurations being resolved. With no conf attribute, resolve takes every configuration.

  • found ... in public: for each module in the graph, the descriptor was found by the resolver named public, which is the ibiblio resolver for Maven Central in the default settings. There are three found lines for one declared dependency: commons-csv brought in commons-io and commons-codec.

  • downloading ... followed by dots and a size: the artifact download, one dot per chunk. Only now, after the whole graph and the conflict decisions, does Ivy download JARs. The descriptor (the POM) of each module was fetched during the found step, and the parent POMs and BOM imports it needed were fetched silently (they are visible in the cache listing below).

  • The resolution report. One row per configuration. modules number is how many modules are in that configuration; search how many required a repository lookup; dwnlded how many descriptors or artifacts were downloaded; evicted how many lost a conflict; artifacts number and dwnlded the files. Both configurations have three modules because runtime extends compile.

  • retrieve: six artifacts were copied, three modules for each of the two configurations.

The second run changes only the report; nothing is downloaded and retrieve finds the files already in place:

[ivy:resolve] :: resolution report :: resolve 43ms :: artifacts dl 2ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      compile     |   3   |   0   |   0   |   0   ||   3   |   0   |
	|      runtime     |   3   |   0   |   0   |   0   ||   3   |   0   |
	---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: io.tidepool#tidepool-engine
[ivy:retrieve] 	confs: [compile, runtime]
[ivy:retrieve] 	0 artifacts copied, 6 already retrieved (0kB/2ms)

Only the resolve and retrieve lines of the second run are shown; the banner and found lines are the same as before. That speed (43 ms instead of 1.5 s) is the cache. Ivy assumes by default that a revision never changes, so once it has a descriptor and its artifacts in the cache it does not query the repository at all. The exceptions (dynamic revisions, changing revisions, resolvers with checkmodified) are on the conflicts and versions page.

What retrieve created, with the pattern build/lib/[conf]/[artifact]-[revision].[ext]:

build/lib/compile/commons-codec-1.19.0.jar
build/lib/compile/commons-csv-1.14.1.jar
build/lib/compile/commons-io-2.20.0.jar
build/lib/runtime/commons-codec-1.19.0.jar
build/lib/runtime/commons-csv-1.14.1.jar
build/lib/runtime/commons-io-2.20.0.jar

Each configuration has its own copy of its files, which is the point of the [conf] token: the application’s runtime directory and the compile classpath can differ. Retrieve also supports sync="true" (delete files in the target that are not part of the retrieve), symbolic links, and, new in 2.6.0, override children that change the revision of a transitive dependency when the task does its own resolve from nested dependency elements (shown on the next page). Those options are in Ivy Ant Tasks.

What the default settings do

The default configuration is not a single resolver. It is five small files inside the JAR that are included in turn, and reading them explains the word public in the log and where local and shared come from. This is their content, read from the 2.6.0 JAR:

<ivysettings>
    <settings defaultResolver="default"/>
    <include url="${ivy.default.settings.dir}/ivysettings-public.xml"/>
    <include url="${ivy.default.settings.dir}/ivysettings-shared.xml"/>
    <include url="${ivy.default.settings.dir}/ivysettings-local.xml"/>
    <include url="${ivy.default.settings.dir}/ivysettings-main-chain.xml"/>
    <include url="${ivy.default.settings.dir}/ivysettings-default-chain.xml"/>
</ivysettings>
<ivysettings>
    <resolvers>
        <ibiblio name="public" m2compatible="true"/>
    </resolvers>
</ivysettings>

The other files define a filesystem resolver shared rooted at ${ivy.default.ivy.user.dir}/shared, a filesystem resolver local rooted at ${ivy.default.ivy.user.dir}/local, a chain named main with dual="true" that tries shared then public, and a chain named default with returnFirst="true" and checkmodified="true" that tries local then main. So, in plain words, a dependency is looked up in the local repository (the repository the Ivy tutorials publish to, a rough counterpart of Maven’s local repository for your own builds), then in a shared file repository, then in Maven Central, and the first hit wins. The ibiblio resolver with no root attribute points at Maven Central, as the principle page says. That is the whole reason a descriptor with a Maven coordinate works with no settings.

ivy.default.ivy.user.dir is the variable that points at the Ivy home directory; unless set it is .ivy2 in the user’s home directory (confirmed here by running with a different user.home, which created .ivy2/cache under it). The cache is in its cache subdirectory. All the examples on these pages set -Divy.default.ivy.user.dir=<scratch>/ivyuser on the command line, because Ant properties are imported as Ivy variables, so that nothing was written to the real ~/.ivy2 and the examples start from a known cache. That variable is used by the default settings but is not described on the settings reference page; treat setting it from the command line as a convenience, not a contract. For a project you would write your own settings file (and set the cache there with the caches element). The settings and resolvers page covers that.

The Ivy cache

Ivy’s cache has two parts, and the difference matters for sharing it and for cleaning it:

  • The repository cache holds what was downloaded from repositories, with a small properties file per module recording where each file came from. It can be shared between machines or users if you pick a suitable lock strategy.

  • The resolution cache holds the results of resolves, so that retrieve, cachepath and report can reuse them. It is overwritten by every resolve and must never be used by two processes at once.

The default location for both is .ivy2/cache in the user’s home directory. After the first run above, the cache directory contained (the .original copies of each descriptor and the report stylesheets omitted):

cache/commons-codec/commons-codec/ivy-1.19.0.xml
cache/commons-codec/commons-codec/ivydata-1.19.0.properties
cache/commons-codec/commons-codec/jars/commons-codec-1.19.0.jar
cache/commons-io/commons-io/ivy-2.20.0.xml
cache/commons-io/commons-io/ivydata-2.20.0.properties
cache/commons-io/commons-io/jars/commons-io-2.20.0.jar
cache/io.tidepool-tidepool-engine-compile.xml
cache/io.tidepool-tidepool-engine-runtime.xml
cache/org.apache.commons/commons-csv/ivy-1.14.1.xml
cache/org.apache.commons/commons-csv/ivydata-1.14.1.properties
cache/org.apache.commons/commons-csv/jars/commons-csv-1.14.1.jar
cache/org.apache.commons/commons-parent/ivy-85.xml
cache/org.apache.commons/commons-parent/ivydata-85.properties
cache/org.apache/apache/ivy-35.xml
cache/org.apache/apache/ivydata-35.properties
cache/org.junit/junit-bom/ivy-5.13.1.xml
cache/org.junit/junit-bom/ivydata-5.13.1.properties
cache/resolved-io.tidepool-tidepool-engine-1.0.0.properties
cache/resolved-io.tidepool-tidepool-engine-1.0.0.xml

How to read it:

  • cache/<organisation>/<module>/ is the repository cache, one directory per module. Inside it, ivy-<revision>.xml is the module descriptor converted to Ivy format (for a module whose original is a POM, the POM is kept beside it as ivy-<revision>.xml.original), ivydata-<revision>.properties records which resolver found it and the original location of each file, and jars/<name>-<revision>.jar is the artifact. The directory under the module is the artifact type with an s added, from the default cache pattern [organisation]/[module](/[branch])/[type]s/[artifact]-[revision](-[classifier])(.[ext]) (no branch here, so that part is dropped), so a source artifact would go in sources and a bundle in bundles.

  • commons-parent, apache and junit-bom were not asked for by the project. They are the parent POM and the BOM that the commons-csv POM refers to; Ivy had to read them to compute the effective POM, which is why a Maven module can pull more descriptors than artifacts. They have no jars directory.

  • io.tidepool-tidepool-engine-compile.xml and -runtime.xml are the resolution cache: one XML report per module and configuration, named <organisation>-<module>-<conf>.xml. These are the files retrieve, cachepath and report read. The two resolved-... files record the outcome of the resolve for the module itself: the revision each dependency was mapped to, and the module’s descriptor as resolved.

The ivydata file for commons-csv shows the bookkeeping, and why the resolver is named in the logs:

#ivy cached data file for org.apache.commons#commons-csv;1.14.1
artifact.resolver=main
...
artifact\:commons-csv\#jar\#jar\#1409887496.location=https\://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.jar
...
resolver=public

The converted descriptor in the cache is what a POM looks like to Ivy, including the configurations Ivy invents for Maven scopes. A fragment (the Maven properties and the long lists of overrides are elided), read from ivy-1.14.1.xml in the cache:

<configurations>
    <conf name="default" visibility="public" description="runtime dependencies and master artifact can be used with this conf" extends="runtime,master"/>
    <conf name="master" visibility="public" description="contains only the artifact published by this module itself, with no transitive dependencies"/>
    <conf name="compile" visibility="public" .../>
    <conf name="provided" visibility="public" .../>
    <conf name="runtime" visibility="public" .../>
    <conf name="test" visibility="public" .../>
    ...
</configurations>
<publications>
    <artifact name="commons-csv" type="jar" ext="jar" conf="master"/>
    <artifact name="commons-csv" type="source" ext="jar" conf="sources" m:classifier="sources"/>
    <artifact name="commons-csv" type="javadoc" ext="jar" conf="javadoc" m:classifier="javadoc"/>
</publications>

That conversion is the key to using Maven Central from Ivy, and to the traps in it, and it is worked through on the next page. It is also why the cache is not a Maven repository layout and cannot be used by Maven or Gradle directly; the three tools' caches are compared in Repositories & Publishing Across Tools.

To start over, delete the cache directory, or run the cleancache task (see Ivy Ant Tasks). The release notes of 2.6.0 recommend this after upgrading from an older Ivy, because some fixes only apply to descriptors parsed afresh.

Ivy and the other tools

Ivy answers the same question as Maven’s dependency mechanism and Gradle’s dependency resolution, with a different split of responsibilities. The Apache Ivy project has its own comparison page with Maven; the table puts its points next to what is known on this site for the other two tools.

Topic Ivy Maven Gradle

What it is

A dependency manager used from Ant (or alone). It does not build.

A build tool whose model includes dependency management.

A build tool whose model includes dependency management.

Descriptor

ivy.xml (or a POM).

pom.xml.

The build script, plus Gradle Module Metadata published for consumers.

Dependency views

Any number of named configurations, mapped between modules.

A fixed list of scopes.

Configurations and variant-aware resolution.

Default conflict rule

latest-revision; nearest since 2.6.0; others pluggable, even per module.

Nearest definition wins.

Highest version wins; rich constraints.

Repositories

Pluggable resolvers, chains, dual metadata and artifact locations, ssh, vfs, custom ones.

Repositories and mirrors, one layout.

Repositories (Maven, Ivy, flat directory) with content filtering.

Local store

.ivy2/cache (own layout).

.m2/repository (repository layout).

.gradle/caches (own layout).

Reads Maven Central

Yes, through ibiblio.

Yes.

Yes.

Locking and verification

None built in beyond what a resolver or checksum setting gives.

dependencyManagement pinning, enforcer rules.

Lockfiles and verification metadata.

Three points from the Ivy side of the comparison are still true, and one is not. Still true: Ivy is far more configurable, since resolvers, conflict managers, version matchers and parsers are all plug-in points, and it can split metadata and artifacts into different repositories; the Maven comparison page notes that Maven has no repository chaining. Still true: Ivy’s reference documentation is extensive and covers every feature with examples. No longer true as stated: the comparison page says that in Maven "none of your dependencies will ever manage to get foo 1.1" without a change in your own declaration, as if that were a limitation. That is Maven’s nearest-wins rule, which Ivy can now apply itself with the nearest conflict manager, and which Maven has long complemented with dependencyManagement and BOMs (Maven dependencies, scopes and mediation). Gradle can also consume Ivy repositories and modules, which is the common bridge when a company has an Ivy repository and a Gradle build (Gradle repositories and content filtering).

When to choose Ivy today: you have an Ant build you do not want to migrate, you need configurations richer than Maven’s scopes, or you run a repository with a layout or a metadata format that Maven’s resolver cannot read. When not to: a new project with no Ant legacy will be better served by Maven or Gradle, and an Ant build that only needs to download a few JARs from Maven Central may be simpler with the Maven Resolver Ant Tasks, whose model is the same as Maven’s. The migration directions (Ant and Ivy to Maven or Gradle) are in Migrating Between Tools and in Deprecations & Migration.

Common problems

  • The ivy: tasks are undefined. The Ivy JAR is not on Ant’s classpath. See the failing run above: use -lib, copy the JAR to <home>/.ant/lib, or taskdef it.

  • Two Ivy resolves in parallel in one JVM. Ivy is not thread-safe. Do not call ivy:* tasks from within <parallel>, and be careful with subant and antcall inside <parallel>.

  • ~/.ivy2 full of stale modules after an Ivy upgrade. Delete the cache once after moving to a new Ivy line, as the release notes advise.

  • The wrong Ivy version is used. A JAR in ANT_HOME/lib always takes precedence over one added with taskdef, as a comment in the documentation’s own snippet says; ant -diagnostics includes a listing of the JARs in ANT_HOME/lib. Keep one Ivy on the classpath.

  • Everything resolves, but far more than expected is downloaded. The default configuration mapping of a dependency with no conf is *->*, which for a Maven module includes its test dependencies. This is the most expensive Ivy surprise and is demonstrated, with real output, on the next page.