Skip to content
Deprecations

Deprecation Schedule

Deprecated and removed features in Drydock, with removal versions and migration guidance.

This page lists every deprecated feature, the version it will be removed in, and how to migrate. Until removal, deprecated features continue to work. Detection methods and warning behavior vary by feature; check the applicable Detection row and the detection summary.

Features listed under a removal version will stop working in that release. Migrate before upgrading.

Removal in v1.5.0

Legacy aggregate container stats endpoint

GET /api/v1/containers/stats was removed when fleet-level stats moved to the dedicated stats API. Current releases catch the old path and return 410 Gone with migration targets instead of treating stats as a container id.

Deprecated sincev1.5.0-rc.17
Removed sincev1.5.0-rc.17
Compatibility response sincev1.5.0-rc.34
MigrationUse GET /api/v1/stats/summary or GET /api/v1/stats/summary/stream for aggregate stats; use GET /api/v1/containers/:id/stats for one container

Implicit wildcard CORS origin

Older drydock releases allowed DD_SERVER_CORS_ENABLED=true without DD_SERVER_CORS_ORIGIN and treated it like * (all origins). Since v1.5.0-rc.9, drydock fails closed instead: startup throws an error and the server does not start.

Deprecated sincev1.4.0
Removed sincev1.5.0-rc.9
MigrationSet DD_SERVER_CORS_ORIGIN to your trusted origin(s), e.g. DD_SERVER_CORS_ORIGIN=https://drydock.example.com

v1.6.0 removals and deferrals

