Stacks
A stack groups the apps and services of one project. Its members share a private network and a set of variables, and can be deployed together in a defined order.
What is a Stack?
In the API and the CLI a stack is called a project: /api/v1/projects and sh0 projects manage stacks. A stack gives its apps:
- A private network on which each app answers to
<app-name>and<app-name>.internal. The hostname does not change when the app is redeployed. - Shared variables, read by every app of the stack.
- A start order, used when the whole stack is deployed at once.
Apps in different stacks do not see each other by name. Database servers are outside stacks: any app reaches them at <server-name>.internal.
Creating a Stack
In the dashboard, open Stacks, click Create Stack, enter a Stack Name (1 to 100 characters) and an optional Description. From the CLI:
$ sh0 projects create my-shop
Project created: my-shop (5aee8eea-9f77-4d10-ac21-2fe4a565e666)sh0 push --project expects the stack ID printed here; the name is not accepted.Stack Page
Opening a stack shows its services grouped by kind, and:
- Add App, which opens the Deploy page for this stack; Stack Settings; Export Snapshot and Import Snapshot.
- The Internal network & shared settings panel: each service's internal hostname, the Shared variables, the Start order, and Deploy the project, which deploys every app in that order.
Stack Variables
A shared variable is injected into every app of the stack at its next deployment. If an app defines the same key, the app's value wins. Details, API and precedence: Environment Variables.
Stack Settings
Stack Settings edits the name, the description, the color and the members, and holds Delete Stack.
Common Patterns
- One stack per product: the frontend, the API and the workers that must reach each other by name.
- One stack per environment: staging and production separated, each with its own shared variables.
- One stack per client: with stack members, each client's apps stay visible only to the people assigned to it.
Managing Stacks via API
The routes live under /api/v1/projects. Updates use PATCH; PUT answers 405. A request without /v1 does not reach the API: it returns the dashboard page. Outputs below were obtained on a test instance:
# Create a stack
$ curl -s -X POST https://panel.example.com/api/v1/projects \
-H "Authorization: Bearer $SH0_TOKEN" -H "Content-Type: application/json" \
-d '{"name":"my-staging","description":"Staging environment"}'
{"data":{"color":null,"created_at":"2026-10-02 02:53:41","description":"Staging environment","id":"b9b14ce5-7aa4-4c0d-85fe-b6c4b3977e8e","member_count":1,"name":"my-staging","owner_id":"50159570-e8ad-46a8-8065-e6c9096edde6"}}
# List stacks (paginated: page, per_page)
$ curl -s https://panel.example.com/api/v1/projects -H "Authorization: Bearer $SH0_TOKEN"
{"data":[{"color":null,"created_at":"2026-10-02 02:53:41","description":"Staging environment","id":"b9b14ce5-7aa4-4c0d-85fe-b6c4b3977e8e","member_count":1,"name":"my-staging","owner_id":"50159570-e8ad-46a8-8065-e6c9096edde6"}, ...],"page":1,"pages":1,"per_page":20,"total":3}
# Get one stack
$ curl -s https://panel.example.com/api/v1/projects/b9b14ce5-7aa4-4c0d-85fe-b6c4b3977e8e -H "Authorization: Bearer $SH0_TOKEN"
{"data":{"color":null,"created_at":"2026-10-02 02:53:41","description":"Staging environment","id":"b9b14ce5-7aa4-4c0d-85fe-b6c4b3977e8e","member_count":1,"name":"my-staging","owner_id":"50159570-e8ad-46a8-8065-e6c9096edde6"}}
# Update a stack
$ curl -s -X PATCH https://panel.example.com/api/v1/projects/b9b14ce5-7aa4-4c0d-85fe-b6c4b3977e8e \
-H "Authorization: Bearer $SH0_TOKEN" -H "Content-Type: application/json" \
-d '{"description":"Staging, rebuilt nightly"}'
{"data":{"color":null,"created_at":"2026-10-02 02:53:41","description":"Staging, rebuilt nightly","id":"b9b14ce5-7aa4-4c0d-85fe-b6c4b3977e8e","member_count":1,"name":"my-staging","owner_id":"50159570-e8ad-46a8-8065-e6c9096edde6"}}
# Delete a stack that still holds an app: refused (HTTP 400)
$ curl -s -X DELETE https://panel.example.com/api/v1/projects/5aee8eea-9f77-4d10-ac21-2fe4a565e666 -H "Authorization: Bearer $SH0_TOKEN"
{"error":{"code":"BAD_REQUEST","key":"project_not_empty","message":"Cannot delete stack: it still has 1 app (my-api). Delete these services first.","params":{"remaining":[{"count":1,"family":"apps","names":"my-api"}]}}}
# Delete an empty stack (HTTP 204, no body)
$ curl -s -X DELETE https://panel.example.com/api/v1/projects/b9b14ce5-7aa4-4c0d-85fe-b6c4b3977e8e -H "Authorization: Bearer $SH0_TOKEN" -o /dev/null -w "%{http_code}\n"
204