---
title: Stack Management
description: Create, deploy, control, and remove Docker Compose stacks.
---

A **stack** in Sencho is a Docker Compose project: a directory inside your `COMPOSE_DIR` that contains at least a `compose.yaml` (or `docker-compose.yml`) file. Sencho automatically discovers every subdirectory as a stack.

<Frame>
  <img src="/images/stack-management/create-stack-dialog.png" alt="New stack dialog" />
</Frame>

## Creating a stack

Click **Create Stack** in the left sidebar. Enter a name and click **Create**.

**Naming rules:**
- Lowercase letters, numbers, and hyphens only (e.g. `my-app`, `nextcloud`)
- No spaces or special characters
- Must be unique; duplicates are rejected

Sencho creates a new directory inside `COMPOSE_DIR` with a blank `compose.yaml` file. You'll land in the editor automatically.

## Convert from a docker run command

If you have a `docker run` command handy (from a README, a forum post, or your shell history), Sencho can turn it into a ready-to-deploy `compose.yaml` without hand translation.

Open the **New stack** dialog and switch to the **From Docker Run** tab.

<Frame>
  <img src="/images/stack-management/convert-tab-empty.png" alt="Create stack dialog on the From Docker Run tab" />
</Frame>

### How to use it

1. Enter a **Stack Name**. Same rules as the Empty tab (lowercase, hyphens, unique).
2. Paste your full command into **Paste your docker run command**. The whole command should be on one logical line; line continuations with `\` are fine.
3. Click **Convert**. Sencho parses the command and shows the resulting compose YAML in a read-only preview below.
4. Review the YAML. If it looks right, click **Create Stack**. Sencho creates the stack directory and writes the converted YAML into `compose.yaml`.
5. The editor opens on the new stack. Click **Start** to deploy it.

<Frame>
  <img src="/images/stack-management/convert-tab-result.png" alt="Converted compose YAML preview before creating the stack" />
</Frame>

<Frame>
  <img src="/images/stack-management/convert-stack-created.png" alt="Newly created stack loaded in the editor after conversion" />
</Frame>

### Supported flags

The converter handles the flags you reach for most often:

| Flag | Purpose |
|------|---------|
| `-d` / `--detach` | Detached mode (implied by compose) |
| `--name` | Container name |
| `-p` / `--publish` | Port mappings (`host:container`) |
| `-v` / `--volume` | Volumes and bind mounts |
| `-e` / `--env` | Environment variables |
| `--env-file` | Env file reference |
| `--restart` | Restart policy (`no`, `always`, `unless-stopped`, `on-failure`) |
| `--network` | Attach to a named network |
| `--label` | Container labels |
| `--user` | Run as a specific user |
| `--workdir` | Set the working directory |
| `--entrypoint` | Override the entrypoint |
| `--cap-add` / `--cap-drop` | Linux capabilities |
| `--privileged` | Privileged mode |
| `--read-only` | Read-only root filesystem |
| `--tmpfs` | Temporary filesystem mount |

The image tag is taken from the final positional argument (for example `nginx:alpine`). Any trailing command arguments are preserved as the service `command`.

### Troubleshooting

<Frame>
  <img src="/images/stack-management/convert-tab-error.png" alt="Error toast shown when the converter cannot parse the input" />
</Frame>

If the converter cannot produce a usable compose file, the request fails with a clear error toast. Common causes:

- **Not a docker run command.** The input must begin with `docker run` and include an image reference. Free-form text, `docker compose` commands, and shell pipelines are rejected.
- **Unrecognized flag.** The parser supports the flags listed above. Rare flags (such as `--userns`, `--ipc`, custom runtime options) may not be recognized. Remove the flag, convert the rest, and add it back by hand in the editor.
- **Quoting issues.** Multi-line commands with embedded quotes sometimes confuse the parser. Paste the command as a single line with escaped quotes, or simplify the command first.
- **Command is too long.** The endpoint accepts commands up to 8192 characters. Longer inputs are rejected; trim anything you do not need and convert in pieces.

When a flag is not supported, paste the output you do get into the **Empty** tab as a starting point and fill in the rest by editing `compose.yaml` directly.

## The stack list

All discovered stacks appear in the left sidebar. Each shows a color-coded status indicator:

| Indicator | Meaning |
|-----------|---------|
| `UP` (green) | All containers running |
| `DN` (red) | One or more containers exited |
| No indicator | No containers / status unknown |

Use the **search box** above the list to filter stacks by name.

## Stack header

Opening a stack puts identity and state front and center.

<Frame>
  <img src="/images/stack-view/identity-header.png" alt="Stack identity header with breadcrumb, title, state pill, image digest, and action row" />
</Frame>

The header answers three questions at a glance:

- **What is this?** A breadcrumb (`node › stacks › name`) and the stack name as the title.
- **Is it healthy?** A pulsing pill to the right of the title reports the live state:
  - `running · healthy` (green) when at least one container reports a passing healthcheck.
  - `running · unhealthy` (red) when any container reports a failing healthcheck.
  - `running · starting` (amber) during the Docker healthcheck start period.
  - `running` (green) when no healthcheck is defined.
  - `exited` (red) when no containers are up.
- **What does it ship?** A mono line under the title shows the primary image tag and the short image digest, with a copy button to grab the full digest.

## Container health strip

Below the header, each container in the stack gets a single row that answers "is this piece working, and how do I reach it?" without expanding anything.

<Frame>
  <img src="/images/stack-view/health-strip-logs.png" alt="Stack view showing the per-container health strip above the structured logs viewer" />
</Frame>

Each row includes:

- **Health badge.** A colored glyph reports the Docker healthcheck state: `✓` green for passing, `✗` red for failing, `…` amber while the healthcheck start period is still in flight. Containers without a `healthcheck:` block show a neutral `✓`.
- **Container name** in mono.
- **Meta line.** Uptime (`up 20 hours`), healthcheck state when one is defined, and the primary port mapping (`6875 → 80/tcp`).
- **Open link.** When the container publishes a port, an `open ↗` link launches the app in a new tab using the active node's hostname.
- **Live stat tiles.** Three tiles show CPU, memory, and network I/O with a rolling 60-sample sparkline. The sparkline uses the cyan data color and refreshes roughly every 1.5 seconds.
- **Action icons.** Shortcuts to open this container's logs or a bash shell.

## Logs viewer

The logs area at the bottom of the stack view has two modes. Toggle between them with the segmented control in the top-right of the panel; your choice is remembered for next time.

**Structured** (default) parses every line into a DOM row with three columns: local time, level badge, and message. Level detection is automatic:

- `err` rows get a red left rail and a subtle rose tint.
- `warn` rows get a warm tint.
- `info` rows render plainly.

The toolbar includes:

- **Following indicator.** A pulsing green dot reads `following` while auto-scroll is engaged. Scrolling up stops follow; a `resume follow` link re-engages it and jumps to the bottom.
- **Level filter.** `all · info · warn · err` pills. The `err` pill shows the running error count as a badge.
- **Download.** Exports the current buffer as a plain text file.

The structured viewer holds up to 10,000 lines; older entries are dropped from the top as new ones arrive.

**Raw terminal** keeps the original xterm-based viewer for cases where ANSI art, control sequences, or interactive TTY output matter. Lines include the raw ISO timestamp.

## Anatomy panel

The right half of the stack view is the anatomy panel: a read-only summary of what the compose file declares, without making you open the YAML editor.

<Frame>
  <img src="/images/stack-view/anatomy-panel.png" alt="Stack view with the anatomy panel on the right showing services, ports, volumes, env file, network, and source" />
</Frame>

Each row maps one compose concept to the value it resolves to right now:

- **Services** — Cyan pills, one per key under `services:`.
- **Ports** — `{host} → {container}/{proto}` per service, host port highlighted.
- **Volumes** — `{host-path} → {container-path}` per mount.
- **Restart** — The effective restart policy.
- **Env file** — Filename plus a count of defined variables. If the compose file references a `${VAR}` that the env file does not define and has no `:-default`, the missing name is called out inline in rose italic.
- **Network** — Derived network name and driver (default `{stack}_default · bridge`).
- **Source** — `git · {host}/{repo}#{branch}` when Git Source is configured, else `local`. The whole row is clickable and opens the Git Source dialog. A pulsing cyan dot appears when upstream has moved ahead of the working copy.

