UiPath Documentation
uipath-cli
latest
false

UiPath CLI user guide

Dernière mise à jour 7 mai 2026

How-to: pack and publish a Solution

This page picks up where Your first pipeline stops. It assumes you already have the three-command flow working on a single tenant and now want to ship the same Solution across dev → stage → prod, pin versions for reproducibility, and know exactly how to back out a bad release.

If you have not yet packed a Solution end-to-end, read Your first pipeline first — everything here builds on uip solution pack / publish / deploy run.

What this guide covers

  • A versioning discipline that plays well with the Orchestrator feed.
  • Promoting the same package through multiple tenants without repacking.
  • Pinning the CLI and its tools so every build is reproducible.
  • Rolling back a broken release with uip solution packages delete and uip solution deploy uninstall.

Pick a version, then freeze it

uip solution pack --version controls both the .zip filename and the packageVersion that every downstream step consumes. The default is 1.0.0; a real pipeline should pass it explicitly.

Semantic versioning (MAJOR.MINOR.PATCH) is the scheme the Orchestrator feed sorts best. Two concrete rules make the difference between a clean history and an unsortable one:

  1. Never reuse a version. uip solution publish rejects a name+version pair that already exists in the feed. Treat a rejected publish as a build bug, not as something to "fix" by re-running pack.
  2. Use build metadata, not timestamps in the version core. Prefer 1.2.0-rc.3 over 1.2.0.20260424. The former sorts correctly in the feed; the latter is technically valid semver but harder to read at a glance.

A typical CI configuration:

# Build number from the pipeline, tag from git, combined for a valid pre-release
VERSION="1.2.0-ci.${BUILD_NUMBER}"

uip solution pack ./my-solution ./dist \
  --name my-solution \
  --version "$VERSION"

uip solution publish "./dist/my-solution.${VERSION}.zip"
# Build number from the pipeline, tag from git, combined for a valid pre-release
VERSION="1.2.0-ci.${BUILD_NUMBER}"

uip solution pack ./my-solution ./dist \
  --name my-solution \
  --version "$VERSION"

uip solution publish "./dist/my-solution.${VERSION}.zip"

The .zip path is deterministic (<outputDir>/<name>.<version>.zip) — see uip solution pack — so scripts can compute it without parsing JSON.

Promote one package across tenants

Pack and publish once per version, then re-deploy the same artifact into each tenant. Re-packing per environment risks drift; re-publishing the same version is also idempotent per (name, version), so if you publish twice by mistake, nothing breaks. Even so, one build = one publish is the cleanest contract.

uip solution publish and every uip solution deploy * subcommand accept --tenant <tenant-name> (short: -t) to override the tenant selected by the active session. For a CI promotion job:

VERSION="$1"   # e.g. 1.2.0-ci.456

for tenant in dev stage prod; do
  uip solution publish "./dist/my-solution.${VERSION}.zip" --tenant "$tenant"

  uip solution deploy run \
    --name "my-solution-${tenant}" \
    --package-name my-solution \
    --package-version "$VERSION" \
    --folder-name MySolution \
    --folder-path Shared \
    --tenant "$tenant"
done
VERSION="$1"   # e.g. 1.2.0-ci.456

for tenant in dev stage prod; do
  uip solution publish "./dist/my-solution.${VERSION}.zip" --tenant "$tenant"

  uip solution deploy run \
    --name "my-solution-${tenant}" \
    --package-name my-solution \
    --package-version "$VERSION" \
    --folder-name MySolution \
    --folder-path Shared \
    --tenant "$tenant"
done

Two notes:

  • publish is idempotent per tenant. Publishing the same (name, version) twice returns the existing PackageVersionKey instead of duplicating — see uip solution publish.
  • Deployment names should be tenant-scoped. Using my-solution-prod rather than my-solution makes uip solution deploy list readable and prevents accidental cross-environment deploy uninstall calls. --name identifies the deployment record, not the folder.

Parameterizing per-environment config

If your Solution has resources (queues, assets) that differ per tenant, generate the config file once and edit it per environment with deploy config set:

uip solution deploy config get my-solution --package-version "$VERSION" -d ./deploy-config.json

# Production uses a bigger retry count
uip solution deploy config set ./deploy-config.json MyQueue maxNumberOfRetries 5

uip solution deploy run \
  --name my-solution-prod \
  --package-name my-solution \
  --package-version "$VERSION" \
  --folder-name MySolution \
  --folder-path Shared \
  --config-file ./deploy-config.json \
  --tenant prod
uip solution deploy config get my-solution --package-version "$VERSION" -d ./deploy-config.json

# Production uses a bigger retry count
uip solution deploy config set ./deploy-config.json MyQueue maxNumberOfRetries 5

uip solution deploy run \
  --name my-solution-prod \
  --package-name my-solution \
  --package-version "$VERSION" \
  --folder-name MySolution \
  --folder-path Shared \
  --config-file ./deploy-config.json \
  --tenant prod

Pass an existing Orchestrator resource instead of a freshly-created one with deploy config link:

uip solution deploy config link ./deploy-config.json MyQueue \
  --name SharedProductionQueue \
  --folder-path "Shared/Production"
uip solution deploy config link ./deploy-config.json MyQueue \
  --name SharedProductionQueue \
  --folder-path "Shared/Production"

Pin the CLI and its tools

