Setting Up a Private Maven Repository (Nexus) for Java Projects

Builds fail due to unavailable external dependency sources, and every artifact version is pulled from the public network. We set up a private Maven repository turnkey: deploy it, configure proxy and group, and hand over policies. Build and release time is reduced severalfold, and the risks of release disruption are eliminated.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Why builds break without a private Maven repository

A build passes on a developer's machine and fails in CI with a dependency resolution error — because the private library remained only in the local ~/.m2 cache.

The local cache is not versioned, is not transferred between agents, and is not a source of truth: as soon as the code lands on a clean machine, the artifact simply isn't there, and troubleshooting starts with finding out whose build "works."

The second class of failures is external source unavailability. A public repository responds with a timeout or error, and it's not just one job that stalls but the entire pipeline: every agent pulls dependencies from the network again.

The same commit builds differently at different times, and build time fluctuates by multiples — depending on the state of someone else's infrastructure that we don't control.

The third is divergent library versions. While dependencies are resolved directly, ranges and transitive links resolve differently on different machines.

The test "flashes," the release is not fully reproducible, and troubleshooting takes hours: what has to be compared is not the code but dependency graphs.

Build reproducibility is a property of infrastructure, not developer discipline.

As long as private libraries and internal modules are built "in place," their versions are not pinned anywhere, the dependency cache is different for everyone, and the build result on a clean machine depends on what happened to be downloaded earlier.

This also leads to long builds: without a shared cache, the same artifacts are downloaded repeatedly on every agent.

Let's break down how this is closed: a private Maven repository becomes the single point for obtaining artifacts — with proxying of external sources, a version retention policy, and predictable builds on any clean machine.

What changes in build and delivery after implementation

While dependencies are pulled directly from public sources, the build behaves unpredictably: some libraries respond slowly, some are unavailable, and individual versions are substituted without warning.

A private Maven repository on Nexus closes the delivery chain onto itself — artifacts come from the internal storage, and external sources are used only for initially populating the cache. Below is what exactly changes and by which metrics this is visible.

  • Clean build time. The first run on a new machine or in a clean container is reduced by multiples: downloads go over the internal network from a warmed proxy cache, rather than in parallel from external sources with different throughput.
  • Build failure rate. Failures due to external source unavailability, connection drops, and corrupted artifacts cease to be a separate class of failures — the build stops depending on someone else's uptime.
  • Version pinning. Ranges and floating tags are replaced with exact versions in the parent descriptor, snapshots of internal libraries go to a separate repository with a retention policy — the build is reproducible on any machine.
  • Onboarding a new developer. Setup comes down to a local config and credentials: the template is distributed from the repository, and time to first successful build is reduced to tens of minutes without going around colleagues with a flash drive.

These four points are convenient to use as acceptance criteria: before implementation, current values are recorded; after, they are compared using build logs.

If at least clean build time and failure rate do not move, then the proxy cache is configured incorrectly or some dependencies bypass the repository.

Proxy, hosting, and repository group: what to choose

Three storage modes solve different tasks, and confusing them is the main source of problems at the start. Proxy mode covers external dependencies: it caches what is actually downloaded by the build, and the run stops depending on public source availability.

Hosting your own artifacts stores what you release yourself — internal libraries, utilities, assembled modules. A repository group stores nothing: it is a single entry point from which the build tool retrieves everything at once.

Option When it fits Limitations
Proxy mode There are external dependencies, build reproducibility is needed The cache grows; a cleanup policy by age and by number of versions is needed
Hosting your own artifacts Several teams reuse internal libraries Requires versioning discipline and write permissions
Repository group One address is needed instead of a set of sources Stores nothing itself, only aggregates with a specified order

Working scheme is a combination: proxy covers the external contour, hosting holds your own releases, and the group serves them at one address. Permissions are granted by purpose: read-only on the proxy, write for build agents on hosting.

Separately, there should be separation by contour: the build contour should not see release artifacts, otherwise a test build will imperceptibly pull in something that has not yet passed validation.

Implementation stages: from dependency audit to handover

The order of steps here is not a formality: if you start with deployment and permissions, and determine the dependency composition at the end, half of the configuration will have to be redone — storage groups and access rules are built for real traffic, not the other way around.

  1. Dependency inventory. We go through all modules and compile the actual list of artifacts: what is pulled from external sources, what is published by your build, and which versions are pinned in parent files. The output is a list of groups with request frequency; it is used to calculate storage volume and the need for mirrors.
  2. Placement scheme. We determine how many repositories are needed: a proxy for external sources, an internal one for your own artifacts, and separate lines for intermediate and release builds. We define the search order so the build does not go to the external network for something that is already available locally.
  3. Access rights setup. We separate roles: build pipeline accounts get read and write only to their groups, developers get read and publish to designated directories, administrators get management. Publishing runs under a separate account tied to a specific project, not a shared one.
  4. Validation on real projects. First we populate proxy repositories, then build two or three projects with a completely cleared local cache. This shows that no dependency is pulled around the repository, and the build passes on a clean machine.
  5. Transfer to operations. We hand over the described access rules, backup regulations, free space monitoring, and escalation procedure. The customer's team repeats typical operations themselves — publishing, version revocation, adding a project.

After handover, the repository lives without our involvement: settings are recorded in documentation, not in chat, and any change is reproducible.

Handover package: configurations, diagrams, regulations

Along with the working configuration, the customer's team receives a complete handover package — everything is in the repository next to the code, not in chat or people's heads.

