UiPath Documentation
uipath-cli
latest
false

UiPath CLI user guide

Última atualização 7 de mai de 2026

How-to: deploy to Orchestrator from CI

This page covers what every CI pipeline deploying a UiPath Solution needs, regardless of whether you run on Azure DevOps, GitHub Actions, Jenkins, or GitLab: auth, caching, tool pre-install, and version pinning. The platform-specific syntax lives in the recipe pages — this one gives you the moving parts so you can read any of them with confidence.

The shape of a good CI pipeline

A production pipeline that ships a Solution always has the same five stages:

  1. Set up Node.js (version 18 or later).
  2. Install @uipath/cli at a pinned version.
  3. Pre-install the tools you will use (so the first uip call is not slower than the rest).
  4. Authenticate with an External Application using the env. prefix for secrets.
  5. Pack, publish, deploy — and optionally test.

Stage 4 is the one that varies the most between platforms, because secret syntax is platform-specific. Stages 1–3 and 5 are nearly identical everywhere.

Authentication: External Application + env. prefix

In a headless environment you authenticate with an External Application (client credentials). See Authentication — Flow 2 for how to create one in the UiPath portal.

Store the credentials in your platform's secret store (never in source control, never in a plain env var file). Pass them to uip login with the special env. prefix:

uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT"
uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT"

The env.VAR_NAME prefix tells uip to read the value from the VAR_NAME environment variable at runtime. This keeps the secret out of shell history and process listings — unlike --client-secret "$UIPATH_CLIENT_SECRET", which expands on the command line and can leak via ps.

AVISO:

Do not rely on implicit env-var reading. Setting UIPATH_CLIENT_ID / UIPATH_CLIENT_SECRET alone, without the flag, will not authenticate you — that feature was removed prior to CLI 1.0. Always pass the flag; use env.VAR_NAME when you want the value resolved from the environment.

In your pipeline, inject the secrets into the step's environment under the exact variable names you reference:

PlataformaSecret syntax in YAML / GroovyShape passed to the step
GitHub Actions${{ secrets.UIPATH_CLIENT_ID }} presente env:UIPATH_CLIENT_ID: <value>
Azure DevOps$(UIPATH_CLIENT_ID) from a variable group in env:UIPATH_CLIENT_ID: $(UIPATH_CLIENT_ID)
JenkinscredentialsId: 'UIPATH_CLIENT_ID' inside withCredentialsexported as $UIPATH_CLIENT_ID
GitLab CIUIPATH_CLIENT_ID CI/CD variable, marked Protected+Masked$UIPATH_CLIENT_ID presente script

In every case, the uip login command itself looks identical — --client-id env.UIPATH_CLIENT_ID --client-secret env.UIPATH_CLIENT_SECRET. Only how the env var arrives in the step changes.

Session storage

uip login persists the session inside a .uipath/ folder. On most CI runners the working directory is already stateless, so the session ends with the job — which is the desired behaviour. If your runner is persistent, either remove the session with uip logout at the end of the job or set --file to a job-local path. See Sessions and credentials.

Multiple organizations in one pipeline

A session holds one organization and one tenant at a time. To target different UiPath organizations from the same pipeline — for example, to promote a Solution from a build org into a customer org — re-run uip login between the two blocks with a different External Application. Each login overwrites the previous session.

Create one External App per org (each with its own OR.* scopes). Store both client IDs and secrets in the pipeline's secret store under distinct names:

set -euo pipefail

# --- Organization A ---
uip login \
  --client-id env.ORGA_CLIENT_ID \
  --client-secret env.ORGA_CLIENT_SECRET \
  --tenant Prod

uip or folders list
uip solution pack ./my-solution ./dist --version "$SOLUTION_VERSION"
uip solution publish "./dist/my-solution.$SOLUTION_VERSION.zip"

# --- Organization Bthis overwrites the previous session ---
uip login \
  --client-id env.ORGB_CLIENT_ID \
  --client-secret env.ORGB_CLIENT_SECRET \
  --tenant Prod

