Streamline Your CI/CD: Jenkins + Nexus NPM Registry (With and Without Docker)
Introduction
Keeping internal NPM packages safe during continuous integration and delivery is more important than ever, and a private registry such as Sonatype Nexus offers a simple, central way to do this. In the steps that follow, you’ll learn how to link Jenkins to a Nexus NPM feed, whether your builds run inside Docker or directly on the server, letting you authenticate securely and install packages the way that suits each job best.
Why This Matters
A well -configured private NPM register allows you to draw early addiction while maintaining source coding security. As a result, a combination of Nexus and Jenkins allows you:
- Authenticate Securely: Log in to your Nexus NPM Registry with valid credentials.
- Dynamic Configuration: Automatically create and set up .npmrc for hassle-free authentication.
- Flexible Installation: Install packages either within an isolated Docker container for consistency or on the Jenkins node directly for speed.
What You’ll Need
Before you begin, verify you have the following:
- Jenkins with either Pipeline (Scripted or Declarative) support.
- Jenkins Credentials: a “Username with password” entry named NEXUS_USER, containing your Nexus login.
- Docker present if you intend to run the builds in containers.
- Node.js on the Jenkins node for jobs that do not use Docker.
Shared Setup: .npmrc Configuration
Secure authentication starts with a properly set .npmrc file. The snippet below uses npm-cli-login, letting it handle tokens while keeping your Nexus details safe.
NPMRC_PATH=".npmrc" REGISTRY_URL="https://nexus.example.com/repository/npm-group/" EMAIL="build@yourdomain.com"
After the relevant environment variables are set, add these commands within a sh block of your pipeline and wrap the entire block with withCredentials for NEXUS_USER and NEXUS_PASS.
if ! command -v npm-cli-login > /dev/null; then
npm install -g npm-cli-login
fi
# Clear existing .npmrc content
cat /dev/null > "$NPMRC_PATH"
# Authenticate with Nexus using npm-cli-login
npm-cli-login -u "${NEXUS_USER}" -p "${NEXUS_PASS}" \
-e "${EMAIL}" -r "${REGISTRY_URL}" --config-path "$NPMRC_PATH"
# Ensure the registry URL is explicitly set if not already present
if ! grep -q "^registry=${REGISTRY_URL}$" "$NPMRC_PATH"; then
echo "registry=${REGISTRY_URL}" >> "$NPMRC_PATH"
fi
# Optional: Replace internal DNS if needed
sed -i 's|//nexus.example.com/repository/npm-group/|//your.nexus.domain/repository/npm-group/|' "$NPMRC_PATH"
The script performs the next operations:
- Install npm-cli-login globally: Installs the util globally if it has not been installed previously.
- Clears .npmrc: Removes the target file to delete any settings/credentials that have been previously established.
- Authenticates: Logs on via Jenkins environment variables, storing the token in .npmrc.
- Sets Registry: Adds the registry line just once if it wasn’t already in it, avoiding duplicities.
- Optional Replacement of DNS: Modifies the URL path of .npmrc if the pipeline is executed against an environment where the hostname of Nexus differs.
Option 1: Running Virtual Environments with Docker
Why do that?
- Clean Build Environments: Each build runs in a brand-new, isolated container, sidestepping version conflicts of the dependency or “leftovers” of previous builds.
- Multiple Node.js Versions: You can seamlessly switch between different Node.js versions by simply pulling a different Node.js Docker image.
- Avoid Host-Level Pollution: Prevents the Jenkins agent filesystem from being polluted by Node.js and NPM dependencies.
Jenkins Pipeline Snippet:
stage('Install Packages in Docker') {
steps {
script {
withCredentials([usernamePassword(credentialsId: 'NEXUS_ADMIN_USER', usernameVariable: 'NEXUS_USER', passwordVariable: 'NEXUS_PASS')]) {
sh '''
# Setup NPMRC (copy the shared config above here)...
if [[ "${CHOOSE_NODE_VERSION}" == "18" || "${CHOOSE_NODE_VERSION}" == "20" ]]; then
IMAGE=""
if [[ "${CHOOSE_NODE_VERSION}" == "18" ]]; then
IMAGE="your-ecr-repo/node:18.18.1"
elif [[ "${CHOOSE_NODE_VERSION}" == "20" ]]; then
IMAGE="your-ecr-repo/node:20.10"
fi
# Log in to AWS ECR
aws ecr get-login-password --region ap-south-1 | docker login --username AWS --password-stdin your-ecr-repo
# Run npm commands inside the Docker container
docker run --rm -t \\
-v /data/jenkins/workspace:/data/jenkins/workspace \\
-v ${WORKSPACE}/.npmrc:/root/.npmrc:ro \\
-w "${WORKSPACE}" \\
"${IMAGE}" \\
bash -c '
cd "${WORKSPACE}" && \\
npm config get registry && npm whoami && \\
npm cache clean --force && \\
npm install --legacy-peer-deps && \\
npm install typescript@5.8.2
'
fi
'''
}
}
}
}
Explanation:
- withCredentials: Safely injects your Nexus username and password as environment variables.
- CHOOSE_NODE_VERSION: You might have this as an example parameter defined in your Jenkins job to choose the node version of your liking.
- ECR Login: Logs Docker into your AWS Elastic Container Registry to be able to pull private images.
- docker run:
–rm: Automatically delete the container once it exists.
-t: Assigns a pseudo-TTY, which is helpful for interactive tasks.
-v /data/jenkins/workspace:/data/jenkins/workspace Mount the Jenkins workspace into the container so npm install can update your project files.
-cv /data/jenkins/.npmrc::/root/.npmrc:ro Mounts the .npmrc file that has been generated by Jenkins on the fly into the root of the container.
– “${WORKSPACE}”: It defines the working directory within the container as Jenkins workspace of yours.
“${IMAGE}”: Specifies the Docker image that will be employed (e.g., the Node.js image that is located on ECR).
bash -c ‘.’: Run a series of commands within the container. These commands run the actual npm commands:
npm config get registry && npm whoami: It verifies the registry and the logged-in user.
npm cache clean –force: It wipes the npm cache to get a clean install.
npm install –legacy-peer-deps: Installs the project.
npm install typescript@5.8.2: It installs a.
Option 2: Installing on Jenkins Node
Why do that?
Faster Builds: Spin-up overhead of the Docker containers can be removed by making the build times faster.
Easier to Debug: In case of issues with Node.js or NPM, debugging is simpler with easy access to the terminal of the Jenkins node.
Jenkins Pipeline Snippet:
stage('Install Packages on Host') {
steps {
script {
withCredentials([usernamePassword(credentialsId: 'NEXUS_ADMIN_USER', usernameVariable: 'NEXUS_USER', passwordVariable: 'NEXUS_PASS')])
sh '''
# Setup NPMRC (paste the shared config above here).
npm config get registry
npm whoami --registry=${REGISTRY_URL}
node --version
npm cache clean --force
npm install
'''
}
}
}
}
Explanation:
- withCredentials: As before, safely provides Nexus login credentials.
- sh ”’…”’: executes the commands directly on the Jenkins agent.
- npm config get registry, npm whoami, node –version: These commands validate your Jenkins node configuration.
- npm install –legacy-peer-deps, npm install typescript@5.8.2, npm cache clean –force: typical npm commands used to include specific libraries and manage the libs used by the project.
Final Reminders
- –legacy-peer-deps: It can be used along with npm install option to prevent strict peer dependency issues, particularly when dealing with highly complex dependency graphs or older packages.
- Verify Authentication: To make sure that the build environment has been authenticated against the right registry of the Nexus, include npm config get registry and npm whoami inside the pipeline at all times.
- Private Credentials Separation: Use Jenkins’ withCredentials feature to handle private information like Nexus login credentials. It does not enable the source code nor logs to print the credentials.
Conclusion:
In short, the CI/CD workflow of yours will significantly improve by adopting this Jenkins pipeline configuration.
- Alternate between host-based and containerised builds according to the needs of your project.
- Authenticating seamlessly with your own Nexus NPM Registry.
- Make the installation of dependency secure and easy to enhance the reliability of the development workflow.
This guide provides a solid foundation for managing your JavaScript dependencies in a Jenkins CI/CD environment. Explore these options to find the best fit for the workflow of your team!
