Introduction

Power Platform makes it incredibly easy to build business applications quickly. That speed is a strength—but without a deliberate Application Lifecycle Management (ALM) approach, it can also become a liability. This post walks through the real problems we ran into with a traditional, unmanaged‑solution workflow, why those problems mattered, and how we designed a Git‑centric ALM model using Power Platform CLI (PAC) and GitHub to regain control.

This is not a theoretical ALM pattern. It’s a practical one, shaped by constraints, trade‑offs, and lessons learned.


The starting point: unmanaged solutions and shared folders

Like many teams, we started with a very common Power Platform setup:

  • Unmanaged solutions used everywhere
  • Changes made directly in environments
  • Solution ZIPs exported manually
  • Packages stored on a shared network drive

At first, this felt simple and flexible. Over time, it became increasingly painful.

The problems we ran into

1. No reliable version history

ZIP files in a shared folder don’t tell a story. Even when filenames included version numbers, there was no guarantee they reflected reality:

  • Which version was deployed to which environment?
  • Was v1.2.3-final-final.zip actually newer than v1.2.2-prod.zip?
  • What changed between two exports?

There was no authoritative answer.

2. Environment drift

Because changes were made directly in environments, each environment slowly diverged:

  • DEV wasn’t quite the same as TEST
  • TEST wasn’t quite the same as PROD
  • Hotfixes were applied in one place and forgotten in another

Over time, confidence dropped. Deployments became riskier, not safer.

3. No auditability

With unmanaged solutions and shared storage:

  • There was no clear review process
  • No pull requests
  • No approval trail

If something broke, it was difficult to answer a simple question: when did this change, and why?

4. Manual, fragile releases

Releases depended on people remembering the right steps:

  • Export the right solution
  • Tick the right boxes
  • Import into the right environment

That’s not a system—it’s tribal knowledge.


Defining the goal

Before choosing tools, we defined what “good” needed to look like.

Our goals were:

  • Track solution versions explicitly
  • Know exactly which version is deployed where
  • Store solution source and release artifacts in Git
  • Make releases repeatable and boring
  • Avoid environment drift

In short: Git should tell the truth, and environments should follow.


Why not Azure DevOps?

Microsoft provides strong native ALM support for Power Platform in Azure DevOps, including built‑in tasks and pipelines. If Azure DevOps had been available to us, we likely would have used it.

However, due to organisational constraints, Azure DevOps was not an option.

What we did have was:

  • GitHub
  • The Power Platform CLI (PAC)
  • The freedom to design our own workflow

So instead of trying to replicate Azure DevOps exactly, we focused on first principles.


Choosing a Git‑centric model

The key decision was this:

Git is the single source of truth.

That meant:

  • Solution structure stored in Git
  • Versions defined in source
  • Releases produced from source control, not environments

Managed and unmanaged source

One early challenge was packaging managed solutions reliably.

Managed solutions cannot be built from unmanaged‑only source. To solve this, we:

  • Exported both managed and unmanaged solutions from DEV
  • Unpacked them together using:
pac solution unpack --packagetype Both

This preserves everything required to deterministically build managed solutions later.

The result: Git contains a complete, authoritative representation of the solution.


Keeping versions in sync: online-version

One subtle but important problem we wanted to avoid was version drift between DEV and Git.

Our versioning rule is simple:

  • The solution version is defined in Solution.xml
  • That version must match what developers see in the DEV environment

To achieve this, we intentionally update the solution version in DEV before export using:

pac solution online-version \  --solution-name "MyPowerApp" \  --solution-version x.y.z.n

This step matters because it:

  • Keeps the DEV environment honest
  • Ensures exports reflect the intended version
  • Prevents a mismatch between what’s running and what’s committed

In other words, when someone looks at DEV and sees version 1.2.3.0, they can trust that Git contains the source for 1.2.3.0.

This is a deliberate choice, used only in DEV, and it has proven to be an effective way to avoid silent version drift.


Automating packaging and releases with GitHub Actions

Once the solution lives in Git, automation becomes straightforward.

We added a GitHub Actions workflow that:

  1. Reads the solution version from Solution.xml
  2. Derives a release tag (e.g. v1.2.3.0)
  3. Packages a managed solution using PAC
  4. Uploads the ZIP as a GitHub Release asset

This gives us:

  • Immutable, versioned release artifacts
  • A permanent audit trail
  • Confidence that every release was built the same way

No manual exports. No shared folders. No guesswork.


Where we are now

Today:

  • Git tells us what version exists
  • GitHub Releases tell us what was released
  • Environments tell us what is deployed
  • All three line up

Deployments are calmer. Reviews are clearer. Rollbacks are possible.


Next steps

This is not the end of the journey. Our next steps include:

  • Automating environment imports from GitHub Releases
  • Adding deployment approvals and promotion gates
  • Improving environment drift detection
  • Exploring automated checks and validations

But the foundation is now solid—and that changes everything.


Closing thoughts

Power Platform doesn’t force you to do ALM well. It gives you just enough rope to decide for yourself.

By stepping back, defining our goals, and embracing a Git‑centric approach with PAC, we moved from an unmanaged, opaque process to one that is deliberate, traceable, and repeatable.

The full workflow is available as a template on GitHub if you’d like to see how it all fits together.

And perhaps most importantly: releases are no longer exciting.

That’s a feature, not a bug.

Leave a comment