If an image update is available for the primary service, an inline banner appears below the rows with the version bump (`27.1.4 → 27.1.5`), risk classification (`safe · patch`, `minor`, or `major · review required`), and an **apply** button that runs the update against the current scheduled-task pipeline. Major bumps show a rose banner and require explicit review before applying.

### Editing compose.yaml

Anatomy is the default surface. When you need to change the compose file, click **edit compose.yaml** in the anatomy header. The Monaco editor slides in over the anatomy panel with the full editing toolbar (tabs for `compose.yaml` and `.env`, Git Source shortcut, Save / Save & Deploy). Close the editor with the `×` button in its header to return to the anatomy view; unsaved changes are discarded when you close.

## Deploying a stack

Select a stack and click **Start** (or **Deploy** from the context menu) in the stack header. This runs `docker compose up -d`, pulling images if needed and creating or recreating containers.

## Controlling a running stack

The stack header groups actions by frequency of use. The most common action is the filled cyan button on the left, everyday secondaries sit next to it, and destructive or occasional actions are tucked behind the `⋯` overflow.

**When running:**

| Placement | Button | Command | What it does |
|-----------|--------|---------|--------------|
| Primary | **Restart** | `docker compose restart` | Restarts all containers in the stack. |
| Secondary | **Stop** | `docker compose stop` | Stops containers without removing them. State is preserved. |
| Secondary | **Update** | `docker compose pull` + `up -d` | Pulls the latest image tags and recreates containers. |
| Overflow `⋯` | **Rollback** | Restores backup | Reverts compose and env files to the pre-deploy snapshot and redeploys. Only shown when a backup exists (Skipper+). |
| Overflow `⋯` | **Scan config** | Trivy config scan | Scans the compose file for misconfigurations (Skipper+, admin). |
| Overflow `⋯` | **Delete** | `down --volumes` + removes files | Stops and removes containers and volumes, then deletes the stack directory. |

