Set Up a Build Tool with JFrog CLI

Set up a build tool with JFrog Artifactory using JFrog CLI. This tutorial walks through the full workflow with npm, then shows how to adapt for any supported build tool.

This topic covers the following tasks:


Prerequisites

  • JFrog CLI installedInstallation guide
  • JFrog CLI authenticated — Run jf config add to configure a server connection (Configuring the CLI)
  • npm installed — Or your build tool of choice
  • An npm project with package.json (or create one for testing)

What You Will Do

  1. Configure npm to use Artifactory
  2. Install npm dependencies via Artifactory
  3. Publish an npm package
  4. Collect and publish build information

How do I configure npm for Artifactory?

Generate npm configuration that points your project to Artifactory for resolving and deploying packages. Run this in your project directory.

To configure npm for Artifactory:

Interactive configuration:

cd <your-project-dir>
jf npm-config

Non-interactive example:

jf npm-config --server-id-resolve=<server-id> --repo-resolve=<repo-name> --server-id-deploy=<server-id> --repo-deploy=<repo-name>

Replace <server-id> and <repo-name> with your Artifactory server ID and repository names. This creates or updates .jfrog/projects/npm.yaml in your project.

To see all available options:

jf npm-config --help

How do I install dependencies through Artifactory?

Install dependencies through Artifactory. The CLI records build information when you pass --build-name and --build-number.

To install dependencies through Artifactory:

jf npm install --build-name=<build-name> --build-number=<build-number>

Or without build information:

jf npm install

Example for CI:

jf npm ci --build-name=my-app --build-number=$BUILD_NUMBER

How do I publish a package to Artifactory?

Publish your package to the configured Artifactory repository. Include build information for traceability.

To publish the package to Artifactory:

jf npm publish --build-name=<build-name> --build-number=<build-number>

How do I enrich and publish build information?

After running npm commands with --build-name and --build-number, enrich the build-info with environment and Git context, then publish.

To enrich and publish build information:

# Capture environment variables (CI build URL, job name, etc.)
jf rt build-collect-env <build-name> <build-number>

# Attach Git commit info (hash, branch, message)
jf rt build-add-git <build-name> <build-number>

# Publish the enriched build-info to Artifactory
jf rt build-publish <build-name> <build-number>

Example:

jf rt build-collect-env my-app 1
jf rt build-add-git my-app 1
jf rt bp my-app 1

The build-collect-env and build-add-git steps are optional but recommended in CI/CD pipelines. They add traceability to your builds — linking each build to its source commit and build environment.


Complete Workflow Example

# 1. Configure npm (run once per project)
jf npm-config --server-id-resolve=my-server --repo-resolve=npm-virtual --server-id-deploy=my-server --repo-deploy=npm-local

# 2. Install dependencies
jf npm install --build-name=my-app --build-number=1

# 3. Publish the package
jf npm publish --build-name=my-app --build-number=1

# 4. Enrich and publish build information
jf rt build-collect-env my-app 1
jf rt build-add-git my-app 1
jf rt build-publish my-app 1

Verifying Success

After completing the workflow, verify that everything worked:

Check that artifacts were uploaded:

jf rt search npm-local/my-package/

Check that build-info was published:

jf rt curl -XGET "/api/build/my-app/1"

Or visit Artifactory UI > Builds > my-app > 1 to see the build-info with its dependencies, artifacts, environment variables, and Git context.


CI/CD Integration

Bash (Jenkins / GitLab CI)

jf config add ci-server --url=$JFROG_URL --access-token=$JFROG_ACCESS_TOKEN --interactive=false
jf npm-config --server-id-resolve=ci-server --repo-resolve=npm-virtual --server-id-deploy=ci-server --repo-deploy=npm-local
jf npm ci --build-name=$BUILD_NAME --build-number=$BUILD_NUMBER
jf npm publish --build-name=$BUILD_NAME --build-number=$BUILD_NUMBER
jf rt build-collect-env $BUILD_NAME $BUILD_NUMBER
jf rt build-add-git $BUILD_NAME $BUILD_NUMBER
jf rt build-publish $BUILD_NAME $BUILD_NUMBER

GitHub Actions

# .github/workflows/build.yml
steps:
  - uses: actions/checkout@v4
  - name: Setup JFrog CLI
    uses: jfrog/setup-jfrog-cli@v4
    env:
      JF_URL: ${{ vars.JF_URL }}
      JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
  - name: Configure npm
    run: jf npm-config --server-id-resolve=setup-jfrog-cli-server --repo-resolve=npm-virtual --server-id-deploy=setup-jfrog-cli-server --repo-deploy=npm-local
  - name: Install dependencies
    run: jf npm ci --build-name=my-app --build-number=${{ github.run_number }}
  - name: Enrich and publish build info
    run: |
      jf rt build-collect-env my-app ${{ github.run_number }}
      jf rt build-add-git my-app ${{ github.run_number }}
      jf rt build-publish my-app ${{ github.run_number }}

