Skip to content
SHC Docs

shc update

update a deployment

Update a deployment in place: bump the app version, change variables, add or remove hosts and ports, and rewire integrations. The update runs asynchronously on the daemon, which re-renders and re-deploys the stack with the merged settings.

—var overrides are persistent deployment state: a bare update replays the overrides the deployment was installed (or last updated) with, —var key=value adds or replaces a single key, and a trailing ’!’ (—var key!) drops that key back to the app’s default.

The trailing ’!’ is the removal marker on the spec flags: —host blog.example.com! drops a persisted route, —port 8080! drops a persisted port mapping, and -i sso! disconnects an integration. You remove a thing by the same identity you would use to replace it, and a token carrying more than that identity is refused rather than having the extra silently discarded: a port removal names [conn@]external[/udp] and never a service or container port, so —port 80:web! is refused; a route removal names hostname[/path] and never a selector, so —host web:80@blog.example.com! is refused.

A removal and an add of the same identity on one line is an add: the removal applies to what the deployment already had, and the add lands afterwards, so the order you type them in does not matter.

A removal token that matches nothing is reported and ignored — the rest of the update still applies — because re-running a correct command must not fail. Pass —strict-removals (or set SHC_STRICT_REMOVALS=1) to make it a hard failure instead.

Integrations are persistent deployment state like routes, ports and —var overrides: -i sso=keycloak adds or repoints ONE edge and leaves every other integration on the deployment wired.

An integration edge is identified by its consumer plug, so -i sso! always names exactly one edge, and a bare removal token is ALWAYS read as a plug — never as a provider, however much the deployment happens to hold. That is what makes re-running a removal safe: once the plug is gone the same token matches nothing and is reported, instead of quietly meaning something else on the second run. The bare ADD form is still sugar — -i keycloak is resolved to the plug it means before anything else happens, and is refused if it cannot be — so the edge it wires is named by that plug, not by ‘keycloak’. An edge whose plug could not be resolved (a sidecar written before this rule, on a node where the provider is not deployed) is named by its provider reference instead: -i @aws-primary! or -i postgres@default!, exactly as shc update prints it back to you. A disconnect drops the edge from the re-rendered compose, from the deployment’s persisted state and from the integration table, so it stops being replayed. It does NOT run the provider’s unintegration teardown — a disconnected keycloak edge leaves its OIDC client in the realm — and it does not revoke a connection-backed edge’s minted credential; both still happen only on uninstall.

To remove several, either repeat the flag (—host a.com! —host b.com!) or comma-join them (—host a.com!,b.com!) — —host, —port and -i comma-split, so both spellings arrive as two removals. —var alone has no comma form: a var value may itself contain commas, so —var takes one key per flag, and a removal key carrying a comma, a semicolon or whitespace is rejected rather than read as one strange key. The comma form always works in scripts, in CI and over the Terraform provider, which do not run history expansion at all; it needs SINGLE quotes only when typed at an interactive bash or zsh prompt, where a bang followed by a comma is a history reference and an unquoted line fails loudly with ‘event not found’ without running anything. A ’!’ inside a —var VALUE is never a marker: the token carries an ’=’, so —var password=hunter2! sets the password to hunter2!. When you do quote a marked token, use SINGLE quotes — zsh runs history expansion inside double quotes, so double quotes are the one form that breaks.

On a terminal, running with no —var opens a form prefilled with the deployment’s current variable values; edited fields become overrides and a cancelled form leaves the deployment untouched. Non-interactive runs skip the form. —ha/—no-ha toggle high availability and —gated/—open switch the SSO gate. —from/—ref/—path/—token repoint or refresh the deployment’s git/path source.

shc update <stack> [<version>] [flags]
shc update myblog
shc update myblog 2.4.1 --var theme=dark
shc update myblog --var theme!
shc update myblog --host web:8080@blog.example.com --gated
shc update myblog --host blog.example.com! --host old.example.com!
shc update myblog --host 'a.example.com!,b.example.com!'
shc update myblog --port 8080!
shc update myblog -i sso=keycloak
shc update myblog -i sso!
shc update myblog --cpu web=1.0 --memory web=512Mi --scale web=3
--acme-provider string override ACME provider (which named CA issues public certs; blank = acme.default)
-c, --connection strings rebind a declared connection: name=connection (bare connection ok when the app declares exactly one)
--cpu strings per-service CPU quota
--disk string disk quota
--dns-provider string override DNS provider
-e, --environment string environment name (default "default")
--force allow --ttl against a protected environment (prod/production)
--from string change source (git URL or local path)
--gated require Keycloak SSO in front of the app
--ha enable HA mode
-h, --help help for update
--host strings add or replace an HTTP route: [service[:container-port]@]hostname[/path] (hostname[/path]! removes one)
-i, --integrate strings integrate with provider: [plug=]provider[@env] or plug=@connection (provider! or plug! disconnects one edge)
--memory strings per-service memory quota
--no-ha disable HA mode
--open no SSO gate; rely on the app's own auth
--path string subdirectory path when using --from or an existing git source
-p, --port strings add or replace a port: [conn@]external[:service][:container][/udp] (conn@ = via that connection's load balancer; [conn@]external[/udp]! removes one)
--preset string re-resolve preset to NAME[@VERSION]
--protected protect the deployment: refuse uninstall/destroy until 'shc unprotect'
--public expose to the internet (default: LAN-only)
-q, --quiet suppress progress output
--ref string git reference when using --from or an existing git source
--scale strings per-service replica override
--strict-removals fail the update when a removal token ('!') matches nothing, instead of reporting it and carrying on
--tls string tls resolver
--token string authentication token for private git repositories
--ttl string re-stamp the deployment lease (e.g. 72h); unset leaves any existing lease untouched
--unprotected clear the deployment's protection flag
--var stringArray variable override: key=value sets, key! removes the persisted override (one key per flag, no comma form)
--vault-provider string override vault provider
--config stringArray extra YAML config file to layer on top of auto-discovered config; repeatable, later files win
-d, --debug enable debug mode (default: $SHC_DEBUG)
--exclude string comma-separated dotted paths to drop
--fields string comma-separated columns/keys to show (and their order)
--filter string comma-separated dotted paths to keep (drops everything else)
-o, --output string output format: tty|text|json|yaml (default: $SHC_OUTPUT)
-s, --stack string stack name (default: $SHC_STACK)
-t, --tenant string tenant name (default: $SHC_TENANT)
-v, --verbose verbose output (default: $SHC_VERBOSE)
  • shc - Selfhosted Cloud CLI