**When stopped:**

| Placement | Button | Command | What it does |
|-----------|--------|---------|--------------|
| Primary | **Start** | `docker compose up -d` | Starts the stack. |
| Secondary | **Update** | `docker compose pull` + `up -d` | Pulls the latest image tags and recreates containers. |
| Overflow `⋯` | **Delete** | Removes files | Deletes the stack directory. |

<Warning>
  **Delete** is irreversible. It removes the stack directory, including `compose.yaml`, `.env`, and any bind-mounted files stored there. Back up important files before deleting.
</Warning>

<Note>
  Stack directories often contain root-owned files, either because Docker Compose creates them, or because the stacks were originally set up outside of Sencho with `sudo`. Sencho handles this automatically: if a normal deletion fails due to permissions, it uses Docker to clean up root-owned files. No manual intervention is needed in the standard setup.
</Note>

## Controlling a single service

Inside the stack detail view, each service row has a kebab menu (`⋮`) on the right side. Use it to act on that service without touching the rest of the stack.

- **Restart service** — stops and starts all containers for that service.
- **Stop service** — stops all containers for that service. Only shown when the service is running.
- **Start service** — starts all containers for that service. Only shown when the service is stopped or exited.

For services running multiple replicas, the action applies to every replica simultaneously. Sibling services are not affected.

<Note>
  The service name in the action must match the `services:` key in your `compose.yaml`. If no containers exist yet for that service, the action will fail with a "service not found" error. Make sure the service is defined in the compose file and has been deployed at least once.
</Note>

## Stack context menu

Right-click any stack in the sidebar to open the context menu. The menu adapts to the stack's current state; only relevant actions are shown.

**Running stack:**

<Frame>
  <img src="/images/stack-management/context-menu-running.png" alt="Context menu for a running stack" />
</Frame>

**Stopped stack:**

<Frame>
  <img src="/images/stack-management/context-menu-stopped.png" alt="Context menu for a stopped stack" />
</Frame>

### Available actions

- **Alerts** - configure metric-based alerting rules for this stack
- **Labels** - assign organizational labels (Skipper+)
- **Check for updates** - manually trigger an image update check
- **Open App** - open the stack's web interface in a new tab (only shown when the stack is running and exposes a web port)
- **Deploy** - start the stack (shown when stopped)
- **Stop** - stop all containers (shown when running)
- **Restart** - restart all containers (shown when running)
- **Update** - pull latest images and recreate containers (shown when running)
- **Delete** - stop and remove the stack (admin only)

All actions are disabled while another operation is in progress on that stack.

## Scanning for stacks

If you place Docker Compose files directly into the stacks directory (for example, via `scp`, a file manager, or the command line), you can import them without going through the full "Create Stack" flow.

Click the **folder-search icon** next to the "Create Stack" button in the sidebar. Sencho scans the configured stacks directory and reports what it finds:

<Frame>
  <img src="/images/stack-scanning/scan-button-sidebar.png" alt="Scan stacks folder button in the sidebar" />
</Frame>

- **New stacks detected** - a success notification lists the newly discovered stack names, and they appear immediately in the sidebar
- **Stacks removed from disk** - an informational notification lists stacks that are no longer present in the directory
- **No changes** - a notification confirms no new stacks were found

<Tip>
  Any subdirectory inside your `COMPOSE_DIR` that contains a `compose.yaml`, `compose.yml`, `docker-compose.yaml`, or `docker-compose.yml` file is recognized as a valid stack.
</Tip>

## Troubleshooting

### Service action returns a "service not found" error

The service name used in the action must match the `services:` key in the stack's `compose.yaml`. This error occurs when no running containers match that service name, either because the service was never deployed or because the compose file defines a different name. Verify the service key in your compose file and ensure the stack has been deployed at least once so containers exist for that service.
