Upgrading & Versioning — Blazor Blueprint
Login Register

💡 This is a template, not a dependency. You own your copy outright — there is no package to bump and no framework upgrading itself underneath you. The flip side is that taking an upstream change is a merge, and how much it costs depends almost entirely on choices you make in your first week. That is what this page is about.

Set It Up So Upgrades Stay Cheap

Clone rather than download, and keep upstream as a second remote from day one. A ZIP with no shared history turns every future update into a manual diff.

git clone <repository-url> your-saas-app
cd your-saas-app

# rename the upstream remote, then point origin at YOUR repository
git remote rename origin upstream
git remote add origin <your-own-repo-url>
git push -u origin main

Now git fetch upstream brings updates in as real history and git merge does the work. Keep upstream read-only; never push to it.

Build in the places designed to be extended

Every upgrade conflict is a line you changed that upstream also changed. The architecture gives you places to add code that upstream does not touch — use them, and most releases merge without a single conflict:

  • Plugins are the big one. A feature built as a plugin lives in its own project, registers itself through DI, and contributes nav, routes, admin pages, public routes and background sweeps without editing a host file. Nothing upstream ships will ever conflict with it. See Plugin Development.
  • Provider interfaces — payments, SMS, email, file storage and AI are all interfaces with shipped implementations. Add your own implementation beside them rather than editing theirs.
  • Configuration over code — feature flags, per-plugin settings and provider credentials are config. A behaviour change you make in appsettings.json costs nothing at merge time; the same change made in a host file costs you every release.
  • New files beat edited files. A new service in your own namespace never conflicts. When you must edit a shipped file, keep the edit small and obvious rather than reformatting around it.

💡 The one thing worth doing on day one: commit your own work in focused commits with real messages. When a merge conflicts eighteen months later, the question you will be asking is "why did we change this?" — and your commit history is the only thing that can answer it.

Versioning

The repo root holds a VERSION file — a plain three-part version, currently 1.0.0. The build pipeline reads it and tags images {VERSION}.{buildNumber} (immutable, and what a deploy pins), alongside floating {VERSION} and latest tags. Bump the file to cut a release.

It is yours to bump once you fork: your product's version is not the template's. If you want to keep track of which upstream release you last merged, record it in your own commit message or a CHANGELOG — leave VERSION describing your product, since that is what your image tags mean.

Performing an Upgrade

git fetch upstream
git checkout -b upgrade/<version> # never merge straight into main
git merge upstream/main

# resolve conflicts, then:
dotnet build BlazorBlueprint.sln --configuration Release
dotnet test BlazorBlueprint.sln --configuration Release

Then, in order:

  1. Diff the configuration. New keys arrive with new features and a merge will not add them to a file you have edited. Compare your appsettings.json against the upstream one and look specifically for new Features: flags — an absent flag falls back to its code default, which may not be the behaviour you want.
  2. Check for schema changes on a relational backend. If entities changed, regenerate migrations and commit them (there is a script for it in scripts/). This is the step most likely to be skipped and most likely to bite: the local test suites self-skip without a database, so a missing migration can pass locally and fail only in CI. Mongo needs nothing.
  3. Run it against a copy of production data, not an empty database. Provisioning and index reconciliation are idempotent, but an upgrade is exactly when that gets tested for real.
  4. Deploy to staging first, with the migrator gated ahead of the app as the shipped pipelines already do — a migration failure then blocks the deploy before the running app is touched.

Two things that must survive every upgrade

⚠️ The Data Protection key ring. It is half of your encrypted data, and where it lives depends on your deploy mode: in Redis under the full stack, on a filesystem volume (dp_keys, mounted at /keys) under Lite. Either way it is a named Docker volume and an upgrade must not touch it. Never docker compose down -v — the -v removes volumes and takes the key ring with it, making every encrypted field permanently unreadable. Snapshot the right volume for your mode before upgrading.

⚠️ Caching:RedisKeyPrefix is part of the key-ring name. Changing it points the app at an empty ring, which it will then happily populate with a fresh key. Set it once at first deploy and never again.

What a Licence Entitles You To

  • Free tier — the public repository, so git fetch upstream keeps working indefinitely.
  • Paid tiers — every version released in the 12 months after payment clears, plus email support over that year. What lapses afterwards is access to newer releases; everything you already have stays yours to use and modify forever, with no forced renewal.

Full terms on the licence page.

Ready to Build?

Take updates without fighting your own fork. The complete source is free to use — including commercially — while your business earns under £100k/year. Past that, a one-time commercial licence (from £499, excl. VAT) applies. Every tier ships the same product; nothing is feature-gated.

🔓 Source-available • Free under £100k/yr revenue • Commercial licence (from £499) above that • Full source code included

Welcome! How can we help you today?
An unhandled error has occurred. Reload