uip solution publish "./dist/my-solution.$SOLUTION_VERSION.zip"
uip solution deploy run \
  --name "my-solution-$GIT_SHA" \
  --package-name my-solution \
  --package-version "$SOLUTION_VERSION" \
  --folder-name MySolution \
  --folder-path Shared
set -euo pipefail

# --- Organization A ---
uip login \
  --client-id env.ORGA_CLIENT_ID \
  --client-secret env.ORGA_CLIENT_SECRET \
  --tenant Prod

uip or folders list
uip solution pack ./my-solution ./dist --version "$SOLUTION_VERSION"
uip solution publish "./dist/my-solution.$SOLUTION_VERSION.zip"

# --- Organization B — this overwrites the previous session ---
uip login \
  --client-id env.ORGB_CLIENT_ID \
  --client-secret env.ORGB_CLIENT_SECRET \
  --tenant Prod

uip solution publish "./dist/my-solution.$SOLUTION_VERSION.zip"
uip solution deploy run \
  --name "my-solution-$GIT_SHA" \
  --package-name my-solution \
  --package-version "$SOLUTION_VERSION" \
  --folder-name MySolution \
  --folder-path Shared

Same pattern for different tenants within a single org — except tenants don't need a second login. Pass --tenant <name> on any uip or … call to override the session tenant for a single command, without re-authenticating.

Observação:

This is a serial pattern. Each uip login overwrites the stored session, so only one org is reachable at any moment. If you need to run commands against two orgs simultaneously (for example, parallel matrix jobs), give each job its own runner or its own --file / HOME scope — see Sessions and credentials.

Pre-install tools to keep build times deterministic

The CLI ships with no tools pre-installed. The first time you run a verb from an uninstalled tool, uip auto-installs it from npm — which is fine on a laptop but adds 5–10 seconds of latency to the first command on a stateless CI runner.

Install the tools you use upfront, as a separate step:

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

Add @uipath/test-manager-tool when you run Test Manager, @uipath/agent-tool when you deploy Agents, @uipath/resource-tool when you manage assets/queues/buckets outside of a Solution. See the tools reference for the full list.

Auto-install is a no-op when the tool is already installed, so the pre-install step is the only behavior change you need — nothing else in your pipeline has to know about it.

Observação:

CI=true does not disable auto-install. There is no env-var switch; pre-install is the only way to avoid it. See Installing UiPath CLI — Controlling tool auto-install.

Cache the npm global directory

CI runners that re-install @uipath/cli on every job waste 20–40 seconds of download and decompression. Caching the npm global node_modules directory turns that into a cache hit — usually under a second.

The directory to cache is the one reported by npm root -g (typically ~/.npm-global/lib/node_modules on Linux/macOS, %APPDATA%\npm\node_modules on Windows). Key the cache on the CLI version you pin, so a version bump invalidates the cache cleanly:

PlataformaCache mechanism
GitHub Actionsactions/cache with path: ~/.npm-global/lib/node_modules and key: uip-${{ version }}-${{ runner.os }}
Azure DevOpsCache@2 keyed on the version variable
JenkinsThe Job Cacher plugin or a manually-managed workspace folder
GitLab CITop-level cache: block with key: uip-$CLI_VERSION

When the cache hits, you can skip both npm install -g @uipath/cli and uip tools install — the uip executable and its tools are already on the PATH. A small bash guard does this cleanly:

if ! command -v uip >/dev/null; then
  npm install -g "@uipath/cli@${CLI_VERSION}"
  uip tools install @uipath/orchestrator-tool @uipath/solution-tool
fi
if ! command -v uip >/dev/null; then
  npm install -g "@uipath/cli@${CLI_VERSION}"
  uip tools install @uipath/orchestrator-tool @uipath/solution-tool
fi

The concrete YAML/Groovy for each platform is in the recipe pages.

Pin versions for reproducibility

