Use Poetry with JFrog CLI

Configure and run jf poetry with JFrog Artifactory for Wrapped and Native Mode builds and build-info.

Run Poetry commands with Artifactory integration and optional build-info collection.

This topic covers the following tasks:

When to Use

Use jf poetry if your Python project uses Poetry (with pyproject.toml) for dependency management. For pip-based projects, use jf pip. For Pipenv-based projects, use jf pipenv. For uv-managed projects, use jf uv.

📘

Package Alias (Ghost Frog)

To run native poetry commands without the jf prefix, see Use JFrog CLI Package Alias.

Prerequisites

  • Poetry must be installed and available on your $PATH.
    • Recommended: pipx install poetry (automatically adds Poetry to your PATH).
    • pip: pip install poetry. On macOS, pip installs Poetry to ~/Library/Python/X.Y/bin/, which is not on $PATH by default. After installing, run:
      export PATH="$PATH:$(python3 -m site --user-base)/bin"
      Add this line to your shell profile (~/.zshrc or ~/.bashrc) to make it permanent.
  • Run jf poetry-config in the project directory before the first install (Wrapped Mode only).
  • Configure a server with jf config add or jf c add.
  • Authentication to Artifactory is required.
  • For Native Mode, configure Poetry via Artifactory's Set Me Up instructions instead.

Configuration: jf poetry-config

Generate Poetry build configuration for dependency resolution. Run this once per project before your first install.

To configure Poetry for Artifactory:

  1. From your project directory, run jf poetry-config with your Artifactory server ID and PyPI resolution repository (see Non-Interactive Configuration with Flags).
  2. Confirm the generated config under .jfrog/projects/poetry.yaml (see How to Verify).

Synopsis

jf poetry-config [options]

Aliases: poc

Configuration Options

FlagDefaultDescription
--globalfalseSet to true for global configuration (all projects). Specific projects can override.
--repo-resolveRepository for dependencies resolution
--server-id-resolveArtifactory server ID for resolution. Configure with jf config add.

Configuration Examples

View Help

jf poetry-config --help

Non-Interactive Configuration with Flags

jf poetry-config --server-id-resolve=<server-id> --repo-resolve=<repo-name>

Where:

  • <server-id>: The server ID configured using jf config add
  • <repo-name>: The name of the PyPI repository in Artifactory

For example:

jf poetry-config --server-id-resolve=my-server --repo-resolve=pypi-virtual

Why Run Config First?

You must run jf poetry-config before jf poetry install (Wrapped Mode only). The config creates .jfrog/projects/poetry.yaml for dependency resolution through Artifactory. Without it, jf poetry does not know where to fetch packages.

👍

Shortcut

In CI/CD, pass all flags non-interactively so the config step is fully automated and reproducible.

Configuration Notes

  • Config sets resolution only: jf poetry-config configures dependency resolution but not a deployer repository. To publish, pass --repository directly on jf poetry publish (Wrapped Mode) or use native poetry publish (Native Mode).
  • Run once per project: Re-run when changing the resolution repository.

Expected Output

$ jf poetry-config --server-id-resolve=my-server --repo-resolve=pypi-virtual
[Info] poetry build config successfully created.

How to Verify

After running, confirm the configuration exists:

cat .jfrog/projects/poetry.yaml

Expected file contents:

version: 1
type: poetry
resolver:
    repo: pypi-virtual
    serverId: my-server

Build: jf poetry

Run Poetry commands with Artifactory integration and optional build-info collection.

To run Poetry with Artifactory integration:

  1. Ensure jf poetry-config has been run in the project directory when using Wrapped Mode (see Configuration).
  2. Run jf poetry with the Poetry subcommand and arguments you need, adding --build-name and --build-number when you want build-info (see Build Examples).

Synopsis

jf poetry <poetry-arguments> [options]

Aliases: none

Arguments

ArgumentRequiredDescription
<poetry-arguments>YesArguments and options for the poetry command (for example, install, add)

Build Options

FlagDefaultDescription
--build-nameBuild name for build-info. Requires --build-number.
--build-numberBuild number for build-info. Requires --build-name.
--moduleOptional module name for build-info. Requires --build-name and --build-number.
--projectJFrog Artifactory project key

