> For the complete documentation index, see [llms.txt](https://developer.celigo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.celigo.com/cli/commands/stacks.md).

# stacks

On-premise bridge runtimes — run data-residency-sensitive flows inside your own network. Stacks host the execution environment (server or AWS Lambda) that integrator.io invokes for custom code, hooks, and wrappers.

**REST API**: [Stacks](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks)

```
celigo stacks <subcommand> [args] [flags]
```

Supports all [global flags](/cli/getting-started/global-flags.md).

***

## Subcommands

| Subcommand            | Purpose                                                                    |
| --------------------- | -------------------------------------------------------------------------- |
| `list`                | List all stacks, both your own and any shared with you.                    |
| `get <id>`            | Fetch one stack by ID (secrets masked as `******`).                        |
| `create`              | Create a stack from a JSON body (`--file <path>` or stdin).                |
| `update <id>`         | Full-replace PUT from a JSON body (`--file <path>` or stdin).              |
| `set <id> <k>=<v>...` | Partial edit via GET → modify → PUT (no stack field is PATCH-whitelisted). |
| `delete <id>`         | Delete a stack by ID.                                                      |
| `dependencies <id>`   | List resources that depend on this stack (alias `used-by`).                |
| `token <id>`          | Retrieve the unmasked system token for a server stack.                     |
| `rotate-token <id>`   | Rotate the server stack's system token.                                    |
| `audit <id>`          | Show the audit log (change history) for a stack.                           |

***

## `celigo stacks list`

List every stack configured on the account (server and Lambda), both your own and any shared with you (`shared=true`).

**Signature**

```bash
celigo stacks list
```

**Arguments**

None.

**Flags**

| Flag              | Type   | Default   | Description                                                                                                                                                                                                                                                                         |
| ----------------- | ------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--fields <spec>` | string | `default` | Fields to return per row. `default` returns `_id`, `name`, and the table columns; `all` returns complete documents; a comma-separated list requests specific fields (dot notation allowed). Applied to both listings. See [field projection](/cli/getting-started/global-flags.md). |

There is no `--limit`: the command merges two listings, your own stacks and the ones shared with you.

Default table columns: `_id`, `name`, `shared`, `lastModified`. `shared` is `false` for your own stacks and `true` for a stack shared with you.

**Example**

```bash
celigo stacks list --format table
```

**Corresponds to**: [`GET /v1/stacks`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#get-v1-stacks) and `GET /v1/shared/stacks`, merged and deduplicated by `_id`.

***

## `celigo stacks get <id>`

Fetch a single stack by ID. For server stacks, `server.systemToken` is returned masked as `******` — use [`token`](#celigo-stacks-token-less-than-id-greater-than) for the real value.

**Signature**

```bash
celigo stacks get <id>
```

**Arguments**

| Argument | Type   | Required | Description |
| -------- | ------ | -------- | ----------- |
| `<id>`   | string | Yes      | Stack ID.   |

**Flags**

None beyond [global flags](/cli/getting-started/global-flags.md).

**Example**

```bash
celigo stacks get 5f8d43a1b9e5a80011a35f2c
```

**Corresponds to**: [`GET /v1/stacks/{_id}`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#get-v1-stacks-_id)

***

## `celigo stacks create`

Create a new stack from a JSON payload. Read the body from a file with `-f, --file` or pipe it on stdin. `type` must be `server` or `lambda`; required sub-blocks depend on the type (`server.hostURI` for server, `lambda.accessKeyId` / `secretAccessKey` / `awsRegion` / `functionName` for Lambda).

**Signature**

```bash
celigo stacks create --file <path>
celigo stacks create < stack.json     # or pipe on stdin
```

**Arguments**

None.

**Flags**

| Flag                | Type   | Default | Description                                                                                                  |
| ------------------- | ------ | ------- | ------------------------------------------------------------------------------------------------------------ |
| `-f, --file <path>` | string | —       | Read the JSON body from a file instead of stdin (`--file -` also means stdin). Added in celigo-cli 2026.6.1. |

**Request body**

Reads JSON on stdin (or from `--file`). See the `POST /v1/stacks` request schema in `dist/stack.yml` for the full payload shape (one variant per `type`: `server`, `lambda`).

Since celigo-cli 2026.10.1, `create` refuses, before any request and with no override, a body that carries a masked placeholder (four or more asterisks and nothing else, such as the `******` a GET returns) — a new stack has no secret behind the mask — and a value that is not a string in `lambda.secretAccessKey` or `server.systemToken`, fields the platform encrypts. Send a string, or `null` to clear the field.

**Example**

```bash
celigo stacks create < stack.json
```

**Corresponds to**: [`POST /v1/stacks`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#post-v1-stacks)

***

## `celigo stacks update <id>`

Full-replace a stack with a JSON payload. Read the body from a file with `-f, --file` or pipe it on stdin. Because `PUT` erases omitted fields, send the complete stack object (typically `GET` → edit → `update`).

> ⚠️ **`update` replaces the entire stack.** `PUT` erases any field you omit. `GET` the stack first, edit it, then send the complete object back — or use `set` for narrow edits.

**Signature**

```bash
celigo stacks update <id> --file <path>
celigo stacks update <id> < stack.json     # or pipe on stdin
```

**Arguments**

| Argument | Type   | Required | Description |
| -------- | ------ | -------- | ----------- |
| `<id>`   | string | Yes      | Stack ID.   |

**Flags**

| Flag                | Type    | Default | Description                                                                                                  |
| ------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------ |
| `-f, --file <path>` | string  | —       | Read the JSON body from a file instead of stdin (`--file -` also means stdin). Added in celigo-cli 2026.6.1. |
| `--force`           | boolean | `false` | Submit even if the body contains masked credential values (`"******"`) copied from a GET.                    |

**Request body**

Reads JSON on stdin (or from `--file`). See `PUT /v1/stacks/{_id}` in `dist/stack.yml`. Secrets are write-only: provide a new value in the request to replace it, or omit the secret fields entirely to leave them untouched (responses always mask them as `******`).

**Example**

```bash
# Drop the masked secrets so they stay untouched (update refuses a body that carries them)
celigo stacks get 5f8d43a1b9e5a80011a35f2c --format json \
  | jq '.name = "Renamed stack" | del(.server.systemToken, .lambda.secretAccessKey)' \
  | celigo stacks update 5f8d43a1b9e5a80011a35f2c
```

**Corresponds to**: [`PUT /v1/stacks/{_id}`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#put-v1-stacks-_id)

***

## `celigo stacks set <id> <key=value>...`

Partial edit. No stack field is PATCH-whitelisted, so every assignment goes through GET → modify → PUT with the complete document. Dotted paths and array indices are supported; values are auto-parsed (booleans, numbers, `null` removes the field).

Because the PUT would write a mask back over the real secret, `set` refuses when the stack the GET returned carries a masked value — as a server stack's `server.systemToken` and a Lambda stack's `lambda.secretAccessKey` do — and points at `update`:

```
Cannot set name on a stack via 'set': the server returned masked credential values ("******") at server.systemToken, and the GET+PUT this field needs would send those masks back over the real secrets. Use 'stacks update' with a body carrying the real credential values (or its --force to submit the masks anyway).
```

For such a stack, edit through `update` with the secret fields left out (see the example above). Since celigo-cli 2026.10.1 only four or more asterisks and nothing else count as a mask.

**Signature**

```bash
celigo stacks set <id> <key=value> [<key=value>...]
```

**Arguments**

| Argument      | Type   | Required | Description                                                                                                                                             |
| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<id>`        | string | Yes      | Stack ID.                                                                                                                                               |
| `<key=value>` | string | Yes (1+) | One or more assignments. Dot notation (`server.hostURI=...`) and array indices (`server.ipRanges[0]=10.0.0.0/8`) are supported. `null` removes the key. |

**Flags**

None beyond [global flags](/cli/getting-started/global-flags.md).

**Example**

```bash
# Refused when the stack's GET carries a masked secret (see above)
celigo stacks set 5f8d43a1b9e5a80011a35f2c name="Renamed stack"

# The same kind of edit through update, with the masked secrets left out
celigo stacks get 5f8d43a1b9e5a80011a35f2c --format json \
  | jq '.server.hostURI = "https://bridge.example.com:3000" | del(.server.systemToken, .lambda.secretAccessKey)' \
  | celigo stacks update 5f8d43a1b9e5a80011a35f2c
```

**Corresponds to**: [`GET /v1/stacks/{_id}`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#get-v1-stacks-_id) then [`PUT /v1/stacks/{_id}`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#put-v1-stacks-_id)

***

## `celigo stacks delete <id>`

Delete a stack. Prompts for confirmation unless `-y` is passed.

> ⚠️ **Deleting a stack cannot be undone.** Flows and resources that reference this stack will fail. Run `celigo stacks dependencies <id>` first to confirm nothing depends on it.

**Signature**

```bash
celigo stacks delete <id> [-y]
```

**Arguments**

| Argument | Type   | Required | Description |
| -------- | ------ | -------- | ----------- |
| `<id>`   | string | Yes      | Stack ID.   |

**Flags**

| Flag        | Type    | Default | Description                        |
| ----------- | ------- | ------- | ---------------------------------- |
| `-y, --yes` | boolean | `false` | Skip the interactive confirmation. |

**Example**

```bash
celigo stacks delete 5f8d43a1b9e5a80011a35f2c -y
```

**Corresponds to**: [`DELETE /v1/stacks/{_id}`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#delete-v1-stacks-_id)

***

## `celigo stacks dependencies <id>`

List the resources that depend on this stack. Use it to check whether the stack is safe to delete; an empty result means no dependents. Aliased as `used-by`.

**Signature**

```bash
celigo stacks dependencies <id>
celigo stacks used-by <id>
```

**Arguments**

| Argument | Type   | Required | Description |
| -------- | ------ | -------- | ----------- |
| `<id>`   | string | Yes      | Stack ID.   |

**Example**

```bash
celigo stacks dependencies 5f8d43a1b9e5a80011a35f2c
```

**Corresponds to**: `GET /v1/stacks/{_id}/dependencies`

***

## `celigo stacks token <id>`

Retrieve the unmasked system token for a **server-type** stack. The regular `get` response always masks `server.systemToken` as `******`; this command returns the actual value so you can paste it into the on-premise bridge's config.

The command first `GET`s the stack to verify `type === "server"` — running it against a Lambda stack fails before any token call is made.

**Signature**

```bash
celigo stacks token <id>
```

**Arguments**

| Argument | Type   | Required | Description                              |
| -------- | ------ | -------- | ---------------------------------------- |
| `<id>`   | string | Yes      | Stack ID. Must be a `server`-type stack. |

**Flags**

None beyond [global flags](/cli/getting-started/global-flags.md).

**Example**

```bash
celigo stacks token 5f8d43a1b9e5a80011a35f2c
```

**Corresponds to**: [`GET /v1/stacks/{_id}/systemToken`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#get-v1-stacks-_id-systemtoken)

***

## `celigo stacks rotate-token <id>`

Rotate the system token for a **server-type** stack. The API generates a new token and the old one is immediately invalid — any bridge instances still using the old token will fail to authenticate until they're updated. Retrieve the new token with `token`. Prompts for confirmation unless `-y` is passed; without a terminal it refuses and exits `1`. On success it prints `System token for stack <id> recycled.`

Since celigo-cli 2026.10.1, `rotate-token` requires `full` mode (it was `operate`): a credential rotation changes the account's infrastructure. Run against a Lambda stack, which holds no system token, the API's `404` now comes with the hint `Only a server-type stack has a system token — this stack exists but is not one (a Lambda stack has none). celigo stacks get <id> shows its type.`

> ⚠️ **Rotating the token is immediate and irreversible.** The old `systemToken` stops working the moment the new one is issued. Every on-premise bridge still using it fails to authenticate until you redeploy with the new token.

**Signature**

```bash
celigo stacks rotate-token <id> [-y]
```

**Arguments**

| Argument | Type   | Required | Description                              |
| -------- | ------ | -------- | ---------------------------------------- |
| `<id>`   | string | Yes      | Stack ID. Must be a `server`-type stack. |

**Flags**

| Flag        | Type    | Default | Description                        |
| ----------- | ------- | ------- | ---------------------------------- |
| `-y, --yes` | boolean | `false` | Skip the interactive confirmation. |

**Example**

```bash
celigo stacks rotate-token 5f8d43a1b9e5a80011a35f2c -y
```

**Corresponds to**: [`DELETE /v1/stacks/{_id}/systemToken`](https://developer.celigo.com/api/api-reference/scripts-and-stacks/stacks#delete-v1-stacks-_id-systemtoken)

***

## `celigo stacks audit <id>`

Show the audit log (change history) for a stack. Since celigo-cli 2026.10.1 the command reads every page of the log, and the table shows `_id`, `resourceType`, `event`, `source`, `byUser.email`, and `time`.

**Signature**

```bash
celigo stacks audit <id>
```

**Arguments**

| Argument | Type   | Required | Description |
| -------- | ------ | -------- | ----------- |
| `<id>`   | string | Yes      | Stack ID.   |

**Example**

```bash
celigo stacks audit 5f8d43a1b9e5a80011a35f2c
```

**Corresponds to**: `GET /v1/stacks/{_id}/audit`

***

## Gotchas

* **`token` and `rotate-token` are server-only.** `token` checks `type === "server"` client-side before the token call — a Lambda stack aborts with `token is only available for server-type stacks (this stack is type 'lambda').` `rotate-token` sends its request without that check, and the API answers a Lambda stack with `404 Not Found`; since celigo-cli 2026.10.1 the CLI adds a hint that only a server-type stack has a system token.
* **Token rotation is immediate and non-reversible.** `rotate-token` issues a brand-new `systemToken` the instant the DELETE returns `204 No Content`. Every on-premise bridge, sidecar, or script still holding the old token will fail auth until you redeploy with the new one — coordinate the rollout before rotating. Since celigo-cli 2026.10.1 it requires `full` mode (see [Profiles & regions](/cli/getting-started/profiles.md#permission-modes)).
* **Responses mask secrets.** `server.systemToken` and `lambda.secretAccessKey` always come back as `******` on `list`, `get`, `create`, and `update`. Use [`token`](#celigo-stacks-token-less-than-id-greater-than) for the real server token; AWS secrets must be re-supplied in the request body each time you want to replace them.
* **`PUT` is a full replace.** `update` overwrites every field, so omit secret fields (they'll remain untouched) or include their real values; it refuses a body that still carries a `******` mask unless `--force`. `set` cannot help here: it would PUT the masked copy it read, so it refuses a stack whose GET carries a masked secret and points at `update`.
* **On-prem security is your problem.** A server stack's `hostURI` is reachable by integrator.io's control plane — lock it down with `server.ipRanges` (CIDR allowlist) so only Celigo's egress IPs can hit the bridge. Without that, anyone who learns the `systemToken` and `hostURI` can invoke your custom code.
* **Framework is pinned.** Only `framework: "twoDotZero"` is currently supported; omit the field or set it to `twoDotZero` on create.

## Related

* [environments](/cli/commands/environments.md) — stacks belong to a specific environment; flows can only reference stacks in the matching environment.
* [on-premise-agents](/cli/commands/on-premise-agents.md) — the on-premise agent (OPA) that runs behind a server stack's `hostURI` and exchanges the `systemToken` with the integrator.io control plane.