Unversioned API paths (/api/*)

The unversioned /api/* path was a backward-compatible alias for /api/v1/*. As of v1.6.0, /api/* requests return 410 Gone with a JSON body pointing at the /api/v1/ equivalent, except the four whitelisted wud-card compatibility endpoints — those keep working at /api/* when DD_COMPAT_WUDCARD=true, served by their own router rather than by falling through to the removed alias, so they're unaffected by this removal (three return WUD's bare-array response shape instead of drydock's envelope; the fourth passes through unmodified). GET /api/auth/status is unaffected for the same reason, unconditionally: it's registered directly on the app, a permanent compatibility alias for GET /api/v1/auth/status with no removal scheduled. GET /api/auth/methods used to be unaffected the same way, but its own registration was removed in v1.7.0, so it now falls through to this same tombstone like the rest of the unversioned surface.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationReplace /api/ with /api/v1/ in all integrations. If you depend on wud-card or Homepage's whatsupdocker widget and can't change their base path, set DD_COMPAT_WUDCARD=true

Unversioned WebSocket alias (WS /api/log/stream)

The system log stream WebSocket accepted both the versioned /api/v1/log/stream path and the unversioned /api/log/stream alias, following the same transition-alias policy as the REST /api/* path above. As of v1.6.0, an upgrade request to the unversioned path is rejected with a 410-style upgrade failure instead of completing the WebSocket handshake.

Deprecated sincev1.5.0
Removed sincev1.6.0
MigrationPoint WebSocket clients at /api/v1/log/stream

Legacy WUD_* environment variables

WUD_* prefixed environment variables are ignored as of v1.6.0. Only DD_* variables are loaded at runtime; the migration CLI still recognizes old names so it can rewrite existing files.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationRename all WUD_* vars to DD_*. Run node dist/index.js config migrate --dry-run to preview changes

Legacy wud.* container labels

wud.* prefixed Docker labels are ignored as of v1.6.0. Only dd.* labels affect container discovery, display, grouping, hooks, rollback, webhooks, and trigger behavior.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationRename all wud.* labels to dd.* in your compose files. Run node dist/index.js config migrate --file /path/to/compose.yml

Legacy template variable aliases

Simple template aliases (id, name, watcher, kind, semver, local, remote, link) and the batch alias count are no longer supplied to templates.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationReplace with container.* equivalents: idcontainer.id, namecontainer.name, countcontainers.length, etc. See Trigger templates

PUT /api/v1/settings

The PUT method on /api/v1/settings is a compatibility alias for PATCH. Responses include Deprecation and Sunset HTTP headers. The unversioned /api/settings path is not a working alias for this endpoint — like the rest of the unversioned surface, it returns 410 Gone (see Unversioned API paths); settings is not among the four wud-card compatibility endpoints exempted from that tombstone.

Deprecated sincev1.4.0
RemovalDeferred to API v2 — /api/v1 is frozen, so the method cannot be dropped from the versioned surface; the Sunset header advertises the earliest retirement instant
DetectionLog warning on each PUT request; Deprecation and Sunset response headers
MigrationChange PUT /api/v1/settings to PATCH /api/v1/settings

HTTP OIDC discovery URLs

OIDC providers configured with http:// discovery URLs are rejected. Identity Providers must serve discovery over HTTPS.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationUpdate your IdP discovery URL to use https://. If your IdP uses a self-signed certificate, set DD_AUTH_OIDC_{name}_INSECURE=true

Legacy password hash formats

SHA-1, APR1/MD5 (Apache), crypt, and plain-text password hashes are rejected. Basic authentication accepts only the documented argon2id hash format.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationRegenerate your password hash with argon2id. See Basic authentication

Kafka clientId configuration key

The camelCase clientId key is rejected by Kafka trigger validation.

Deprecated sincev1.4.5
Removed sincev1.6.0
MigrationRename clientId to clientid (lowercase) in your Kafka trigger configuration

DD_WATCHER_*_WATCHDIGEST environment variable

Per-watcher digest watching via environment variable has been removed.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationUse the dd.watch.digest=true label on individual containers instead

DD_WATCHER_*_WATCHATSTART environment variable

Watching at startup is always scheduled. WATCHATSTART is no longer part of watcher configuration, including the former false suppression behavior.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationRemove the variable from your configuration. If you need to delay the first scan, use DD_WATCHER_{name}_CRON to control the schedule instead

Token-only Hub/DHI PUBLIC_TOKEN configuration

Hub/DHI public instances that provide PUBLIC_TOKEN without the matching PUBLIC_LOGIN are rejected instead of silently falling back to anonymous access. The TOKEN key itself remains supported as part of a complete LOGIN+TOKEN pair.

Deprecated sincev1.4.0
Removed sincev1.6.0
MigrationAdd the matching login and use LOGIN+TOKEN, use LOGIN+PASSWORD, use AUTH, or remove credentials for intentional anonymous access

Agent-mode WUD_AGENT_SECRET / WUD_AGENT_SECRET_FILE fallback

Agent mode's secret lookup no longer falls back to WUD_AGENT_SECRET / WUD_AGENT_SECRET_FILE when DD_AGENT_SECRET / DD_AGENT_SECRET_FILE is unset.

Deprecated sinceNever, removed directly with no deprecation period
Removed sincev1.6.0-rc.1
MigrationRename WUD_AGENT_SECRET to DD_AGENT_SECRET and WUD_AGENT_SECRET_FILE to DD_AGENT_SECRET_FILE

v1.7.0 removals and deferrals

DD_TRIGGER_* environment variable prefix

The DD_TRIGGER_* prefix has been replaced by semantic prefixes that distinguish action triggers from notification triggers. As of v1.7.0, any detected DD_TRIGGER_* environment variable fails startup outright — the error lists every offending variable next to its exact replacement, so a config can be fixed in one pass.

Deprecated sincev1.5.0
Removed sincev1.7.0
DetectionStartup error listing every detected variable with its exact replacement; drydock does not start until all are renamed
MigrationRename DD_TRIGGER_* to DD_ACTION_* (for Docker/Compose/Command triggers) or DD_NOTIFICATION_* (for Slack/email/Pushover/etc.). Run node dist/index.js config migrate --source trigger to auto-rewrite. See Triggers

dd.trigger.include / dd.trigger.exclude container labels

These labels have been replaced by semantic equivalents. As of v1.7.0, dd.trigger.include / dd.trigger.exclude no longer resolve to anything — only the scoped dd.action.* / dd.notification.* labels are read for include/exclude filtering.

Deprecated sincev1.5.0
Removed sincev1.7.0
DetectionError-level log during container initialization (once per label key); Prometheus counter dd_legacy_input_total{source="label"}
MigrationReplace dd.trigger.include with dd.action.include or dd.notification.include. Replace dd.trigger.exclude with dd.action.exclude or dd.notification.exclude

A container still carrying either legacy label is detected and logged (so an unmigrated fleet stays visible in monitoring), but the label itself is never consulted for filtering — only the scoped labels affect trigger routing.

Manual updates bypass dd.action.include / dd.action.exclude

In v1.5.x–v1.6.x, the trigger-not-included and trigger-excluded eligibility reasons were soft blockers: the UI showed a Trigger filtered / Trigger excluded pill, but clicking the per-row Update button still queued the update after a confirmation step. As of v1.7.0, both reasons are hard blockers, shipping together with the per-action execution policy (dd.action.auto / AUTO=onauto) that separates action authorization from automatic promotion, so the manual-only escape hatch isn't removed on its own. The Update button is now locked when the labels filter out the action trigger, and the API rejects manual update requests with the blocker's message.

This does not change AUTO=oninclude's meaning — a matching dd.action.include label still grants both manual and automatic access under that mode, exactly as before. Only the default-deny and explicit-exclude outcomes (no matching include/auto label, or an explicit dd.action.exclude match) flip from soft to hard.

Deprecated sincev1.5.0
Removed sincev1.7.0
DetectionUI eligibility pill on container row (now locked instead of clickable); API 409 response on manual update attempts
MigrationIf you relied on manual updates bypassing an action trigger's include/exclude filter, either (a) remove the dd.action.exclude label, (b) add the trigger to the container's dd.action.include list (or dd.action.auto list under AUTO=onauto), or (c) configure a separate action trigger that the labels permit. The eligibility pill on the row identifies the exact trigger / label combination in conflict

Agent-less Home Assistant MQTT topic layout (multi-agent)

Through v1.6.x, the Home Assistant MQTT topic layout (<topic>/<watcher>/<container> and the watcher-level sensor topics) had no agent segment. In a multi-agent deployment where the controller and one or more agents all used the default watcher name local, two containers with the same name on different agents published to — and overwrote — the same MQTT topic, and watcher-level sensor counts summed across all agents. As of v1.7.0, DD_NOTIFICATION_MQTT_<name>_HASS_AGENTTOPICSEGMENT defaults to true: an agent/<name> segment is inserted into every Home Assistant topic for containers owned by a remote agent, watcher running-status topics and watcher-level sensor counts are scoped per agent, and discovery-entity cleanup is scoped per agent. Controller-local container topics are unchanged.

Agent-owned container and watcher entities move to new topic paths (new entity IDs) the first time drydock starts under v1.7.0 without the opt-out set. The old, pre-v1.7.0 discovery entities are not retroactively removed — cleanup only clears topics drydock currently tracks, and that tracking starts empty on every process restart, so the pre-upgrade entities stay retained on the broker and appear in Home Assistant as orphaned, frozen-at-last-state duplicates until manually removed.

Deprecated sincev1.5.0
Default flipped sincev1.7.0
DetectionManual — affects multi-agent Home Assistant MQTT deployments where more than one node uses the default watcher name local
MigrationUpdate Home Assistant automations/dashboards/templates that reference the old (agent-less) entity IDs for agent-owned containers, and manually remove the orphaned old-path discovery entities once the new ones are confirmed working. Set DD_NOTIFICATION_MQTT_<name>_HASS_AGENTTOPICSEGMENT=false to keep the pre-v1.7.0 layout temporarily. See MQTT trigger

curl in Docker image

The official Docker image kept curl available in v1.5.x and v1.6.x for backward compatibility with custom healthcheck overrides. The default built-in HEALTHCHECK has used the lightweight static binary (/bin/healthcheck) instead since v1.5.0. As of v1.7.0, curl is removed from the image entirely, so a container whose own HEALTHCHECK override still shells out to curl starts failing.

Deprecated sincev1.5.0
Removed sincev1.7.0
DetectionUI deprecation banner when Drydock can inspect its own container via the local Docker socket; startup log warning naming the affected container when a curl-based override is detected
MigrationSwitch custom healthcheck overrides to test: /bin/healthcheck $${DD_SERVER_PORT:-3000} (doubled $ defers expansion to the container shell instead of the host environment), or drop the override to use the built-in image healthcheck. See Monitoring

Unversioned GET /api/auth/methods alias

GET /api/auth/methods was a legacy, unversioned auth-discovery alias kept unauthenticated so the login screen could render before a session existed. It was registered directly on the app, ahead of the /api mounts, so it survived the /api/* path removal in v1.6.0 on its own separate v1.7.0 timeline. As of v1.7.0, that registration is gone: the route is no longer mounted, so requests to it now return 410 Gone from the same unversioned /api/* tombstone.

Deprecated sincev1.6.0
Removed sincev1.7.0
MigrationReplace GET /api/auth/methods with GET /api/v1/auth/status

Removal in v1.8.0

Legacy auth strategies response shape

GET /auth/strategies returns the older { strategies, warnings } response shape. The canonical replacement, GET /api/v1/auth/status (also available at /api/auth/status and /auth/status), returns { providers, errors } — the same provider list plus structured startup registration errors. Its unversioned alias, GET /api/auth/methods, was removed outright in v1.7.0 (see above), ahead of this response-shape migration deadline.

Deprecated sincev1.6.0
DetectionLog warning on each request plus RFC 9745 Deprecation and RFC 8594 Sunset response headers
MigrationRead providers/errors from GET /api/v1/auth/status instead of strategies/warnings from GET /auth/strategies

Enforced security changes (no deprecation window)

These behaviors were removed immediately rather than going through a grace period, because the deprecated behavior was itself the vulnerability. They're listed here for upgrade visibility, not because they're still active.

Implicit reverse-proxy header trust for CSRF origin checks

Removed sincev1.5.0-rc.30
MigrationSet DD_SERVER_TRUSTPROXY to the number of proxy hops in front of Drydock (e.g. 1) if you terminate TLS at a reverse proxy. See the FAQ

Implicit reverse-proxy header trust for WebSocket origin checks

Removed sincev1.6.0-rc.3
MigrationSet DD_SERVER_TRUSTPROXY to the number of proxy hops in front of Drydock (e.g. 1) if you terminate TLS at a reverse proxy and use the log-stream or container log-stream WebSocket endpoints. See the FAQ

Command trigger process-environment inheritance

Removed sincev1.5.0-rc.35
MigrationScripts that need additional variables from the drydock process name them explicitly with DD_ACTION_COMMAND_{name}_ENV (comma-separated). See Command trigger

HTTP trigger requests to cloud metadata endpoints

Removed sincev1.5.0-rc.35
MigrationA deployment that genuinely needs a link-local target sets DD_NOTIFICATION_HTTP_{name}_ALLOWMETADATA=true on that trigger. See HTTP trigger

Anonymous-auth grandfather path for upgrades

Removed sincev1.6.0-rc.3
MigrationSet DD_AUTH_BASIC_{name}_USER/_HASH (or configure OIDC) before upgrading, or set DD_ANONYMOUS_AUTH_CONFIRM=true to explicitly keep the instance anonymous. See Authentication
Removed sincev1.6.0-rc.3
MigrationNone required. Existing connect.sid cookies are no longer recognized, so every user is signed out once on upgrade and needs to log back in

Detection summary

Drydock provides multiple channels for discovering deprecated feature usage:

ChannelCovers
Startup log warningsAll runtime-detectable deprecations
UI deprecation bannersActive dd.trigger.* container-label usage (the DD_TRIGGER_* env var prefix now fails startup instead, so there is no running instance left to surface a banner for)
Prometheus countersdd_legacy_input_total{source,key} for active dd.trigger.* label usage, API tombstones, and historical observations
HTTP response headersDeprecation and Sunset on PUT /api/v1/settings and GET /auth/strategies
Migration CLInode dist/index.js config migrate --dry-run previews all env var and label renames