Build Examples

Help

jf poetry --help
📘

Note

jf poetry --help passes --help through to the native Poetry client and shows Poetry's own help page. JFrog-specific flags (--build-name, --build-number, --module, --project) are intercepted by JFrog CLI and do not appear in Poetry's help output. Refer to the Build Options table for JFrog-specific flags.

Install with Build-Info

jf poetry install --build-name=my-app --build-number=1

Expected output (Wrapped Mode):

[Info] Running Poetry install.
[Info] Added tool.poetry.source name:"<repo-name>" url:"https://<server>/artifactory/api/pypi/<repo-name>"
[Info] Running Poetry update
Updating dependencies
Resolving dependencies...
Writing lock file
📘

Note

In Wrapped Mode, JFrog CLI automatically injects a [[tool.poetry.source]] entry into your pyproject.toml and may run poetry update to resolve dependencies. This is expected behavior and modifies poetry.lock. Switch to Native Mode if you require a fully deterministic lockfile.

Add Dependencies

jf poetry add <package-name>

Poetry Execution Modes

JFrog CLI supports two execution modes for Poetry.

Wrapped Mode (Default)

  • Uses jf poetry-config settings
  • Injects tool.poetry.source entries into pyproject.toml
  • May call poetry update during dependency resolution
  • May modify poetry.lock
  • Automatically collects build-info when provided --build-name / --build-number

Native Mode

Enable using:

export JFROG_RUN_NATIVE=true

