md.

From batch releases to feature releases: rethinking our CI/CD strategy

A look at our planned shift from batch releases to feature-based CI/CD to improve delivery speed, reduce risk, and support continuous delivery.

Long exposure lights speeding by
Author

Matt Dobson

Published

28 Mar 2026

At Checkmyfile , we're currently operating a Gitflow-styled CI/CD process, where changes are promoted through environments and new features are typically released at the end of our 3-week sprint cycle.

This has served us well as we transitioned from on-prem to cloud, introducing full CI/CD workflows just a few years ago. But as our confidence and processes have matured, we're starting to outgrow it.

We're now looking to reduce risk and increase our release cadence.

At its core, this change is simple:

We’re moving from promoting branches through environments to promoting individual features to production

This shift allows us to release work independently, rather than in batches.


Current model

Our current model can best be described as:

A Gitflow-style environment promotion model

We have 4 infrastructure environments, with corresponding branches in our repositories:

  • develop - a moving environment. Engineers branch from here and merge new features back into it. On PR completion, work is automatically deployed to the develop environment.
  • qa - the QA team merges develop into QA and tests on this branch. Deployments are gated and require approval in our pipelines. The intention is to ensure the environment doesn’t move under QA’s feet.
  • prelive - our staging environment, using live data but limited to internal users. It is also gated and used for testing live integrations and UAT (which is a topic for another post).
  • main - the production branch. Naturally, this has stricter approvals and deployment controls.

To summarise:

  • Work is merged into a shared branch - develop
  • That branch is promoted through environments
  • Releases (outside of bug fixes) are made as batches of changes

Problems with the current model

There are a number of challenges with this approach, but these are the most impactful:

Features block each other

Multiple features are bundled together. If one feature fails testing, it prevents other features from being promoted through the environments.

If we discover an issue later in the sprint - for example, a failure in prelive just before release - it can disrupt the entire release process and lead to last-minute scrambling.

Ultimately, completed work cannot be released independently.

A typical scenario for us:

  • Feature A passes QA
  • Feature B fails QA
  • Neither can be released without additional work or rollback

Large batch releases

Releasing many changes at once increases the risk of defects and makes it harder to isolate issues when something goes wrong.

Slow time to production

Features often sit waiting for release cycles. We can have work completed and tested within the first few days of a sprint, but it may still take weeks to reach customers.

This creates a significant gap between “completed” and “released”.


New model: Feature-Based Releases

With our new model, we’re introducing a key principle:

Promoting individual features to production

Instead of releasing everything in develop at the end of a sprint, we want the flexibility to release features as soon as they are tested and approved.

Our goals are:

  • Release features as soon as they’re ready
  • Reduce batch size and release risk
  • Decouple features so they no longer block each other

For a direct comparison:

  • Branch promotion → Feature promotion
  • Fixed release cycle (3 weeks) → Release when ready
  • Higher risk (more changes) → Lower risk (fewer changes)

New branching strategy and flow

We’ll use two primary branches:

  • main - production. This branch is always considered deployable
  • develop - integration. Changes here are deployed to the develop and QA environments

Development flow

  1. Create a feature branch from main
  2. Develop the feature
  3. Merge into develop after peer review
  4. Automatically deploy to develop and QA
  5. QA performs testing
  6. Once approved, merge the same feature branch into main
  7. Automatically deploy to prelive
  8. After approval, deploy to production

The key difference is that develop is no longer treated as a release candidate.

Instead of promoting develop through environments, we selectively promote individual features to production via main.

We’re also removing gated deployments in non-production environments, allowing us to move toward continuous deployment with greater confidence.

Mindset changes

Moving from batch releases to continuous delivery requires a shift in how we work.

Keep changes small and think incrementally

We want short-lived branches and smaller PRs.

Long-running branches drift away from production and increase risk. Breaking work into smaller increments keeps changes easier to review, test, and release.

Increased use of feature flags

We already have a flexible feature flag system, supporting:

  • user-level targeting
  • exclusions
  • percentage rollouts

We’re confident in our use of feature flags - they now need to become standard practice.

Respecting contracts

A contract is the interface between systems:

  • API request/response structures
  • Endpoint behaviour
  • Data formats
A contract defines what one part of the system expects from another

This is what enables this model.

Without backwards compatibility, independent releases become risky or tightly coupled.

In batch releases, coordination is less critical because everything is deployed together. In this new model, we must design for compatibility.

The backend cannot remove fields still used by the frontend. Likewise, the frontend must not assume new behaviour is available until it is.

Before making any contract change, we ask:

1. Will the current frontend continue to work after this backend change?
2. Will the current backend continue to work with this frontend change?

If not, the change must be phased or redesigned.

Increased ownership

A quote that stuck with me from an article I recently read on Increment , was:

you don’t “own” the code you write, unless you run and maintain it, too

We want engineers to own features end-to-end, from PR to production, with Engineering leadership acting as approvers rather than gatekeepers.

Migration approach

We won’t switch everything at once.

Instead, we’ll:

  • Start with a pilot service
  • Validate the approach
  • Roll out repository by repository

In-flight work will be handled pragmatically:

  • Work close to release may complete under the current model
  • New work will adopt the new model

This reduces risk and gives us room to learn.


Our future direction: trunk-based

Our long-term goal is to move toward:

  • Changes merged directly into main
  • Continuous releases
  • Strong automated testing
  • QA supported by automation

To get there, we need improvements in:

  • end-to-end testing
  • CI reliability
  • backwards compatibility
  • feature flag usage
  • incremental delivery

Ephemeral environments

We’re also exploring ephemeral environments - spinning up temporary environments per PR.

This would allow isolated testing and reduce reliance on shared environments.

We’re not quite there yet, at an IAC level, but it’s a natural next step.

Pure trunk-based development can feel unrealistic in practice. Guardrails like ephemeral environments and some manual QA help maintain confidence without over-relying on engineers writing automations to mark their own homework.

Closing thoughts

This isn’t about adopting a trendy CI/CD model. It’s about reducing risk, increasing delivery speed, and giving teams more control over what reaches production.

A feature-based release model should allow us to deliver value more frequently, with less risk.

We’ll learn a lot during the rollout - what works, what doesn’t, and where the real friction is. I’ll share a follow-up once we’ve put this into practice!