Coming from the UI? If you have been configuring build tool integrations through the Artifactory UI under Administration > Repositories, the *-config commands create the same association between your project and Artifactory repositories — but locally, so your builds resolve dependencies through Artifactory automatically.


Adapting for Other Build Tools

This tutorial uses npm, but the pattern is the same for all build tools:

Build ToolConfig CommandBuild CommandPublish Command
npmjf npm-configjf npm installjf npm publish
Mavenjf mvn-configjf mvn clean installVia deploy goal
Gradlejf gradle-configjf gradle buildVia publish tasks
pipjf pip-configjf pip installjf twine upload
Gojf go-configjf go buildjf go-publish
Dockerjf docker pull / buildjf docker push
Yarnjf yarn-configjf yarn install
NuGetjf nuget-configjf nuget restore
Poetryjf poetry-configjf poetry installjf poetry publish

Always finish with jf rt build-publish <name> <number> to send build information to Artifactory.

End-to-End: Python (pip + twine)

# Configure
jf pip-config --server-id-resolve=my-server --repo-resolve=pypi-virtual \
    --server-id-deploy=my-server --repo-deploy=pypi-local

# Install dependencies
jf pip install -r requirements.txt --build-name=my-python-app --build-number=1

# Build and publish the package
python -m build
jf twine upload dist/* --build-name=my-python-app --build-number=1

# Enrich and publish build-info
jf rt build-collect-env my-python-app 1
jf rt build-add-git my-python-app 1
jf rt build-publish my-python-app 1

End-to-End: Java (Maven)

# Configure
jf mvn-config --server-id-resolve=my-server \
    --repo-resolve-releases=libs-release --repo-resolve-snapshots=libs-snapshot \
    --server-id-deploy=my-server \
    --repo-deploy-releases=libs-release-local --repo-deploy-snapshots=libs-snapshot-local

# Build (artifacts deploy automatically at install phase)
jf mvn clean install -DskipTests --build-name=my-java-app --build-number=1

# Enrich and publish build-info
jf rt build-collect-env my-java-app 1
jf rt build-add-git my-java-app 1
jf rt build-publish my-java-app 1

End-to-End: Go

# Configure
jf go-config --server-id-resolve=my-server --repo-resolve=go-virtual \
    --server-id-deploy=my-server --repo-deploy=go-local

# Build
jf go build --build-name=my-go-app --build-number=1

# Publish the module
jf go-publish v1.0.0 --build-name=my-go-app --build-number=1

# Enrich and publish build-info
jf rt build-collect-env my-go-app 1
jf rt build-add-git my-go-app 1
jf rt build-publish my-go-app 1

End-to-End: Docker

# Login to the Docker registry
jf docker login acme.jfrog.io

# Build and push
jf docker build -t acme.jfrog.io/docker-local/my-app:1.0.0 .
jf docker push acme.jfrog.io/docker-local/my-app:1.0.0 \
    --build-name=my-docker-app --build-number=1

# Enrich and publish build-info
jf rt build-collect-env my-docker-app 1
jf rt build-add-git my-docker-app 1
jf rt build-publish my-docker-app 1

Common Issues and Fixes

ProblemFix
"no config file was found"Run jf <tool>-config in the project directory first
Resolution fails with 404Check that the repo name in config matches an existing Artifactory repository
Build info shows 0 dependenciesEnsure you passed --build-name and --build-number to the build command
jf rt build-publish failsVerify your server configuration has a valid access token with deploy permissions

Build Succeeded but Nothing Was Deployed

JFrog CLI invokes your package manager and passes native flags through unchanged. If your build finishes successfully but no artifacts appear in Artifactory (or only build-info is recorded), check whether your native tool requires you to select a target to publish:

  • Gradle (Artifactory Gradle plugin): You must tell the plugin which publication(s) to deploy.
  • Maven: Make sure you run a phase/goal that actually deploys (e.g., deploy, or install if your setup deploys during install). The CLI accepts Maven args as-is.
  • npm / Yarn: Install only resolves. Use jf npm publish (or jf rt upload) to push a package.

Frequently Asked Questions

What is the difference between jf npm install and jf npm ci?

jf npm install resolves dependencies from package.json and may update package-lock.json. jf npm ci installs strictly from package-lock.json without modifying it — preferred in CI/CD for reproducible builds. Both collect build-info when --build-name and --build-number are provided.

Do I need to run jf rt build-publish after every build?

Only if you want build-info stored in Artifactory. The --build-name and --build-number flags collect build-info locally. Running jf rt build-publish uploads that record to Artifactory, enabling traceability, promotion, and Xray scanning.

Can I adapt this tutorial for Maven, Gradle, or other tools?

Yes. The three-step pattern (configure, build, publish build-info) is identical for all tools.

What if my build succeeds but no artifacts appear in Artifactory?

Check whether your build tool requires an explicit publish step. For npm, run jf npm publish. For Gradle, configure the Artifactory plugin's publication target.


Related Topics