In Native Mode, JFrog CLI:

  • Delegates to the native Poetry client without injecting configuration
  • Does not inject tool.poetry.source into pyproject.toml
  • Does not call poetry update
  • Does not modify poetry.lock
  • Does not apply jf poetry-config values or JFrog CLI YAML (.jfrog/projects/*.yaml) configuration
  • Relies entirely on Poetry's own configuration (as set via Artifactory Set Me Up)
  • Still collects build-info when --build-name and --build-number are provided via jf poetry
  • Ensures deterministic, reproducible builds
📘

Prerequisite for Native Mode

Your pyproject.toml must contain a [[tool.poetry.source]] entry pointing to your Artifactory PyPI repository for Native Mode to route traffic through Artifactory. This entry can be added manually, or it will already be present if you previously ran a Wrapped Mode install. You can also add it using Artifactory's Set Me Up instructions.

Install: Wrapped vs Native

Wrapped Mode Install

jf poetry install --build-name=my-python-app --build-number=1.2.0

Wrapped Mode behavior:

  • May implicitly run poetry update
  • May modify poetry.lock
  • May inject repository sources into pyproject.toml

Use Native Mode if you require full lockfile fidelity.

Native Mode Install

export JFROG_RUN_NATIVE=true

# With build-info collection
jf poetry install --build-name=my-python-app --build-number=1.2.0

# Or directly (no build-info)
poetry install
📘

Note

In Native Mode, you can use either jf poetry install (which delegates to native Poetry and collects build-info when --build-name and --build-number are provided) or poetry install directly (no build-info). Poetry must be configured using Artifactory's Set Me Up instructions to authenticate and resolve from Artifactory.

Publish: Wrapped vs Native

Wrapped Mode Publish

jf poetry publish --repository pypi-local --no-interaction --build-name=my-python-app --build-number=1.2.0
❗️

Important

Use --repository (Poetry's native flag, also available as -r) to specify the target repository. The --no-interaction flag suppresses Poetry's confirmation prompt (Build anyway? (yes/no)) when existing dist files are present. This flag is required in CI/CD environments where no TTY is available.

Behavior:

  • May inject tool.poetry.source into pyproject.toml
  • May update dependency metadata

Use Native Mode to prevent any modifications.

Native Mode Publish

export JFROG_RUN_NATIVE=true

# With build-info collection
jf poetry publish --no-interaction --build-name=my-python-app --build-number=1.2.0

# Or directly (no build-info)
poetry build
poetry publish --no-interaction -r <REPO_ALIAS>

Credentials must be configured via Set Me Up.

Environment Variable

VariablePurposeDefault
JFROG_RUN_NATIVEEnables Native Mode and bypasses Wrapped Mode entirelyfalse

For a cross-tool comparison of Native Mode across Maven, Gradle, npm, and Poetry, see the dedicated Native Mode page.

Universal Package Note

JFrog CLI is a pass-through to Poetry for execution and output. Output format and behavior belong to Poetry. If Poetry changes its output in a newer version, JFrog CLI honors that without any custom adjustment.

📘

Note

The jf poetry-config configuration is used only in Wrapped Mode. Native Mode ignores this entirely.


Important Notes

  • Config required first: Run jf poetry-config in the project directory before your first install (Wrapped Mode only).
  • Resolution only: Poetry config currently supports dependency resolution. For publishing, use jf poetry publish (Wrapped Mode) or Poetry's native poetry publish (Native Mode).
  • Poetry commands: All standard Poetry arguments work (install, add, update, lock, and others).
  • Build-info: Use --build-name and --build-number, then publish with jf rt build-publish.

CI/CD Example: GitHub Actions

📘

Package Alias (Ghost Frog)

To run poetry without the jf prefix, enable Package Alias in setup-jfrog-cli and set JFROG_CLI_GHOST_FROG=true. If you install the tool after the action (for example setup-java or setup-node), re-pin the alias path to GITHUB_PATH. See Use JFrog CLI Package Alias.

# .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: Setup Python
    uses: actions/setup-python@v5
    with:
      python-version: '3.12'
  - name: Install Poetry
    run: |
      pip install poetry
      echo "$(python3 -m site --user-base)/bin" >> $GITHUB_PATH
  - name: Configure Poetry
    run: jf poetry-config --server-id-resolve=setup-jfrog-cli-server --repo-resolve=pypi-virtual
  - name: Install dependencies
    run: jf poetry install --build-name=my-python-app --build-number=${{ github.run_number }}
  - name: Publish package
    run: jf poetry publish --repository pypi-local --no-interaction --build-name=my-python-app --build-number=${{ github.run_number }}
  - name: Publish build info
    run: jf rt build-publish my-python-app ${{ github.run_number }}

Troubleshooting

SymptomCauseFix
command not found: poetryPoetry not on $PATH (common after pip install)Add Poetry to PATH: export PATH="$PATH:$(python3 -m site --user-base)/bin". Use pipx install poetry to avoid this permanently.
no config file was foundjf poetry-config was not run (Wrapped Mode)Run jf poetry-config in the project directory
404 on jf poetry installResolution repository does not exist or name is wrongVerify the repo name matches an existing PyPI virtual repository in Artifactory
401 / 403 errorsInvalid credentials or insufficient permissionsRe-run jf config add with a valid access token
poetry.lock modified unexpectedlyWrapped Mode may run poetry update implicitlySwitch to Native Mode (export JFROG_RUN_NATIVE=true) for lockfile fidelity
The option "--repo" does not exist--repo is not a valid flag for jf poetry publishUse --repository (or -r) instead: jf poetry publish --repository <local-repo-name> --no-interaction ...
jf poetry publish hangs on Build anyway? (yes/no)Poetry prompts for confirmation when dist files existAdd --no-interaction to the publish command to suppress the prompt
jf poetry publish fails with "repo not configured"No target repository specifiedPass --repository <local-repo-name> directly on the publish command
[Warn] couldn't extract payload from Access TokenUsing a JFrog Platform reference token (non-JWT)This warning is informational only. Commands still authenticate correctly. If using basic auth, provide a username via jf config add.
Native Mode not resolving from ArtifactoryNo [[tool.poetry.source]] in pyproject.tomlAdd a source entry manually or run a Wrapped Mode install first. Alternatively, configure Poetry using Artifactory's Set Me Up

Enable debug logging: export JFROG_CLI_LOG_LEVEL=DEBUG


Frequently Asked Questions

This section provides answers to frequently asked questions about using Poetry with JFrog CLI.

plusFAQs
Q: Does jf poetry-config affect Native Mode?

A: No. Native Mode ignores jf poetry-config and the .jfrog/projects/poetry.yaml configuration entirely. See Native Mode.

Q: Can Native Mode collect build-info?

A: Yes, when you run jf poetry (not native poetry) with --build-name and --build-number. See Build-Info Flags in Native Mode for details across all tools.

Related Topics


Did this page help you?