Over the last few years, I've worked with teams using GitHub Actions, GitLab CI/CD, Jenkins, CircleCI, Azure DevOps, and newer AI-native delivery platforms. One lesson keeps coming up:
The more vendor-specific your pipeline YAML becomes, the harder it is to migrate later.
By keeping pipeline definitions modular, separating business logic from platform-specific configuration, and relying on portable scripts where possible, teams can significantly reduce migration effort while preserving flexibility.
The Problem
Most CI/CD platforms use YAML.
At first glance, they look remarkably similar.
steps:
- checkout
- install
- test
- build
- deploy
But beneath that familiar syntax are platform-specific features:
Custom actions
Proprietary expressions
Vendor-specific runners
Secret management APIs
Environment variables
Deployment strategies
Over time, those dependencies become difficult to untangle.
I’ve seen teams realize this only when they wanted to migrate to a different platform—or simply evaluate another option.
YAML Isn't Portable by Default
Many developers assume YAML equals portability.
It doesn't.
This GitHub Actions example:
name: CI
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test
works perfectly...
...inside GitHub Actions.
Moving it to GitLab CI or another platform usually means rewriting jobs, triggers, environment variables, authentication, and deployment steps.
The YAML file survives.
The workflow doesn't.
What Actually Travels Well?
I've had much better results treating the pipeline as an orchestrator—not the place where all the logic lives.
Instead of embedding everything inside YAML, move reusable logic into scripts.
For example:
steps:
- run: ./scripts/install.sh
- run: ./scripts/test.sh
- run: ./scripts/build.sh
- run: ./scripts/deploy.sh
Now those scripts can be reused almost anywhere:
GitHub Actions
GitLab CI/CD
Jenkins
CircleCI
Azure DevOps
Self-hosted runners
The pipeline simply decides when to execute them.
Keep Vendor-Specific Features at the Edge
Some platform-specific features are worth using.
Examples include:
GitHub Actions Marketplace
GitLab Review Apps
Azure DevOps Environments
CircleCI Orbs
The mistake is building the entire delivery process around them.
Instead, I try to isolate vendor-specific functionality to small sections of the pipeline.
That makes future migrations far less painful.
Standardize the Workflow
Across projects, I like keeping the same delivery stages regardless of platform:
Checkout
↓
Dependencies
↓
Lint
↓
Tests
↓
Build
↓
Security Scan
↓
Package
↓
Deploy
The orchestration tool can change.
The workflow remains familiar.
Infrastructure Should Be Portable Too
The same philosophy applies outside CI/CD.
Instead of relying on deployment features tied to one platform, use portable infrastructure tooling where practical.
Examples include:
Docker
Kubernetes
Terraform
OpenTofu
OpenTelemetry
These standards make changing CI/CD platforms much less disruptive because the surrounding ecosystem remains consistent.
Where AI Can Help
As AI becomes more integrated into software delivery, I think portability becomes even more important.
An AI system that understands your delivery workflow shouldn't depend entirely on one CI/CD vendor.
Instead, it should reason about concepts like:
Build failures
Test results
Security findings
Infrastructure changes
Deployment health
Those concepts exist regardless of whether the pipeline runs in GitHub Actions, GitLab CI/CD, Jenkins, or another platform.
That's one reason I'm interested in AI-native delivery platforms like Revolte. Rather than replacing existing CI/CD tools, the idea is to add intelligence around the delivery workflow—analyzing pipelines, deployments, infrastructure, and runtime behavior—while allowing teams to continue using the tools that fit their environment.
What I'd Do Today
If I were designing a CI/CD platform from scratch, I'd follow a few simple rules:
Keep YAML as thin as possible.
Move business logic into reusable scripts.
Prefer open standards over proprietary integrations.
Standardize pipeline stages across repositories.
Isolate vendor-specific functionality.
Treat CI/CD as interchangeable infrastructure, not a permanent dependency.
Those decisions don't eliminate migration work, but they make future changes dramatically easier.
Final Thoughts
Vendor lock-in rarely haxppens overnight.
It happens one convenient feature at a time.
Most of those features are useful, and many are worth adopting. The key is knowing where convenience ends and long-term flexibility begins.
For me, portable pipelines aren't about preparing to switch CI/CD vendors tomorrow. They're about preserving the freedom to evolve your engineering stack as your team's needs change.
A little discipline in how you structure your YAML today can save weeks—or even months—of migration effort down the road.
Top comments (0)