Note: The Maven endpoint is currently available only in the bx-cli beta.
CommandBox has long had ForgeBox and GitHub as primary artifact sources, but Java developers have always needed a way to pull JAR dependencies without leaving their BoxLang/CFML project or managing a separate build tool. The jar: endpoint worked for a single JAR, but didn’t get any dependencies, which let to you having to manually build the dependency graph yourself, bypassing the project’s pom.xml. With bx-cli’s new maven: endpoint, you can resolve and install Maven artifacts — including all of their transitive dependencies — directly into your project.
The Simplest Case: One JAR, No Version Specified
The easiest way to use the endpoint is to install a single artifact and let Maven pick the latest stable release:
box install maven:org.apache.commons:commons-lang3
That’s it. bx-cli resolves commons-lang3 from your registered repos (Maven Central by default), picks the current <release> version, downloads the JAR along with its transitive dependencies (commons-codec, commons-logging, etc.), and installs everything into your project. No separate build tool, no pom.xml to manage — just one command.
Pinning an Exact Version
If you need a specific version (and most production projects do), append it directly:
box install maven:org.apache.commons:commons-lang3:3.14.0
Exact versions are cached by their groupId:artifactId:version coordinates, so repeat installs of the same Group Archive and Version (known as GAV) cost zero network calls — bx-cli pulls straight from its local artifact cache.
Version Ranges with Semver Syntax
You can also use semver-style ranges. Note, we use the CommandBox semantic version range syntax, which is based on npm.
box install maven:io.undertow:undertow-core:2.3.x # highest 2.3.* release
box install maven:io.undertow:undertow-core:~2.3.0 # tilde-range (patch flexibility)
box install maven:io.undertow:undertow-core:^2.3.0 # caret-range (minor flexibility)
These ranges are resolved against the repository’s maven-metadata.xml, filtering out SNAPSHOTs and picking the highest matching non-SNAPSHOT version.
A note on Windows shell escaping: If you’re typing ranges directly on a Windows command line, be aware that cmd.exe (which wraps box.bat) treats <, >, and ^ as special characters even inside quotes. For anything beyond simple exact versions or x-ranges, we strongly recommend putting your dependencies in a project’s box.json instead of fighting shell quoting on the CLI.
Using Maven Dependencies in box.json (Recommended)
While the CLI works great for quick experiments, the real power comes from declaring Maven artifacts directly in your project’s box.json:
{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"commons-lang3": "maven:org.apache.commons:commons-lang3:3.14.0",
"undertow-core": "maven:io.undertow:undertow-core:2.3.19.Final"
}
}
Forcing a Specific Repository
By default, bx-cli walks your registered repos in order (Maven Central first) until it finds an artifact. You can force resolution from a specific repo by prefixing with its alias or URL followed by a pipe:
{
"dependencies": {
"jboss-threads": "maven:sonatype|org.jboss.threads:jboss-threads:3.9.2"
}
}
This tells bx-cli to use only the Sonatype OSS repository for this artifact — no fallback. You can also use a full URL instead of an alias:
{
"dependencies": {
"my-lib": "maven:https://repo1.maven.org/maven2/|com.example:my-library:1.0.0"
}
}
When no repo is specified, bx-cli walks your registered repos in order and uses the first one that returns the artifact. A 404 on one repo simply moves to the next — you can see the resolution trail with box install --verbose.
Per-Install Flags: Fine-Tuning Resolution
Append query-string-style flags after the version to override default behavior for a single install:
{
"dependencies": {
"undertow-sources": "maven:io.undertow:undertow-core:2.3.18.Final?classifier=sources&transitive=false"
}
}
| Flag | Default | Description |
|---|---|---|
scopes |
runtime,compile |
Comma-separated Maven scopes to include as transitives |
snapshots |
false |
Allow SNAPSHOT versions when resolving STABLE/ranges |
optional |
false |
Include <optional>true</optional> transitive dependencies |
transitive |
true |
Set false to install just the requested JAR, skipping dep resolution |
exclude |
(none) | Comma-separated groupId:artifactId pairs to exclude from transitive resolution |
installMode |
dedicated |
Use shared to bundle artifacts into a common directory |
classifier |
(none) | Select a JAR variant such as sources, javadoc, or tests |
Example: Excluding Optional Dependencies
Some libraries like logback-classic declare certain dependencies as <optional>true</optional>. By default, bx-cli honors this and skips them. With the optional=true flag plus an exclude list, you can selectively include only what you need:
{
"dependencies": {
"logback-classic": "maven:ch.qos.logback:logback-classic:1.2.13?optional=true&exclude=javax.mail:mail,org.codehaus.janino:janino"
}
}
This installs logback-core, slf4j-api, and the one remaining optional dep (javax.servlet-api) — while correctly excluding javax.mail and janino.
Transitive Dependency Resolution
When you install a Maven artifact, bx-cli doesn’t just grab the JAR — it reads the .pom file, walks the parent chain (up to 10 levels deep with cycle detection), and produces a flat list of transitive dependencies. Each transitive is written into the generated box.json as a plain maven: endpoint ID without a pinned repo, so each can resolve independently from your artifact cache or any registered repo.
By default, only compile and runtime scope deps are installed. Test, provided, and system-scoped dependencies are filtered out. Dependencies marked <optional>true</optional> in the POM are also excluded unless you enable them with the flag above.
Artifact Cache & Local Maven Repository
Maven JARs are verified against repository checksums (.sha256 preferred, .sha1 fallback) before installation. Downloaded artifacts are stored under ~/.CommandBox/artifacts/, keyed purely by groupId:artifactId:version — the repo that served it is not part of the cache key. This matches real Maven semantics and guarantees immutability: once cached from a trusted repo, a later rogue repo can’t silently shadow it.
Additionally, bx-cli checks your local Maven repository at ~/.m2/repository before downloading anything over the network. If an exact GAV is already sitting there (downloaded by real Maven, IntelliJ, or other JVM tooling), bx-cli copies it from disk instead of downloading again — then stores a copy in its own cache for future installs.
Configuring Repositories
Globally
Register repositories that apply to every CLI session:
box config set endpoints.maven.repositories.sonatype="https://oss.sonatype.org/content/repositories/releases/"
box config set endpoints.maven.repositories.jitpack="https://jitpack.io/"
{
"endpoints": {
"maven": {
"repositories": {
"sonatype": "https://oss.sonatype.org/content/repositories/releases/",
"jitpack": "https://jitpack.io/",
"google": "https://maven.google.com/"
}
}
}
}
Repos are tried in the order they appear. mavenCentral is always tried first unless you redefine it here with a different URL.
Per Project
Add a nested maven.repositories key to your project’s box.json:
{
"name": "my-project",
"version": "1.0.0",
"maven": {
"repositories": {
"mavenCentral": "https://maven-central.storage.googleapis.com/maven2/",
"jitpack": "https://jitpack.io/"
}
},
"dependencies": {}
}
A per-project entry with the same alias as a global (or built-in) entry overrides its URL. Entries not present globally are simply appended to the list.
Maven Install Modes
By default, each Maven artifact is installed in its own package directory (dedicated mode), allowing normal package version tracking and dependency trees. This allows individual Maven dependencies to be uninstalled or updated since they are in separate folders. Some Java tooling expects all jars to exist in a single directory. For shared libraries that should live together, use shared mode by setting this in your box.json:
{
"maven": {
"installMode": "shared",
"installDirectory": "libs/"
}
}
Install-mode precedence is:
- Endpoint flag (
?installMode=shared) - Project
box.json:maven.installMode - Global configuration:
endpoints.maven.installMode - Default:
dedicated
Configure the global default with:
box config set endpoints.maven.installMode=shared
Version Handling Deep Dive
STABLE Resolution
Omitting a version resolves to the artifact’s <release> from maven-metadata.xml. If <release> is missing, bx-cli scans <versions> and picks the highest non-SNAPSHOT entry. SNAPSHOT versions are always excluded from STABLE resolution unless you enable them with the snapshots=true flag.
Semver Ranges
All of these are tested and working:
2.3.x # x-range — highest 2.3.*
~2.3.0 # tilde-range — patch-level flexibility
^2.3.0 # caret-range — minor-level flexibility
>=2.3.0 <2.4.0 # explicit bound range
bx-cli fetches the repo’s maven-metadata.xml, filters out SNAPSHOTs, sorts descending, and picks the highest matching version.
Maven-Style Ranges in POMs
When parsing transitive dependencies from a downloaded POM, bx-cli translates Maven bracket notation into semver equivalents:
| Maven | Semver |
|---|---|
[1.0,2.0) |
>=1.0 <2.0 |
(1.0,2.0] |
>1.0 <=2.0 |
[1.0] |
exact 1.0 |
Configuration Settings Summary
Global Config
{
"endpoints": {
"maven": {
"repositories": { /* repo aliases → URLs */ },
"installMode": "dedicated",
"installDirectory": "libs"
}
}
}
Project Config (box.json)
{
"name": "my-project",
"version": "1.0.0",
"maven": {
"repositories": { /* repo aliases → URLs */ },
"installMode": "shared",
"installDirectory": "libs/"
},
"dependencies": {
"artifact-name": "maven:groupId:artifactId:version?flag=value"
}
}
Known Limitations
- POM
<repositories>are not consulted. Only repos you’ve explicitly registered (built-in, global config, or projectbox.json) are used. This is intentional — blindly trusting a POM’s own repo declarations is a supply-chain risk. An opt-in setting (endpoints.maven.trustPomRepositories) is planned. - BOM imports (
<scope>import</scope><type>pom</type>) are not fully processed yet. Most real-world artifacts still resolve correctly because their direct dependencies carry their own versions. - Classifiers on transitive dependencies are parsed but not honored during download — only the primary
.jaris fetched. Theclassifierflag remains supported for requested artifacts. - Only one JAR per endpoint ID. bx-cli does not automatically download sources, javadocs, or test artifacts; request them explicitly with the
classifierflag.
Getting Started
The Maven endpoint in bx-cli brings the full power of Maven dependency resolution into your BoxLang/CFML projects without requiring a separate build tool. Whether you’re pulling a single utility library or managing complex transitive dependencies, the maven: endpoint handles it all — with caching, checksum verification, and seamless integration into your existing box.json workflow.
Give it a try in the beta and let us know what you think!
Thanks to Pete Freitag and his original CommandBox module that we based this work off of.