# Your first pipeline

> This page shows how to take a UiPath Solution on disk and ship it to Orchestrator end-to-end: **pack** it locally, **publish** it to your tenant's solution feed, and **deploy** it to a folder. It uses the `solution` tool, which works the same from a developer laptop and from a CI pipeline.

This page shows how to take a UiPath Solution on disk and ship it to Orchestrator end-to-end: **pack** it locally, **publish** it to your tenant's solution feed, and **deploy** it to a folder. It uses the `solution` tool, which works the same from a developer laptop and from a CI pipeline.

## What you need

- UiPath CLI installed and a logged-in session. See [Installing UiPath CLI](./installing-uipath-cli.md) and [Authentication](./authentication.md).
- A UiPath **Solution** on disk. [`uip solution pack`](./uip-solution-pack.md) accepts either of two shapes (matching the CLI's own `solution pack --help`):
  - a **solution directory** containing a `.uipx` solution descriptor (the common case — what Studio writes and what `uip solution new` creates), or
  - a standalone **`.uis` file** (a pre-bundled Solution artifact).
- An Orchestrator folder path where you want the Solution deployed (for example, `Shared/MySolutionFolder`).

## The flow

Three commands, each a separate step so you can run them independently in a CI pipeline:

1. `uip solution pack` — produce a versioned `.zip` package from the solution directory.
2. `uip solution publish` — upload the `.zip` to the tenant's solution feed.
3. `uip solution deploy run` — create a folder and deploy the published package into Orchestrator.

## Step 1. Pack the Solution

```bash
uip solution pack ./my-solution ./dist \
  --name my-solution \
  --version 1.0.0
```

Arguments:

- The first positional argument is the solution directory (or a `.uis` file).
- The second is the output directory. `uip` creates it if missing.

Flags:

- `--name` overrides the package name (default: the solution directory name).
- `--version` sets the package version (default: `1.0.0`). Use semantic versioning for readability and to let Orchestrator sort versions correctly.

On success, `./dist/my-solution.1.0.0.zip` is written. The JSON response returns `Data.Package` (formatted as `name@version`) and `Data.Packages` (the inner `.nupkg` filenames). The `.zip` path itself follows the convention `{outputDir}/{name}.{version}.zip`, so pipelines can construct it without parsing JSON:

```bash
NAME=my-solution
VERSION=1.0.0
uip solution pack ./my-solution ./dist --name "$NAME" --version "$VERSION"
PACKAGE="./dist/${NAME}.${VERSION}.zip"
```

## Step 2. Publish to the tenant

```bash
uip solution publish ./dist/my-solution.1.0.0.zip
```

The package is uploaded to the tenant's solution feed. Orchestrator assigns a `PackageVersionKey` — the identity of this specific version on the tenant. `publish` is idempotent per `(name, version)` — re-running it with the same version returns the existing version instead of duplicating.

:::tip
If you are running against a specific tenant from a multi-tenant org, pass `--tenant <tenant-name>` to `publish`, `pack` is tenant-agnostic. When in doubt, `uip login status` shows the tenant the CLI is currently bound to.
:::

## Step 3. Deploy to Orchestrator

```bash
uip solution deploy run \
  --name MyFirstDeployment \
  --package-name my-solution \
  --package-version 1.0.0 \
  --folder-name MySolutionFolder \
  --folder-path Shared
```

Flags (required unless stated):

- `--name` — the **deployment name** (not the package name). Use something meaningful; this identifies the deployment for future `deploy status` / `deploy activate` calls.
- `--package-name`, `--package-version` — match what you published in Step 2.
- `--folder-name` — the Orchestrator folder to create for this deployment.
- `--folder-path` — the parent folder path. `Shared` is the tenant root.
- `--folder-key` — the parent folder GUID; use this instead of `--folder-path` if you prefer to bind by ID.

`deploy run` polls Orchestrator until the deployment reaches a terminal state (default poll timeout `360` seconds, adjustable with `--timeout`). The response carries the new folder's path and the deployment key.

:::note
`--name` and `--folder-name` are **two different things**. `--name` names the deployment record; `--folder-name` names the new Orchestrator folder that the deployment creates. Picking the same value for both is fine and common.
:::

## Putting it together in CI

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

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

uip solution pack ./my-solution ./dist --version "$BUILD_VERSION"
uip solution publish "./dist/my-solution.$BUILD_VERSION.zip"
uip solution deploy run \
  --name "my-solution-$GIT_SHA" \
  --package-name my-solution \
  --package-version "$BUILD_VERSION" \
  --folder-name MySolutionFolder \
  --folder-path Shared
```

The script exits on the first non-zero status, so a failure in any step aborts the build. `uip` returns `0` on success and `1` on failure; commands with domain-specific semantics (for example `uip tm wait`, which reuses `2` for timeout) may return other codes — see [Exit codes](./exit-codes.md).

## After deployment

With the Solution deployed, Orchestrator has a folder (`Shared/MySolutionFolder`), a process per deployable project in the Solution, and all associated resources (assets, queues, triggers). You can now:

```bash
# confirm the folder exists
uip or folders list --all --path "Shared/MySolutionFolder"

# find the processes that were created
uip or processes list --folder-path "Shared/MySolutionFolder"

# start a job
uip or jobs start <process-key>

# inspect the deployment
uip solution deploy status --deployment-key <deployment-key>
```

## What about a single Studio project?

For a single Studio project (a directory with `project.json` — **not** a Solution), the classic pipeline is `pack a .nupkg` → `upload to a feed` → `create a process`. That flow uses commands from the `rpa` and `or` tools:

```bash
uip rpa pack ./MyStudioProject ./dist
uip or packages upload ./dist/MyStudioProject.1.0.0.nupkg
uip or processes create \
  --name MyProcess \
  --package-key MyStudioProject \
  --package-version 1.0.0 \
  --folder-path Shared
```

See [uip rpa](./uip-rpa.md) and the Orchestrator [packages](./uip-orchestrator-packages.md) and [processes](./uip-orchestrator-processes.md) references for full flag lists.

## Next steps

- **[How-to: deploy to Orchestrator from CI](./howto-deploy-from-ci.md)** — variants per CI platform.
- **[CI/CD recipes: Azure DevOps](./recipes-azure-devops.md)**, **[GitHub Actions](./recipes-github-actions.md)**, **[Jenkins](./recipes-jenkins.md)**, **[GitLab](./recipes-gitlab.md)**.
- **[uip solution reference](./uip-solution.md)** — every `solution` subcommand.
- **[Pack and publish a solution (how-to)](./howto-pack-publish-solution.md)** — deeper coverage including versioning strategy and multi-environment promotion.
