HR's Journal
Technical guide

A Data-Preserving Playbook for Production Upgrades

Protect databases, uploads, configuration, and local patches while staging, migrating, activating, verifying, and rolling back an upgrade.

ByHabibur Rahman

Editor & Engineer

5 min read

An application upgrade is successful only when the new code works and the old data remains correct. That sounds obvious, yet many upgrade procedures verify containers and HTTP status while treating databases, uploaded files, local compatibility patches, and user-created configuration as background details.

A data-preserving upgrade makes those assets explicit. It establishes what is durable, captures recoverable backups, stages the new version separately, and verifies real records after activation. The method works for containerized applications and conventional services alike.

Classify state before touching the deployment

Inventory every source of state and label it replaceable or durable. Replaceable state includes application images, compiled assets, dependency directories, and caches. Durable state includes database volumes, uploaded media, encryption keys, environment files, generated user content, and sometimes application-specific indexes that are expensive to rebuild.

Inspect the running configuration rather than relying on a remembered compose file. Resolve volume mounts, bind paths, database names, container image digests, service dependencies, and the active source revision. A file named docker-compose.yml is not proof that it is the file used by the running stack.

Also identify local changes. A production checkout may contain a compatibility patch, branding adjustment, or provider configuration absent from upstream. Compare the active source against its recorded base and save a patch. Otherwise an apparently clean upstream upgrade can quietly remove behavior the deployment depends on.

Create backups that match the data model

Filesystem snapshots and logical database dumps solve different problems. A volume snapshot can restore exact storage quickly, while a logical dump is portable and can be inspected or restored into a clean database. For important systems, use both when practical.

Run the database's own dump tool from a context that uses the real connection settings. Save globals or roles when they are required for restoration. Back up bind-mounted configuration and uploads separately. Record checksums and sizes so an empty or truncated artifact does not masquerade as protection.

Store backups outside the directory or volume being replaced. Copy a protected artifact off the VPS when the data matters. Retention should keep multiple points in time, because corruption may be discovered after the most recent backup has already captured it.

A backup is not fully trusted until restoration has been exercised. At minimum, list its contents and run the database tool's verification or metadata command. Better, restore into an isolated database periodically and perform application-level checks.

Stage the new version without replacing the old one

Fetch or copy the target source into a new release directory. Pin the version by commit or image digest instead of a floating tag. Review upstream release notes and schema changes for the exact versions crossed.

Reapply local patches deliberately. If a patch no longer applies, stop and understand the conflict rather than discarding it or forcing hunks. The upstream change may already solve the issue, or it may have changed the assumptions behind the local modification.

Build new images or application assets while the existing service remains available. Validate generated configuration with tools such as docker compose config, run unit or integration checks, and inspect the final image tags. Pulling an image is preparation; recreating a container is activation.

Control database compatibility

Read migration code before execution when the upgrade is significant. Determine whether migrations are additive, destructive, reversible, and compatible with the previous application version. Record the current schema version and the expected target.

When possible, follow expand-and-contract deployment. Add new tables or nullable fields first, deploy code that understands both shapes, migrate data, and remove obsolete fields in a later release. This preserves an application rollback window.

If the application performs migrations automatically at startup, know exactly which service triggers them and how failure appears. Starting every replica simultaneously can race migrations or overload the database. Prefer one controlled migration step followed by application rollout.

Do not assume restoring an old application image will undo a migrated schema. The rollback guide must state whether file-only rollback is supported and, if not, which database backup and restore steps are required.

Activate the narrowest possible change

Restart or recreate only the services required by the upgrade. In Docker Compose, targeted service updates reduce disturbance to databases and unrelated dependencies. Confirm that named volumes remain attached and that no command introduces anonymous replacement volumes.

Watch startup logs from the first moment. Check migration completion, connection errors, background job initialization, and repeated restarts. Then probe internal health before routing public traffic or declaring completion.

For a traditional service, switch an atomic release pointer and restart the supervised unit. For containers, immutable image tags and a saved previous compose resolution provide the equivalent rollback reference.

Verify data through the application

Count important records before and after: users, published items, jobs, messages, files, or other domain entities. Counts do not prove semantic correctness, but unexpected changes are immediate warning signs.

Open representative records through the real application path. Confirm that an existing user can authenticate, old content renders, uploaded files resolve, and a safe new write persists after a restart. Verify background workers and scheduled jobs, not only the web process.

Check public TLS and reverse proxy behavior from outside the server. Recheck co-hosted services if proxy or network configuration changed. Save the final active version, image digest, schema version, backup path, and verification results in the operations log.

Keep the rollback assets until confidence grows

Do not delete the prior release, previous images, or pre-upgrade backup immediately. Define an observation window based on traffic and job cycles. A problem in a weekly task cannot be discovered during a five-minute smoke test.

Rollback should use recorded identifiers, not guesses such as "the previous tag." Restore the prior release or image set, handle the database according to the compatibility assessment, start services, and repeat the same verification checklist.

Data preservation is less about one clever command than about disciplined evidence. Know where state lives, capture it in restorable forms, stage code separately, understand migrations, change only what is required, and validate real user data afterward. That process turns an upgrade from a hopeful restart into a controlled, reviewable operation.

BackupsDatabaseDeploymentDocker