Remember the last time you fixed a bug, ran tests locally, zipped the app, logged into Azure, clicked deploy, and prayed nothing broke? Now imagine doing that ten times a day across a team of eight developers. Something will slip through.
That is the problem CI/CD solves. And GitHub Actions is one of the easiest ways to set it up if your code already lives on GitHub. Let us walk through what it is, why it matters, and how to ship a .NET app to Azure automatically.
What is GitHub Actions CI/CD?
CI/CD stands for Continuous Integration and Continuous Deployment. In plain English: every time someone pushes code, a robot builds it, runs tests, and — if everything passes — deploys it to your servers.
GitHub Actions is GitHub's built-in automation engine. You write a workflow (a YAML file) that says, "When code lands on the main branch, run these steps." GitHub spins up a temporary virtual machine, runs your steps, and reports pass or fail.
Think of it like a car assembly line. Each station does one job — weld, paint, inspect — and the car only moves forward when the current step succeeds. Your code gets the same treatment.
Why do we need it?
Manual deploys are slow, inconsistent, and stressful. One person forgets a config file. Another skips tests because it is Friday evening. CI/CD removes that human roulette.
Teams adopt it because it:
- Catches broken builds before users see them.
- Makes every deploy repeatable — same steps, every time.
- Frees developers from copy-paste deploy rituals.
- Creates an audit trail: who deployed what, and when.
For Azure apps — App Service, Functions, containers — a pipeline is the bridge between your GitHub repo and your cloud environment.
How does it work?
A workflow has three main pieces: a trigger (when to run), a runner (where steps execute), and jobs/steps (what to do).
Common triggers are push to a branch or opening a pull request. The runner is usually ubuntu-latest — a fresh Linux machine GitHub provides for free (with usage limits).
Developer pushes code to GitHub
↓
Workflow triggers (on: push)
↓
Runner starts → checkout code
↓
dotnet build + dotnet test
↓
Deploy to Azure App Service
↓
Live site updated (if tests passed)
To deploy to Azure safely, use OIDC (OpenID Connect). Instead of storing long-lived Azure passwords in GitHub, GitHub proves its identity to Azure and gets a short-lived token. It is like showing a visitor badge instead of giving someone your house keys.
Real-world example
A food delivery startup ships its ordering API as a .NET app on Azure App Service. Ten developers merge pull requests daily.
Before CI/CD, the lead developer deployed manually every evening. Bugs reached customers when someone skipped tests. After GitHub Actions, every merge to main runs unit tests, builds a release package, and deploys to a staging slot. Only after a smoke test passes does the team swap staging to production — like previewing a YouTube video before publishing it live.
Step-by-step: your first pipeline
Step 1: In Azure, create a federated credential on a user-assigned managed identity or app registration that trusts GitHub's OIDC issuer.
Step 2: Add the identity details as GitHub repository variables (tenant ID, client ID, subscription ID).
Step 3: Create .github/workflows/azure-deploy.yml in your repo.
Step 4: Add build and test steps with the official actions/setup-dotnet action.
Step 5: Add an Azure login step with azure/login@v2 using OIDC, then deploy with azure/webapps-deploy.
name: Deploy to Azure App Service
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- run: dotnet restore
- run: dotnet build --configuration Release
- run: dotnet test --no-build
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
- uses: azure/webapps-deploy@v3
with:
app-name: my-api-app
package: ./publish
Common misconceptions
"CI/CD means deploy to production on every commit." Not necessarily. Many teams auto-deploy to staging but require approval for production. You control the rules.
"Pipelines are only for big companies." A ten-line workflow on a free GitHub plan beats manual FTP uploads for a solo developer too.
"If the pipeline is green, the app is perfect." Tests catch what you wrote tests for. You still need monitoring and staging validation — CI/CD is a safety net, not a crystal ball.
| Step | What it does | Why it matters |
|---|---|---|
dotnet restore | Downloads NuGet packages | Ensures the build has all dependencies |
dotnet test | Runs automated tests | Blocks broken logic from deploying |
azure/login | Authenticates to Azure via OIDC | No long-lived passwords in GitHub |
webapps-deploy | Pushes the build to App Service | Updates the live site automatically |
Quick recap
- CI/CD automates build, test, and deploy every time code changes.
- GitHub Actions workflows live in
.github/workflowsas YAML files. - Use OIDC to connect GitHub to Azure without storing permanent secrets.
- Failed tests should stop the pipeline — that is the whole point.
Summary
GitHub Actions turns deploy day into deploy minute. You define the assembly line once; every push rides through the same stations. Azure receives only builds that passed your tests, authenticated through short-lived tokens.
Start with build and test on pull requests. Add staging deploy next. Production promotion can wait until you trust the flow — but even the first step saves hours and prevents "it worked on my machine" surprises.
Frequently Asked Questions
.github/workflows that defines steps to run on events like push or pull request — build, test, deploy, and more.Key Takeaways
- GitHub Actions automates build, test, and deploy on every code change.
- Workflows are YAML files triggered by events like push or pull request.
- OIDC lets GitHub authenticate to Azure without permanent passwords.
- Start with test gates on pull requests before enabling production deploys.