Skip to content
SHC Docs

Adapter reference

Generated file — do not edit by hand. Regenerate from the repo root with CGO_ENABLED=0 go run scripts/gen-adapters-md.go.

Adapters connect SHC to other self-hosting platforms. Each adapter understands one platform’s app grammar and on-box layout, and powers two verbs:

  • shc adapter load transpiles a live install of the platform into an adapted app — an SHC app package that runs on SHC — and pulls the app’s data with it.
  • shc adapter migrate --from extracts a platform app’s data package-free and replays it into the matching native SHC catalog app through a migration recipe — a transform into the native app, not a shim around the foreign one.

See the glossary: Adapter, Adapted app, shc adapter load, shc adapter migrate.

Source of truth is the capability registry (modules/adapter/capabilities.go); shc adapter ls renders the same registry live from your binary.

Column key — Load / Migrate: the two verbs above. Env capture: how live env/secret values are captured from the box (none, file: <path>, or live-inspect: <mechanism>). Secret minting: how foreign values classify as secrets and mint (typed-schema | fixed | heuristic | none). Vars: whether the foreign config grammar lowers into the typed vars DSL. Plugs: whether platform addons map onto SHC capability socket+plug pairs. Quiesce: the pause mechanism wrapped around a data pull so the capture is a consistent point-in-time copy. Load proven / Migrate proven are the validation honesty markers, tracked SEPARATELY per verb (a live-proven load says nothing about migrate): live = driven end-to-end against a real platform box; fixture = fixture / fake-box + conformance validated only; unproven = no meaningful validation yet; n/a — not supported = the verb is absent by design (not a debt).

Total: 15 platforms — 13 load + migrate, 2 migrate-only.

These platforms define apps as Docker Compose — plain, or with a manifest riding alongside — and transpile through the shared compose core.

AdapterLoadLoad provenMigrateMigrate provenEnv captureSecret mintingVarsPlugsQuiesce
casaosyesliveyeslivecompose-derived: installed compose env (values carried on Package.Secrets)heuristicyesnocasaos-cli app-management stop (async) + compose-project drain poll
Coolify coolifyyesliveyesfixturefile: /data/coolify/services/<uuid>/.envtyped-schemayesnodocker compose -p <uuid> stop (no drain poll)
Created with Fabric.js 5.3.0 dockgeyesliveyeslivefile: /opt/stacks/<id>/.envheuristicyesnocd /opt/stacks/<id> && docker compose stop (synchronous)
dokployyesliveyeslivefile: /etc/dokploy/compose/<appName>/code/.envheuristicyesnodocker compose -p <appName> stop + drain poll (composeType=stack has no non-destructive stop — live pull)
runtipiyesliveyeslivefile: runtipi/app-data/<store>/<id>/app.envtyped-schemayesnoruntipi-cli app stop (sudo) + compose-project drain poll
Synology synologyyesfixtureyesfixturecompose-derived: project <share>/.env (values carried on Package.Secrets; docker-inspect backstop)heuristicyesnodocker compose -p <project> stop (sudo, abs path) + compose-project drain poll
TrueNAS truenasyesfixtureyesfixturecompose-derived: rendered compose inline env (values carried on Package.Secrets; docker-inspect backstop)heuristicyesnodocker compose -p ix-<app> stop + drain poll (app.stop is destructive async)
Umbrel umbrelyesliveyeslivelive-inspect: docker inspect <compose-project> envfixedyesyesdocker stop by compose-project label + drain poll

These platforms have their own app grammar (JSON, XML, or template manifests — no compose upstream); each adapter ships a dedicated transpiler.

AdapterLoadLoad provenMigrateMigrate provenEnv captureSecret mintingVarsPlugsQuiesce
CapRover caproveryesliveyeslivenonetyped-schemayesnodocker service scale srv-captain--<app>=0 (replica stash) + drain poll (manager-only)
Cloudron cloudronyesliveyeslivenonefixedyesyesno-op (native backup tarball is a point-in-time snapshot)
easypanelyesfixtureyesfixturecompose-derived: state-store env block + db password fields (values carried on Package.Secrets)heuristicyesnodocker service scale <project>_<svc>=0 (async) + drain poll + replica restore
Portainer portaineryesliveyeslivelive-inspect: docker inspect <container> envheuristicyesnodocker stop <container> (no sudo shim, no drain poll)
Unraid unraidyesfixtureyesfixturecompose-derived: my-<Name>.xml Config values (values carried on Package.Secrets)typed-schemayesnodocker stop -t 10 <Name> + drain poll (root ssh)

