DEV Community

Cover image for The Update Button I Wanted Before Self-Hosting in Production
hoagminh
hoagminh

Posted on Edited on

The Update Button I Wanted Before Self-Hosting in Production

The first deployment is rarely the moment that makes me nervous.

The application is new, there is little data, and if something goes wrong I can usually start again. The uncomfortable moment comes months later, when the application is already useful and a new version is available.

At that point, “pull the latest image and restart the container” no longer feels like a complete update plan.

What if the new container starts but never becomes healthy? What if an environment variable changed? What if the update migrated the database and the previous image can no longer read it? And if I need to go back, which version and which data state should I return to?

This is the problem behind safer updates in Nitrobase.

Nitrobase has only recently launched and is still in Beta. The feature does not promise risk-free upgrades. Its purpose is narrower and more practical: make every update a visible process with a recovery path prepared before anything changes.

An update is a small migration

I used to think of an update as replacing one container image with another. That model works until the application has persistent state.

A real update may change several things at once:

  • the container image or source commit;
  • the expected environment variables;
  • the database schema;
  • files stored in volumes;
  • the time the application needs before it becomes ready;
  • the behavior of the health endpoint.

The command that starts the new container is usually the easy part. The difficult part is deciding whether the update succeeded and knowing what to do when it did not.

That is why Nitrobase treats an update as a job rather than a single Docker command.

Prepare the way back before moving forward

The default update flow follows a simple order:

  1. detect the newer template version, database image, or Git revision;
  2. create a backup before changing the running application;
  3. deploy the selected version;
  4. wait for its health checks;
  5. keep the new version only when those checks pass;
  6. run the configured rollback strategy when deployment or verification fails.

The most important step happens before the update begins.

If I only think about recovery after a failed deployment, I may discover that the data I need has already changed. Taking the backup first turns rollback from a hopeful idea into an actual option.

“The container is running” is not enough

Docker can report a container as running even when the application inside it cannot serve requests.

The process may still be warming up, waiting for a database, restarting a worker, or returning errors from its API. Switching traffic based only on container state can therefore turn a technically successful restart into an outage.

Nitrobase waits for the application health check after deploying the new version. If the application does not become healthy within the expected period, the update is considered unsuccessful.

This is a small distinction, but it changes the meaning of the update button. Success is not “Docker accepted the command.” Success is “the new application can do the job it was deployed to do.”

Not every rollback means the same thing

One lesson I learned while building this workflow is that application rollback and data recovery are different operations.

For some updates, the data format remains compatible. In that case, Nitrobase can redeploy the previous application version while leaving the data untouched.

Other updates perform an irreversible database migration. Starting an older image against that newer schema may make the situation worse. For these applications, the template can require restoring the backup captured before the update.

Nitrobase supports three rollback approaches:

  • Redeploy: return to the previous application version without replacing its data.
  • Restore: recover the pre-update backup when the upgrade may have changed data incompatibly.
  • Manual: stop automatic recovery and leave a clear record for cases that require an operator's decision.

The right strategy depends on the application. Nitrobase does not try to pretend every failure can be solved by running the previous container image.

Automatic updates still need boundaries

Once manual updates have a recovery path, automatic updates become less intimidating—but they should still be constrained.

In Nitrobase, an application can be configured to apply patch or minor releases during a maintenance window. Automatic updates always create a backup first, and versions that cannot be interpreted safely are not applied automatically.

I prefer this model to blindly following latest. It gives automation a defined scope:

  • which level of release may be applied;
  • when the update may run;
  • how success is verified;
  • what recovery action should happen on failure.

Automation is useful when it makes a decision repeatable. It is dangerous when it removes the decision without preserving its safeguards.

The problem this feature is trying to solve

Self-hosting gives me control over the server and the data, but it also makes me responsible for the moment an update goes wrong.

The hard questions are not complicated, yet they are easy to postpone:

  • Do I have a current backup?
  • Can that backup actually restore the application?
  • Which version is running now?
  • How will I determine whether the new version is healthy?
  • Does going back require only the old image, or the old data as well?
  • What happens if the deployment fails in the middle?

Nitrobase tries to put those answers into the update workflow itself, with a job log, explicit health verification, and a rollback policy attached to the application.

Still a Beta feature

This workflow is part of Nitrobase Beta, and real applications will expose cases that templates and test environments do not cover.

An application with a long database migration, an unusual health check, or a custom release format may need different handling. For important workloads, I would still begin with a staging instance, verify the restore process, and schedule the first update during a maintenance window.

The goal is not to make updates harmless. It is to make failure expected, observable, and recoverable.

That is the update button I wanted: not one that simply moves forward, but one that prepares the way back first.

Nitrobase source code: https://github.com/AydenGroup/nitrobase

Top comments (1)

Collapse
 
hoagminh profile image
hoagminh •

If you find this project useful, please give it a star 🫡