Reproducible pipelines pin every tool they depend on. The CLI is distributed on npm as @uipath/cli; uip solution … is provided by @uipath/solution-tool. Both follow semver.

# Pin the CLI exactly
npm install -g @uipath/cli@1.0.0

# Pre-install tools explicitly so the first command is not slower than the rest
uip tools install @uipath/solution-tool @uipath/orchestrator-tool
# Pin the CLI exactly
npm install -g @uipath/cli@1.0.0

# Pre-install tools explicitly so the first command is not slower than the rest
uip tools install @uipath/solution-tool @uipath/orchestrator-tool

Tool versions default to tracking the CLI's MAJOR.MINOR line, so pinning the CLI alone usually suffices. For strict per-patch reproducibility, pin the tool too:

uip tools install @uipath/solution-tool@1.0.2
uip tools install @uipath/solution-tool@1.0.2

Restaurer (Rollback)

Breaking production is rare; rolling back when you do matters. There are two levels of rollback — redeploy a known-good version (fast) and delete the bad artifact (clean).

Fast: re-deploy the previous version

If the bad deployment is live, install the previous version over it instead of uninstalling first. The deployment name stays the same; only --package-version changes:

uip solution deploy run \
  --name my-solution-prod \
  --package-name my-solution \
  --package-version 1.1.9 \
  --folder-name MySolution \
  --folder-path Shared \
  --tenant prod
uip solution deploy run \
  --name my-solution-prod \
  --package-name my-solution \
  --package-version 1.1.9 \
  --folder-name MySolution \
  --folder-path Shared \
  --tenant prod

This is the common case. Orchestrator re-activates the new deployment for the configuration key and leaves the folder's resources intact.

Clean: uninstall the deployment

If the Solution provisioned resources (queues, assets, triggers) that you do not want, call uip solution deploy uninstall:

uip solution deploy uninstall my-solution-prod --tenant prod
uip solution deploy uninstall my-solution-prod --tenant prod

This removes all provisioned resources and the Solution folder. It is a destructive operation — confirm the deployment name with deploy list before running it, especially in a loop over tenants.

Retire the artifact

Once nothing references a bad version, remove it from the tenant feed with uip solution packages delete:

uip solution packages delete my-solution 1.2.0-ci.456 --tenant prod
uip solution packages delete my-solution 1.2.0-ci.456 --tenant prod

There is no soft-delete; this is permanent. Keep the deletion to a small window — the command accepts exactly one packageVersion at a time, so scripting bulk cleanups requires a listfilterxargs pattern. See the packages delete reference for a full example.

Checking what you have

Before any of the above, get the ground truth:

# What is in the feed?
uip solution packages list --take 50 \
  --output-filter "Data[?packageName=='my-solution']"

# What is deployed?
uip solution deploy list --folder-path Shared --take 50
# What is in the feed?
uip solution packages list --take 50 \
  --output-filter "Data[?packageName=='my-solution']"

# What is deployed?
uip solution deploy list --folder-path Shared --take 50

CI-ready snippet

Combining the steps — a shell script that any CI system can run as-is:

#!/usr/bin/env bash
set -euo pipefail

VERSION="$1"                          # e.g. 1.2.0-ci.456
SOLUTION_DIR="./my-solution"
OUT_DIR="./dist"

# 1. Log in (External App in CI)
uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT_DEV"

# 2. Pack once
uip solution pack "$SOLUTION_DIR" "$OUT_DIR" \
  --name my-solution \
  --version "$VERSION"

PKG="${OUT_DIR}/my-solution.${VERSION}.zip"

# 3. Publish + deploy to each tenant
for env_name in dev stage prod; do
  tenant_var="UIPATH_TENANT_$(echo "$env_name" | tr a-z A-Z)"
  tenant="${!tenant_var}"

  uip solution publish "$PKG" --tenant "$tenant"
  uip solution deploy run \
    --name "my-solution-${env_name}" \
    --package-name my-solution \
    --package-version "$VERSION" \
    --folder-name MySolution \
    --folder-path Shared \
    --tenant "$tenant"
done
#!/usr/bin/env bash
set -euo pipefail

VERSION="$1"                          # e.g. 1.2.0-ci.456
SOLUTION_DIR="./my-solution"
OUT_DIR="./dist"

# 1. Log in (External App in CI)
uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT_DEV"

# 2. Pack once
uip solution pack "$SOLUTION_DIR" "$OUT_DIR" \
  --name my-solution \
  --version "$VERSION"

PKG="${OUT_DIR}/my-solution.${VERSION}.zip"

# 3. Publish + deploy to each tenant
for env_name in dev stage prod; do
  tenant_var="UIPATH_TENANT_$(echo "$env_name" | tr a-z A-Z)"
  tenant="${!tenant_var}"

  uip solution publish "$PKG" --tenant "$tenant"
  uip solution deploy run \
    --name "my-solution-${env_name}" \
    --package-name my-solution \
    --package-version "$VERSION" \
    --folder-name MySolution \
    --folder-path Shared \
    --tenant "$tenant"
done

With set -euo pipefail, any failure aborts the loop at the failing tenant. Later tenants are unaffected — the partial promotion can then be re-run or rolled back explicitly.

Prochaines étapes

Cette page vous a-t-elle été utile ?

Connecter

Besoin d'aide ? Assistance

Vous souhaitez apprendre ? UiPath Academy

Vous avez des questions ? UiPath Forum

Rester à jour