Nothing loads from these platforms — their apps cannot run on SHC as adapted apps. shc adapter migrate extracts the app’s data package-free and replays it into the matching native SHC app through a migration recipe.

AdapterLoadLoad provenMigrateMigrate provenEnv captureSecret mintingVarsPlugsQuiesce
kubenon/a — not supportedyeslivenonenonenonokubectl scale deploy/sts to 0 (replica stash) + pod-drain poll + helper-pod PVC stage
YunoHost yunohostnon/a — not supportedyesfixturenonenonenonono-op (yunohost backup create = operator-run point-in-time snapshot)

One line per adapter: where the importer reads the platform’s install tree from (“live-synthesized catalog” means the platform keeps no static manifest tree, so the catalog is reconstructed over SSH from the live engine), and the adapter’s headline limit.

  • caprover — live-synthesized catalog (root /captain/data). limited load: only image-based apps (~84% of the catalog) load; built-from-source apps (img-captain-* images) are load-rejected but stay fully migrate-capable.
  • casaos — box tree /var/lib/casaos/apps. no resolved env file exists on the box, so an imported datastore keeps the source box’s plaintext credentials while the adapted package re-mints fresh values at deploy — and the load report cannot flag the mismatch.
  • cloudron — box tree /var/backups/snapshot. shared postgres/mysql/mongo/redis addon dumps inside the backup tarball are not imported — an app without a self-dump contract imports configured-but-empty; the tarball import path has no end-to-end proof.
  • coolify — box tree /data/coolify/services. one-click services subset only; migrate recipes ship (gitea, invoice-ninja/mariadb) but no live-box migrate has been driven green end to end.
  • dockge — live-synthesized catalog (root /opt/stacks). stacks hold app data as relative binds beside the compose, so the catalog fetch is per-stack config-only; expect a high gate-reject rate — dockge stacks are arbitrary user compose.
  • dokploy — box tree /etc/dokploy/compose. composeType=stack apps have no non-destructive stop upstream (dokploy’s own stop is docker stack rm), so their quiesce is a no-op and the pull is effectively live.
  • easypanel — box tree /etc/easypanel. the platform’s headline source-build deploys (github/git/dockerfile/nixpacks/buildpacks) carry no pullable image and load-reject; the state store is closed-source, so live env capture is still owed.
  • kube — live-synthesized catalog. no live cluster has run this path — PVC/RWO/CSI fidelity must be proven on a real cluster; the Kubernetes-to-compose load lowering is a later increment.
  • portainer — live-synthesized catalog (root /var/lib/docker/volumes). quiesce is a plain docker stop with no sudo shim and no drain poll — a passwordless-sudo-but-no-docker-group login silently degrades every pull to a live capture; live env values are never seeded into secrets.
  • runtipi — box tree runtipi/apps. the backup.yaml ephemeral-volume exclusion is a substring heuristic — a data volume named …cache… is wrongly excluded.
  • synology — live-synthesized catalog (root /var/packages/ContainerManager/etc/projects). a project’s live values ride its <share>/.env, whose box path is not recoverable from the importer’s handle — no live-secret seeding is wired; .spk-packaged apps are out of scope.
  • truenas — box tree /mnt/.ix-apps/app_configs. host_path storage points at arbitrary, multi-TB SMB-shared user datasets and is treated as an external reference — never captured; only ix_volume and docker named volumes travel.
  • umbrel — box tree umbrel/app-data. never live-imported; only the curated exports.sh profiles (bitcoin, electrs) lower manifest dependencies onto plugs — every other dependencies/exports.sh app gates.
  • unraid — box tree /boot/config/plugins/dockerMan/templates-user. ExtraParams is a raw docker-run flag string — the adapter tokenizes it and folds each dangerous flag onto the synthesized compose so the shared gate rejects it; manifests (USB flash) and data (array) live on disjoint filesystems.
  • yunohost — box tree /home/yunohost.backup/archives. migrate-only by design — apps are Debian packages over a shared server-side database, so nothing can load; migration recipes are the scarce resource.