Most CI/CD blogs talk about deploying web apps — and those are relatively simple.
You push code, run tests, build, deploy to cloud, done.
But Electron desktop apps are a different world.
You’re dealing with:
- Windows, macOS, and Linux
- OS-level permissions
- Signing certificates
- Private storage
- Installers
- Auto-update logic
Six months ago, I built a complete secure update pipeline for a multi-OS Electron app, and I recently remembered the journey. So I decided to write it down properly in case someone else goes through the same struggle.
🧩 The Problem
Shipping a desktop app is not like shipping a website.
Web → backend downtime = API solves
Desktop → user already downloaded the binary
Every version matters. Every URL matters. And security matters even more.
So the goal was:
Build once → package for all OS → upload securely → users get auto-update reliably → without exposing storage URLs.
🔁 The CI/CD Flow (High-Level)
PR → Validation (ENV + Tests) → Merge to Main
→ Matrix Build (Windows + macOS + Linux)
→ Upload to Azure Blob (Versioned)
→ Update Metadata
→ CDN sync
→ Auto-Update Notifies Users
⚙️ Step 1 PR Validation
When a PR was raised, the pipeline first ensured:
- All required
.envvariables exist - All tests pass
- Nothing breaks before hitting
main
Only after that merging was allowed.
🧰 Step 2 Parallel Matrix Build (Not Sequential)
Sequential builds were slow and OS dependencies broke each other.
So I switched to a matrix build strategy each OS built in parallel:
| OS | Output |
|---|---|
| Windows |
.exe + latest.yml
|
| macOS |
.dmg / .zip
|
| Linux |
.AppImage / .deb
|
Because some OS requirements were heavy (signing certificates, Linux package dependencies, Windows secrets), parallel execution reduced overall build time massively.
📦 Step 3 Dual Blob Storage Strategy
Inside Azure I maintained two storage accounts:
| Storage | Purpose |
|---|---|
| Recent | Always contains the latest build |
| Archive | Contains version history forever |
Folder structure example
/recent/windows/app.latest.exe
/recent/mac-linux/app.latest.AppImage
/archive/1.11/windows/app-1.11.exe
/archive/1.11/mac-linux/app-1.11.AppImage
So:
- CDN always pointed to
/recent/…/app.latest.exe - But rollback was still possible via
/archive/<version>/
Users always saw:
Installing app.latest.exe
instead of app-1.11.exe — but latest still internally had version info.
🌍 Step 4 Secure CDN instead of Direct Blob Links
We never exposed Azure Blob URLs (security risk).
So CDN was placed in front of the Blob and configured with:
- CORS restricted to metadata URL only
- No public blob token exposure
- Cache invalidation triggered on every deployment
When a new version deployed:
- Only
/recent/…/app.latest.exegot replaced - Metadata file got updated
- CDN refreshed
Users never had to think about version numbers.
🔒 Step 5 Auto-Update Validation with Hash Logic
This was one of the most important security parts.
The Electron app did not blindly download the file.
Instead:
- App sends request to CDN (after 10s)
- Metadata returns latest version + hash
- App converts its own version → hash
- If both hashes match → allow update
- If mismatch → reject (prevents malicious uploads)
Even if someone somehow replaced the installer,
no existing user could be affected because they don’t know the hashing logic.
🎯 Final Result
| Requirement | Achieved |
|---|---|
| Multi-OS build | ✔️ |
| Fast builds | ✔️ (matrix strategy) |
| Secure storage | ✔️ |
| Easy rollback | ✔️ |
| Auto-update without exposing URLs | ✔️ |
| Hash-based integrity | ✔️ |
| Smooth user experience | ✔️ |
Users open the app → 10 seconds later → “A new version is available” → download starts → install done.
No version numbers, no confusion — just app.latest.exe.
🥲 Closing Thoughts
This wasn’t like CI/CD for a web API.
It took debugging OS permissions, signing certificates, platform secrets, and update logic.
Electron CI/CD looks simple in documentation until you actually do it.
But once it’s set up, the delivery becomes:
- Scalable
- Secure
- Fully automated
If you're building a production grade Electron app, you need to think like a software distributor, not just a developer.
I hope this write-up helps someone facing the same headaches I had six months ago. 😄
Top comments (0)