Duplicate database migrations are easier to prevent when schema changes run as one explicit deployment step instead of inside every app container startup.
The preventive design is to give migrations one owner, one credential set, and one completion signal before new replicas begin serving traffic. Keep web and worker containers free to restart without acquiring schema-change privileges, make the rollout wait for a successful migration job, and design schema changes so the old and new app versions can briefly coexist. That removes the race condition instead of merely hoping every replica notices the same migration history first.
Remove Migration Commands From Normal App Startup
Inspect the image entrypoint, Compose command, worker command, health wrapper, and deployment script for automatic migration calls. The application should be able to restart without mutating the schema unless that restart is the deliberately chosen migration step.
An Octopus deployment article argues that migrations need a separate lifecycle rather than being coupled to every microservice process start.
Keep the migration binary available where needed, but do not invoke it from both the web entrypoint and a second job. One explicit owner is easier to audit than several startup paths that all depend on framework locking.
Run One Pre-Deploy Migration Job
Create a one-shot job that uses the same migration files as the release and exits successfully only after the target database reaches the expected schema state. Make the application rollout depend on that result.
A current rollout guide shows how one job runs before rollout instead of letting every replica race at startup.
Do not scale the migration task like the app service. The job should have one execution owner per target database, a bounded timeout, logs, and a clear failed state that blocks the new app version.
Gate Application Startup on Migration Success
Keep new web and worker containers waiting until the migration stage reports success, but do not make each waiting container rerun the migration itself. The dependency is on the result, not on executing the schema change again.
Andrew Lock’s deployment pattern uses app pods wait for migration while the migration logic remains centralized.
For a small home-server stack, the same principle can be implemented with a dedicated Compose service and a controlled deploy script. Keep the mechanism simple enough that a failed migration visibly stops the rollout.
Use Backward-Compatible Schema Changes During Overlap
Rolling deployments can temporarily run old and new application versions against one database. Avoid a migration that removes or renames a field before the old version has stopped using it.
A recent zero-downtime migration guide recommends expand before you contract so additive schema work lands before destructive cleanup.
Split large changes into expand, backfill, switch, and contract phases when necessary. The migration job should not create a schema that only the new container understands while old replicas are still serving requests.
Keep Migration Credentials Out of App Replicas
Use a database account with schema-change privileges only for the one-shot migration stage when practical. Normal app containers should keep the narrower read and write permissions needed for application data.
A Liquibase deployment article describes database changes belong in automation with controlled, repeatable change application.
This separation makes accidental migration execution less likely even if an app process is restarted or duplicated. Store the elevated credential in the deployment secret path rather than the ordinary long-running service environment.
Verify the Rollout Cannot Apply the Batch Twice
Test the deployment in a disposable database or restored snapshot by starting multiple app replicas, restarting them, and rerunning the deployment command. The migration stage should report the existing schema state without changing it a second time.
JetBrains summarizes the operational rule as run migrations as deployment step before normal application startup.
The prevention policy is complete when app restarts cannot mutate schema, one failed migration blocks the release, and repeated rollout execution leaves the database unchanged. The related ZimaSpace article on duplicate migration diagnosis is the recovery branch if duplicate execution has already occurred.
Support & Tips
More to Read

Can Plex Share a GPU With Another Docker Container?
Plex and another container can often access the same GPU, but you must test driver support, device mapping, video-engine load, memory, and recovery behavior.

How to Tell Whether a Plex Error Comes From the Client or Server
Reproduce the same item on another client, compare the session path, then collect server evidence only after scope tells you where the failure actually...

How to Configure Plex Cache and Transcode Temporary Storage
Protect persistent Plex state while placing transcode temp files on suitable local storage, then verify cleanup, free space, and restart behavior.

