Jenkins Artifact Management: Nexus, Artifactory, S3 Gotchas & Production War Stories
Production-grade guide to Jenkins artifact management with Nexus, Artifactory, and S3.
20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.
- ✓Solid grasp of devops fundamentals
- ✓Comfortable reading and writing code examples independently
- ✓Basic understanding of production deployment concepts
- Use Nexus staging profiles for release promotion; avoid deploying snapshots to release repos.
- Configure Artifactory build-info to trace artifacts back to Jenkins builds for auditability.
- S3 stash/unstash works for small artifacts (<500MB); for larger, use S3 plugin with direct upload.
- Set Maven deploy with credentials via settings.xml encrypted with Jenkins credentials binding.
- Implement artifact retention: delete snapshots older than 30 days, keep last 5 releases.
- Use semantic versioning with git hash for traceability; timestamped versions cause dependency hell.
- Proxy Maven Central via Nexus/Artifactory to avoid external outages and speed up builds.
- Always use checksum verification; missing checksums cause silent corruption in production.
Think of artifact management like a library. Developers write books (code), and the library stores them. Nexus and Artifactory are fancy librarians that check each book's ISBN (version), ensure no duplicates, and allow borrowing (downloading). S3 is like a giant warehouse where books are kept in boxes. Jenkins is the publishing house that sends books to the library. The problem? If you send a book with the wrong ISBN or overwrite a rare edition, you corrupt the library. In production, a single misconfigured deploy can overwrite a critical artifact, breaking all downstream systems.
I once spent a sleepless night because a Jenkins pipeline deployed a SNAPSHOT artifact to our production Nexus release repository. The artifact had a checksum mismatch, so every downstream service that pulled it failed with cryptic errors. The root cause? A developer had manually triggered a build with a stale branch, and the pipeline didn't validate the artifact type. That night, I learned that artifact management is not just about storage—it's about governance. Over the years, I've battled Nexus staging rules, Artifactory build-info corruption, and S3 bucket policies that mysteriously blocked uploads. This article distills those hard-won lessons into a practical guide for Jenkins artifact management.
1. Nexus Repository Manager Integration
Nexus Repository Manager (version 3.38.0) is a popular binary repository. Integrating with Jenkins involves setting up Maven or Gradle to deploy artifacts. For Maven, configure your POM's distributionManagement to point to Nexus, and provide credentials via settings.xml in Jenkins. Use the Nexus Platform Plugin (version 3.14.0) to trigger Nexus tasks (e.g., staging). Key concepts: release vs snapshot repositories. Release repos should have 'Disable Redeploy' enabled to prevent overwrites. Snapshot repos allow multiple versions with timestamped filenames. Staging profiles allow promoting artifacts from staging to release after validation. Use Nexus REST API (v1) to search, upload, or delete artifacts. In production, always use HTTPS and ensure Jenkins nodes have the Nexus CA certificate. A common gotcha: Nexus returns 400 if the artifact already exists in a release repo with 'Disable Redeploy' enabled. Always check the artifact existence before deploy.
2. Artifactory Integration
JFrog Artifactory (version 7.55.0) integrates via the Artifactory Plugin (version 3.19.0) or JFrog CLI. The plugin allows uploading/downloading artifacts, publishing build-info, and promoting builds. Build-info is crucial for traceability: it links artifacts to Jenkins build metadata (commits, env variables). Use the 'Artifactory Maven' build wrapper to automatically deploy Maven artifacts. For Gradle, use the 'Artifactory Gradle' wrapper. JFrog CLI (jfrog v2) can be used in pipeline scripts: jfrog rt upload and jfrog rt download. Set up virtual repositories to aggregate local and remote repos. In production, use access tokens instead of passwords. A common issue: build-info publishing fails if the artifact already exists with different checksums. Always use '--build-name' and '--build-number' to associate artifacts. Artifactory's 'Maven-3-compatible' option generates .md5 and .sha1 files; without it, Maven downloads fail.
3. S3 Artifact Storage
Amazon S3 (or S3-compatible like MinIO) can be used for artifact storage via the S3 Plugin (version 1.10.0). The plugin supports stash/unstash for transferring artifacts between stages (e.g., from build to deploy). However, for large artifacts (>500MB), use direct S3 upload/download with AWS CLI. Configure S3 bucket policies to allow only Jenkins IAM role. Use lifecycle policies to expire old artifacts (e.g., delete after 90 days). Versioning is recommended to prevent accidental overwrites. In Jenkins, the S3 plugin stores artifacts under a prefix (e.g., jenkins/$JOB_NAME/$BUILD_NUMBER). A common pitfall: S3 eventual consistency can cause 'NoSuchKey' errors if you try to download immediately after upload. Use S3 strong consistency (newer regions) or add a retry loop. Also, ensure the S3 bucket is in the same region as Jenkins to avoid cross-region data transfer costs.
4. Maven Deploy Configuration in Jenkins
Configuring Maven deploy in Jenkins requires settings.xml with credentials for Nexus/Artifactory. Use Jenkins Credentials Binding to inject credentials as environment variables, then use the 'withMaven' step to generate a temporary settings.xml. Alternatively, use the Config File Provider plugin to manage settings.xml as a managed file. In the POM, define distributionManagement as shown earlier. To avoid hardcoding URLs, use Jenkins environment variables or pipeline parameters. A common mistake: using the same repository for snapshots and releases. Always separate them. For multi-module projects, ensure all modules deploy correctly by running 'mvn deploy' from the root. In production, use 'mvn deploy -DskipTests' to speed up deployment. Also, set the Maven version to avoid unexpected behavior; we use Maven 3.8.6.
5. Gradle Publish Plugin Setup
Gradle uses the 'maven-publish' plugin to deploy artifacts. Configure publishing.repositories in build.gradle. Use Jenkins credentials via -PmavenUser and -PmavenPassword. Example: 'gradle publish -PmavenUser=user -PmavenPassword=pass'. For Artifactory, use the 'com.jfrog.artifactory' plugin. For Nexus, use 'maven-publish' with Nexus URL. A common issue: Gradle's incremental build may skip publishing if nothing changed. Use '--rerun-tasks' to force. Also, Gradle generates POM files automatically; ensure they include correct dependencies. In production, use Gradle 7.5.1 and verify artifact checksums post-deploy.
6. Promoting Artifacts Across Environments
Promotion moves artifacts from dev to staging to prod. In Nexus, use staging profiles: deploy to staging repo, run tests, then promote to release repo. In Artifactory, use build promotion: jfrog rt build-promote. For S3, copy artifact to different prefixes (e.g., s3://bucket/dev/ -> s3://bucket/prod/). In Jenkins, create separate pipelines for each environment with manual approval gates. Use versioning to track which artifact is in which environment. A common pattern: tag the Git commit with the version and environment (e.g., v1.2.3-staging). Ensure that promotion is atomic: if promotion fails, rollback by copying the previous artifact. In production, we use Artifactory's 'Promote' REST API with a Jenkins job that requires two approvals.
7. Artifact Retention Policies and Cleanup
Retention policies prevent repository bloat. For snapshots, delete those older than 30 days and keep last 5 versions. For releases, keep all versions indefinitely, but consider archiving old ones to S3 Glacier. Nexus has built-in cleanup policies: Admin > System > Cleanup Policies. Artifactory has 'Cleanup' repository settings. For S3, use lifecycle rules. In Jenkins, you can create a periodic cleanup job that calls the Nexus/Artifactory REST API to delete old artifacts. Example: delete snapshots older than 30 days using Nexus REST API: DELETE /service/rest/v1/components?repository=snapshots&group=com.example. Be careful: deleting a release artifact that is referenced by a downstream build will break it. Always check if the artifact is still needed.
8. Versioning Strategies
Versioning ensures traceability and reproducibility. Semantic versioning (semver) is common: major.minor.patch (e.g., 1.2.3). Append build metadata like build number or git hash: 1.2.3-${BUILD_NUMBER} or 1.2.3-${GIT_COMMIT_SHORT}. Timestamped versions (e.g., 1.2.3-20230101-120000) are useful for snapshots but can cause dependency resolution issues if multiple builds produce the same timestamp. Git hash alone is not human-readable. Best practice: use semver for releases and semver-SNAPSHOT for development. In Maven, use the 'maven-buildnumber-plugin' to inject git hash. In Gradle, use 'gradle-git-properties'. In Jenkins, set the version in the pipeline using environment variables. Avoid using 'LATEST' as it can cause unpredictable builds.
9. Binary Repository as Build Cache
Nexus and Artifactory can proxy remote repositories like Maven Central, JCenter, or npm. This speeds up builds by caching dependencies locally. In Jenkins, configure Maven's settings.xml to use the proxy repo (e.g., https://nexus.example.com/repository/maven-public/). For Gradle, set repositories { maven { url 'https://nexus.example.com/repository/maven-public/' } }. This also provides a safety net: if Maven Central goes down, builds still succeed using cached dependencies. However, cache staleness can be an issue: if a dependency is updated remotely, the proxy may still serve the old version. Set the cache refresh interval (e.g., 1440 minutes for Nexus). In production, we always use a virtual repository that aggregates local and remote repos.
10. Artifact Metadata and Search via REST API
Nexus and Artifactory provide REST APIs to search, retrieve, and manage artifacts. Nexus: /service/rest/v1/search?repository=releases&group=com.example&name=myapp. Artifactory: /api/search/aql with AQL queries. Use these in Jenkins to verify artifact existence, get checksums, or list versions. For example, before deploying, check if the artifact already exists to avoid overwrites. Also, use metadata to store build info: in Artifactory, you can add properties (e.g., build.number=123). In Nexus, use custom facets. In production, we have a Jenkins shared library that queries the repository to determine the next version or to validate promotion.
11. Common Failures and Solutions
Common failures include: 401 Unauthorized (wrong credentials), checksum mismatch (missing .md5 file), artifact overwrite lock (concurrent deploys), S3 AccessDenied (wrong IAM role), and artifact not found (wrong path). Solutions: always test credentials manually, enable checksum generation, use unique versions, validate bucket policies, and double-check paths. Another failure: Maven deploy fails with 'Failed to transfer file' due to network issues. Use retry logic in Jenkins (e.g., retry(3) { sh 'mvn deploy' }). Also, ensure that the repository has enough disk space. In production, we monitor repository disk usage and set up alerts.
12. Production Incident: The Deploy That Overwrote Production
This incident taught us the importance of artifact governance. The deploy pipeline had no stage to validate artifact type. A developer manually triggered a build from a feature branch, which produced a SNAPSHOT artifact. The deploy step used the same repository path as releases, overwriting the production JAR. The Artifactory plugin's 'Maven-3-compatible' option was disabled, causing checksums to not be generated. Downstream builds failed with 'checksum mismatch'. The fix involved restoring from backup, modifying the pipeline to enforce branch-based deployment, enabling checksum generation, and adding a pre-deploy check. The lesson: always validate artifact metadata before deploying. Use repository permissions to prevent overwrites. Enable checksum generation and verification. Since then, we have implemented a 'deploy gate' that checks the artifact version, branch, and checksums before allowing deployment.
The Deploy That Overwrote Production
- Always validate artifact metadata before deploying.
- Use repository permissions to prevent overwrites.
- Enable checksum generation and verification.
Print-friendly master reference covering all topics in this track.
Key takeaways
Common mistakes to avoid
6 patternsDeploying snapshots to release repository
Not enabling checksum generation
Hardcoding credentials in POM or settings.xml
Not separating snapshot and release repos
Ignoring artifact retention policies
Using 'LATEST' in dependency versions
Interview Questions on This Topic
How would you prevent a SNAPSHOT artifact from being deployed to a release repository in Jenkins?
Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.
That's Jenkins. Mark it forged?
5 min read · try the examples if you haven't