Such a set allows changing the module composition, onboarding new teams, and restoring the repository without contacting us.

  • settings.xml and build profiles for local workstations and agents: mirrors, order of access to sources, binding to credentials.
  • Repository configuration: layout of local, proxying, and group repositories, binding of artifact formats, caching rules for external dependencies.
  • Artifact flow diagram: from build to publication, who writes and who only reads, where the immutability rule for a release version is pinned.
  • Access policies: roles for service accounts, publish and delete permissions, rotation periods, integration with the corporate user directory.
  • Update regulations: procedure for rolling out repository versions, maintenance windows, compatibility checks with build pipelines, rollback plan.
  • Backup: copy composition, schedule, off-site storage, regular recovery testing on a test contour.
  • On-call instructions: recovery scenarios, actions when a node fails, granting access to a new team, diagnosing publication failure.
  • Acceptance checklist: permission reconciliation, building a project from scratch, restoring from a copy, checking cleanup of outdated artifacts.

Case: moving builds from a public source to your own

Before: the build depended on someone else's node

Twenty-eight Java projects were built directly from a public source, and the dependency cache lay on developers' machines and build agents.

As long as the external node responded, there were no problems; when there was a delay or connection drop, the pipeline stalled at the dependency resolution stage. Over a quarter, about forty such stoppages accumulated, each requiring a manual restart and team downtime.

A full build pass took 12–14 minutes, and a noticeable portion of the time went to re-downloading the same libraries.

What we did

Our engineers deployed a private Maven repository on Nexus and introduced a single entry point for all teams: external sources are proxied, internal artifacts are published to local hosting, and the group address is specified in build settings.

The cache moved to the server and stopped depending on a specific machine — repeated requests for a library are fulfilled within the network. We also described retention policies and snapshot rules so the directory would not grow uncontrollably.

Result

The average build pass was reduced from 12–14 to 6–7 minutes, and the number of stoppages due to external availability dropped to isolated cases per quarter. All 28 projects were moved to the single entry point, including old modules with their own settings.

The "external source unavailable" failure class stopped affecting releases: the build runs from the internal cache, and the external node is used only to replenish it.

What to do if you already have your own artifact server deployed?

A deployed Nexus is not a reason to migrate "from scratch." The reasonable order is the reverse: audit the current repository, migrate artifacts, then connect it to the unified access scheme. With this order, teams continue to build and ship releases while we work with the repository.

The audit starts with a map of repositories: which ones are your own, which proxy external sources, what actually lies in shared groups, and who publishes artifacts under each account.

Separately, we record where snapshots have not been cleaned and which builds are hard-bound to old addresses — these links will have to be changed in project configurations, and it is better to know about them in advance.

Migration is done not by copying directories but while preserving version history: released versions, metadata, and checksums are transferred so old builds remain reproducible and rollback to a previous version works as before. Outdated items can be left behind — storage volume is reduced, while the necessary history remains.

The last step is connecting to the unified access scheme: groups from the corporate directory, separate roles for reading and publishing, separate accounts for build systems, unified snapshot retention rules.

After that, the repository lives by common rules and does not require manual intervention on every release.

Addressing doubts: updates, access, fault tolerance

Before starting, five questions usually come up: contour isolation, contractor access, behavior when the repository is unavailable, storage volume, and edits to build files. Below are brief answers to each.

How do you separate contours so test builds don't go into production?

A separate repository for each contour: the build reads only its own, publication goes to an intermediate one, and from there the artifact is promoted to the release one. Writing outside promotion is closed by permissions.

How do you give a contractor access without opening the entire repository?

A role with read access to a specific set of artifacts and a separate account without publish rights. Access is time-limited and revoked with one operation when the work is finished.

What happens if the repository is unavailable?

The local dependency cache on the build machine covers a repeat build, but new versions will not be pulled. We set up a mirror and describe the switchover procedure — the pipeline does not stall during a failure.

How quickly does storage volume grow?

Growth mainly comes from the cache of third-party libraries and build snapshots. A retention policy keeps the latest builds per version and cleans the rest on a schedule — volume stops growing linearly, and rollback remains possible.

Will build files have to be changed?

Yes, but minimally: the Nexus address and credentials are moved into environment settings, not into project code. A developer only needs an edit in their personal profile; the team build takes parameters from the environment.

Let's discuss the task and come back with an estimate and plan

To make the conversation substantive rather than a general overview, a few inputs about your contour are enough for us.

There is no need to prepare anything specifically — what the team already has is sufficient: project descriptions, build configurations, and security service requirements. It is useful to send:

  • composition of Java projects: how many modules, what is published as an artifact and what is only consumed, which teams depend on shared libraries;
  • current dependency sources: public external repositories, local mirrors, artifacts lying directly in the version control system;
  • contour isolation requirements: which environments should not see each other's artifacts and on which side validation is needed;
  • access model: who publishes, under which credentials, whether integration with the corporate user directory and a role scheme are needed;
  • retention and proxying policy: what is reasonable to keep permanently, what to serve from intermediate storage, and what retention depth is needed for rollbacks;
  • site constraints: where the service is hosted, requirements for backup, recovery, and monitoring;
  • transition scenario: how we move projects to the private repository so that builds do not stop at any stage.

Based on the review, we will come back with an implementation plan and timeline estimate: stages, responsibility areas, checkpoints, rollback procedure. Describe the task — and we will come with a concrete proposal, not general questions.