# Change every Nexus and Artifactory URL in your builds, lockfiles included

> Map Nexus 2, Nexus 3 and Artifactory URLs to CloudRepo's, find every one in your builds, and regenerate npm, Yarn, Poetry and uv lockfiles.

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](/docs/migrate/from-nexus.html) or [Migrate from JFrog Artifactory](/docs/migrate/from-jfrog.html).

## Nexus URLs and their CloudRepo URLs

Nexus Repository 3 writes a repository’s URL with the repository’s name after `/repository/`, for [Maven](https://help.sonatype.com/en/maven-repositories.html), [npm](https://help.sonatype.com/en/configuring-npm.html) and [Python](https://help.sonatype.com/en/configure-pypi-with-nexus.html). 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](https://help.sonatype.com/en/repository-manager-2.html) 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

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](https://docs.jfrog.com/artifactory/docs/maven-repositories), [npm](https://docs.jfrog.com/artifactory/docs/npm-repositories) and [Python](https://docs.jfrog.com/artifactory/docs/pypi-repositories) 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](/docs/consume/maven.html), [Install npm packages](/docs/consume/npm.html) and [Install Python packages](/docs/consume/python.html) 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](/docs/migrate/artifactory-and-nexus-terms.html) says what takes their place.

## 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:

**Terminal**

```bash
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

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

Each package in `package-lock.json` has a `resolved` field. npm describes it in [its lockfile page](https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json) 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`](https://docs.npmjs.com/cli/v11/using-npm/config#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](https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json#hidden-lockfiles) 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.

**Terminal**

```bash
rm -rf node_modules package-lock.json
npm install
```

With no lockfile, `npm install` resolves each dependency from the ranges in `package.json`, which npm calls [“the source of truth for acceptable version ranges”](https://docs.npmjs.com/cli/v11/commands/npm-install#how-npm-install-uses-package-lockjson), 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

Yarn 1 writes `resolved "<URL>#<hash>"` for each package, as the example on [its lockfile page](https://classic.yarnpkg.com/en/docs/yarn-lock) 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](https://classic.yarnpkg.com/en/docs/cli/install) 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`.

**Terminal**

```bash
rm yarn.lock
yarn install
```

The 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](https://yarnpkg.com/configuration/yarnrc#npmRegistryServer)). 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

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](/docs/formats/poetry.html#add-cloudrepo-as-an-explicit-source) 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](https://python-poetry.org/docs/cli/#lock) says “packages that have already been added to the lock file before will not be updated”, so the versions stay.

**Terminal**

```bash
poetry lock
```

If 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

`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”](https://docs.astral.sh/uv/concepts/projects/layout/#the-lockfile). Set the index as [uv Repositories](/docs/formats/uv.html#pin-private-packages-in-a-project) 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”](https://docs.astral.sh/uv/concepts/projects/sync/#upgrading-locked-package-versions), so the versions stay unless your constraints exclude them.

**Terminal**

```bash
uv lock
```

## 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`, `~/.npmrc` and `pip.conf`. The page for each build tool shows its file: [Pull Maven artifacts](/docs/consume/maven.html), [Pull Gradle dependencies](/docs/consume/gradle.html), [Install npm packages](/docs/consume/npm.html) and [Install Python packages](/docs/consume/python.html).
- 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](/docs/ci/dependabot-and-renovate.html).
- The steps of a CI job that publish: [Move your CI off the JFrog CLI and Nexus staging](/docs/migrate/move-ci-off-jfrog-cli-and-nexus-staging.html).
- 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](/docs/migrate/rest-api-calls-in-scripts.html).
- Docker image names: [Docker image names after Nexus or Artifactory](/docs/migrate/docker-image-names.html).

## 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:

**Terminal**

```bash
# npm
npm ci
# Yarn 1
yarn install --frozen-lockfile
# Yarn 2 and later
yarn install --immutable
# Poetry
poetry install
# uv
uv sync --locked
```

For Maven, Gradle and pip, run the build. Then follow step 6 of [Migrate from Sonatype Nexus Repository](/docs/migrate/from-nexus.html#6-check-then-cut-over) or [Migrate from JFrog Artifactory](/docs/migrate/from-jfrog.html#6-check-then-cut-over), which sets the order of the switch.

---

The page: https://www.cloudrepo.io/docs/migrate/repoint-builds.html