Reproducible pipelines pin everything. Four versions matter:

  • Node.js — pin the major (20.x on GitHub Actions' setup-node, versionSpec: '20.x' on Azure DevOps).
  • @uipath/cli — pin exactly (@1.0.0), not a range.
  • Tools — optional. By default they track the CLI's MAJOR.MINOR line; pin only if you need strict patch-level reproducibility (@uipath/solution-tool@1.0.2).
  • Your own Solution's version — pass --version to uip solution pack explicitly. Never rely on the 1.0.0 default in CI.
# Pin these once at the top of the pipeline; reuse below
CLI_VERSION="1.0.0"
SOLUTION_VERSION="1.2.0-ci.${BUILD_NUMBER}"

npm install -g "@uipath/cli@${CLI_VERSION}"
uip tools install @uipath/solution-tool @uipath/orchestrator-tool

uip solution pack ./my-solution ./dist --version "$SOLUTION_VERSION"
# Pin these once at the top of the pipeline; reuse below
CLI_VERSION="1.0.0"
SOLUTION_VERSION="1.2.0-ci.${BUILD_NUMBER}"

npm install -g "@uipath/cli@${CLI_VERSION}"
uip tools install @uipath/solution-tool @uipath/orchestrator-tool

uip solution pack ./my-solution ./dist --version "$SOLUTION_VERSION"

The .zip path is deterministic (./dist/my-solution.${SOLUTION_VERSION}.zip), so downstream steps can construct it without parsing the uip solution pack JSON output.

See Scripting patterns — pinning versions in CI for the tool-pinning rules in depth.

The minimal deploy block

Every platform boils down to this:

set -euo pipefail

# Authenticate
uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT"

# Pack
uip solution pack ./my-solution ./dist \
  --name my-solution \
  --version "$SOLUTION_VERSION"

# Publish
uip solution publish "./dist/my-solution.${SOLUTION_VERSION}.zip"

# Deploy
uip solution deploy run \
  --name "my-solution-${ENVIRONMENT}" \
  --package-name my-solution \
  --package-version "$SOLUTION_VERSION" \
  --folder-name MySolution \
  --folder-path Shared
set -euo pipefail

# Authenticate
uip login \
  --client-id env.UIPATH_CLIENT_ID \
  --client-secret env.UIPATH_CLIENT_SECRET \
  --tenant "$UIPATH_TENANT"

# Pack
uip solution pack ./my-solution ./dist \
  --name my-solution \
  --version "$SOLUTION_VERSION"

# Publish
uip solution publish "./dist/my-solution.${SOLUTION_VERSION}.zip"

# Deploy
uip solution deploy run \
  --name "my-solution-${ENVIRONMENT}" \
  --package-name my-solution \
  --package-version "$SOLUTION_VERSION" \
  --folder-name MySolution \
  --folder-path Shared

set -euo pipefail makes the script fail fast: -e aborts on any non-zero exit, -u catches undefined variables, -o pipefail propagates failures through pipes. This is the pattern every recipe in this documentation uses. See Scripting patterns — strict shell options.

Optional: run tests after deploy

If the Solution includes a test set, launch → wait → verify it before marking the pipeline green. The three-step pattern is important: uip tm testset execute exits 0 as soon as the run is queued, not when tests pass — so you need uip tm wait to block and uip tm report get to read the verdict.

See How-to: run tests from the CLI for the full pattern with error handling.

Handling re-authentication mid-pipeline

Access tokens can expire during long-running pipelines. The scripting-patterns page has the canonical retry pattern: branch on exit code 2 (AuthenticationError), re-run uip login, retry once, fail otherwise. In most CI pipelines this is unnecessary — jobs are short enough that the initial login's token lasts the whole run — but long test suites or multi-tenant promotion loops can benefit from it.

Platform recipes

For complete, copy-pasteable pipelines in your platform's native syntax:

Each recipe shows the full pipeline (install → auth → pack → publish → deploy → test), the secret wiring, a cache entry, and variations for pinning versions and running tests.

Veja também

Esta página foi útil?

Conectar

Precisa de ajuda? Suporte

Quer aprender? Academia UiPath

Tem perguntas? Fórum do UiPath

Fique por dentro das novidades