Change every Nexus and Artifactory URL in your builds, lockfiles included
A build names its repository in more places than one settings file, and a lockfile names it again. package-lock.json and Yarn 1’s yarn.lock hold the tarball URL of each package, and poetry.lock and uv.lock hold the URL of the index each package came from. If you change the settings and leave the lockfiles, npm ci goes on downloading from Nexus or Artifactory until the day you switch it off, and Poetry and uv refuse a lockfile that no longer matches your settings.
This page maps each Nexus 2, Nexus 3 and Artifactory URL to its CloudRepo URL, gives one search that finds every one in your repositories, and gives the step that regenerates each lockfile. It changes URLs. It does not copy files: to copy them, see Migrate from Sonatype Nexus Repository or Migrate from JFrog Artifactory.
Nexus URLs and their CloudRepo URLs
Section titled “Nexus URLs and their CloudRepo URLs”Nexus Repository 3 writes a repository’s URL with the repository’s name after /repository/, for Maven, npm and Python. Nexus Repository 2 writes a hosted repository’s URL with its name after /nexus/content/repositories/ and a repository group’s after /nexus/content/groups/, for Maven and npm, as the PDF linked from Sonatype’s Nexus Repository 2 help shows. Each row shows a URL as Sonatype’s examples write it, with nexus.example for your host and the repository names the examples use, and the same repository on CloudRepo. The first three rows are Nexus 3 and the last four are Nexus 2, which their first cell says:
| Build tools | URL in Nexus | URL on CloudRepo |
|---|---|---|
| Maven and Gradle | https://nexus.example/repository/maven-public/ |
https://your-org.mycloudrepo.io/repositories/your-repo |
| npm and Yarn | https://nexus.example/repository/npm-all/ |
https://your-org.mycloudrepo.io/repositories/your-repo/ |
| pip, Poetry and uv | https://nexus.example/repository/pypi-all/simple |
https://your-org.mycloudrepo.io/repositories/your-repo/simple/ |
| Maven and Gradle, Nexus 2 group | https://nexus.example/nexus/content/groups/public |
https://your-org.mycloudrepo.io/repositories/your-repo |
| Maven and Gradle, Nexus 2 repository | https://nexus.example/nexus/content/repositories/releases/ |
https://your-org.mycloudrepo.io/repositories/your-repo |
| npm and Yarn, Nexus 2 group | https://nexus.example/nexus/content/groups/npm-all/ |
https://your-org.mycloudrepo.io/repositories/your-repo/ |
| npm and Yarn, Nexus 2 repository | https://nexus.example/nexus/content/repositories/npm-internal/ |
https://your-org.mycloudrepo.io/repositories/your-repo/ |
The /nexus in a Nexus 2 URL is the server’s webapp context path. Sonatype’s help says it is /nexus by default and shows how to move it to the root, so your URLs may have another path, or none, before /content/. The search below finds a Nexus 2 URL either way.
Artifactory URLs and their CloudRepo URLs
Section titled “Artifactory URLs and their CloudRepo URLs”JFrog writes a repository’s URL with the repository key after /artifactory/, and after /artifactory/api/npm/ or /artifactory/api/pypi/ for npm and Python, as its pages for Maven, npm and Python show. Each row shows a URL as JFrog’s examples write it, with acme.jfrog.io for your host, and the same repository on CloudRepo:
| Build tools | URL in Artifactory | URL on CloudRepo |
|---|---|---|
| Maven and Gradle | https://acme.jfrog.io/artifactory/libs-release |
https://your-org.mycloudrepo.io/repositories/your-repo |
| npm and Yarn | https://acme.jfrog.io/artifactory/api/npm/npm-virtual/ |
https://your-org.mycloudrepo.io/repositories/your-repo/ |
| pip, Poetry and uv | https://acme.jfrog.io/artifactory/api/pypi/pypi-virtual/simple |
https://your-org.mycloudrepo.io/repositories/your-repo/simple/ |
Copy the CloudRepo column as it is written. The Maven URL has no trailing slash, the npm URL ends in / and the Python index URL ends in /simple/, as Pull Maven artifacts, Install npm packages and Install Python packages show. The last part of each is the name of the CloudRepo repository you moved those packages to, so before you search, write down each Nexus or Artifactory repository your builds use and the CloudRepo repository that replaces it.
A Nexus group or an Artifactory virtual repository can serve your own packages and public ones from one URL. CloudRepo has group repositories for Maven and Docker and none for npm or Python: Artifactory and Nexus terms in CloudRepo says what takes their place.
Find every URL
Section titled “Find every URL”This command lists every line, in the files below that Git tracks, that names an old host or holds /repository/ (Nexus 3), /content/repositories/ or /content/groups/ (Nexus 2), or /artifactory/ (Artifactory) in a URL, so a host you did not think of shows up too. Run it in each repository you have, and write your own host names in place of nexus.example and acme.jfrog.io, with a backslash before each dot:
git grep -n -i -E '/repository/|/artifactory/|/content/repositories/|/content/groups/|nexus\.example|acme\.jfrog\.io' -- '*pom.xml' '*settings.xml' '*build.gradle' '*build.gradle.kts' '*settings.gradle' '*settings.gradle.kts' '*.npmrc' '*package-lock.json' '*yarn.lock' '*.yarnrc.yml' '*pip.conf' '*requirements*.txt' '*pyproject.toml' '*poetry.lock' '*uv.lock'Each hit is a file and a line. A hit in package-lock.json, yarn.lock, poetry.lock or uv.lock is a lockfile, and the next section regenerates it. A hit in any other file is a URL to change by the tables above, unless it names a public server that is not yours: leave that URL as it is. The list includes pyproject.toml, which holds the index of Poetry and uv, and .yarnrc.yml, which holds the registry of Yarn 2 and later.
Regenerate each lockfile
Section titled “Regenerate each lockfile”Change the settings first, so that every tool below already points at CloudRepo. Then regenerate each lockfile with the tool that wrote it, so the tool writes the new URLs itself. Afterwards read git diff of the lockfile: it should change URLs, and it shows any version that moved.
npm: package-lock.json
Section titled “npm: package-lock.json”Each package in package-lock.json has a resolved field. npm describes it in its lockfile page as “The place where the package was actually resolved from”, a tarball URL for a package that comes from a registry. By default npm replaces the host of a resolved URL only when it is https://registry.npmjs.org (replace-registry-host), so a resolved URL that names Nexus or Artifactory is used as it is written, and npm ci goes on downloading from there when your .npmrc already names CloudRepo.
Remove node_modules as well as the lockfile. npm keeps a hidden lockfile in node_modules, and with that folder in place npm install reads the old URLs back from it and writes them into the new lockfile.
rm -rf node_modules package-lock.jsonnpm installWith no lockfile, npm install resolves each dependency from the ranges in package.json, which npm calls “the source of truth for acceptable version ranges”, so the new lockfile can hold newer versions than the old one. Check the diff, run your tests, and end with npm ci. If you must keep every locked version, replace the old URL with the CloudRepo URL in each resolved line yourself and run npm ci.
Yarn: yarn.lock
Section titled “Yarn: yarn.lock”Yarn 1 writes resolved "<URL>#<hash>" for each package, as the example on its lockfile page shows, and that page says the file is “auto-generated and should be handled entirely by Yarn”. With a yarn.lock that is enough for package.json, Yarn’s install page says “the exact versions recorded in yarn.lock are installed, and yarn.lock will be unchanged”, so Yarn does not rewrite the URLs. Without one, Yarn “looks for the newest versions available that satisfy the constraints in package.json” and writes them to a new yarn.lock.
rm yarn.lockyarn installThe new file can hold newer versions than the old one, so check the diff and run your tests.
Yarn 2 and later read the registry from npmRegistryServer in .yarnrc.yml (Yarn configuration). A yarn.lock written by Yarn 4 lists a package from the registry by its resolution and checksum and holds no registry URL, so there is no URL to change in it. Set npmRegistryServer, run yarn install, and run the search again. If the search still finds the old host in yarn.lock, delete the file and run yarn install as above.
Poetry: poetry.lock
Section titled “Poetry: poetry.lock”For each package that comes from a source you named in pyproject.toml, poetry.lock holds a [package.source] table with the source’s url. Set the source as Poetry Repositories shows, then lock again. poetry install stops with “pyproject.toml changed significantly since poetry.lock was last generated” until you do, and poetry lock writes the new url. Poetry’s lock command says “packages that have already been added to the lock file before will not be updated”, so the versions stay.
poetry lockIf the search still finds the old host in poetry.lock, run poetry lock --regenerate. Poetry describes that option as “Ignore existing lock file and overwrite it with a new lock file created from scratch”, and says it and poetry update --lock “normally produce the same result”, which moves each dependency to its latest compatible version. Check the diff.
uv: uv.lock
Section titled “uv: uv.lock”uv.lock holds source = { registry = "<index URL>" } for each package that comes from an index, and the URL of each of its files. uv says the file “is managed by uv and should not be edited manually”. Set the index as uv Repositories shows, then lock again. With the index changed, uv lock --check and uv sync --locked stop with “The lockfile at uv.lock needs to be updated”, and uv lock writes the new URLs. uv “will prefer the previously locked versions of packages”, so the versions stay unless your constraints exclude them.
uv lockBeyond the files
Section titled “Beyond the files”The search reads the files that Git tracks, in the repositories you ran it in. Check these by hand:
- Settings that live in your home directory and not in a repository:
~/.m2/settings.xml,~/.gradle/gradle.properties,~/.npmrcandpip.conf. The page for each build tool shows its file: Pull Maven artifacts, Pull Gradle dependencies, Install npm packages and Install Python packages. - The variables and settings of your CI system, and of the build images it uses.
- A dependency bot that proposes updates: Dependabot and Renovate with CloudRepo.
- The steps of a CI job that publish: Move your CI off the JFrog CLI and Nexus staging.
- A script that calls the Nexus or Artifactory REST API, to fetch the latest version of an artifact or to upload a file: REST calls in your scripts after Nexus or Artifactory.
- Docker image names: Docker image names after Nexus or Artifactory.
Then build against CloudRepo
Section titled “Then build against CloudRepo”Run the search again: no file it lists should name Nexus or Artifactory. Then install from each lockfile with the command that never rewrites it, in a CI job or on a machine that cannot reach Nexus or Artifactory, so a URL you missed fails now and not on the day you switch it off:
# npmnpm ci# Yarn 1yarn install --frozen-lockfile# Yarn 2 and lateryarn install --immutable# Poetrypoetry install# uvuv sync --lockedFor Maven, Gradle and pip, run the build. Then follow step 6 of Migrate from Sonatype Nexus Repository or Migrate from JFrog Artifactory, which sets the order of the switch.