Back to Blog
2026-02-20
10 min read

When Azure Auto-Generated My Workflow File: A DevOps Migration Story

#Azure#DevOps#GitHub Actions#CI/CD#Docker#Node.js#Automation

When Azure Auto-Generated My Workflow File: A DevOps Migration Story

How I Solved Production Deployment Conflicts Moving from Manual Docker Builds to Automated CI/CD


TL;DR

Migrating from manual Docker deployments to automated GitHub Actions on Azure, I encountered deployment conflicts because Azure auto-generated a workflow file while my original manual workflow still existed. This post covers why this happens, how to fix it, and how to prevent it in your own projects.

Key Takeaway: Azure (and most CI/CD platforms) automatically creates workflow files when you connect GitHub Actions. Always audit your .github/workflows/ folder before enabling platform automation.


The Context: Manual Deployment Fatigue

I was running a Node.js backend on Azure App Service using manual Docker deployments. The process looked like this:

# Local development complete
# Now deploy...

# 1. Build Docker image locally
docker build -t myapp:latest .

# 2. Tag for Azure Container Registry
docker tag myapp:latest myregistry.azurecr.io/myapp:latest

# 3. Push to registry
docker push myregistry.azurecr.io/myapp:latest

# 4. Manually trigger Azure deployment
# (via Azure Portal or CLI)

It worked. But it had problems:

  • ⏰ Time-consuming: 5-10 minutes per deployment
  • πŸ”„ Manual process: Required local machine to be ready
  • 🚫 No rollback: No easy way to revert bad deployments
  • πŸ“‹ No audit trail: Beyond Git commits
  • πŸ‘€ Single point of failure: Only I could deploy

Time to modernize.


The Goal: Automated CI/CD with GitHub Actions

I wanted the holy grail of modern deployment:

PUSH TO GITHUB β†’ AUTOMATIC BUILD β†’ AUTOMATIC DEPLOY β†’ LIVE IN PRODUCTION

No manual steps. No local builds. Just code and ship.

Azure Deployment Center promised exactly this with GitHub Actions integration.


The Setup: Connecting GitHub to Azure

The process seemed straightforward. Azure's documentation made it look like three clicks:

Step 1: Navigate to Azure Deployment Center

Azure Portal β†’ Your App Service β†’ Deployment β†’ Deployment Center

Step 2: Choose GitHub Actions

Three options presented:

  • Container Registry (my current manual approach)
  • GitHub Actions ← This one!
  • Azure Pipelines

Step 3: Connect GitHub

  1. Click "Authorize" to connect GitHub account
  2. Select Organization: anupamkushwaha85
  3. Select Repository: pinnaclewear-shop
  4. Select Branch: main
  5. Click "Save"

Done. Or so I thought.


The Surprise: Azure's Auto-Generation

Within 30 seconds of clicking "Save," something unexpected happened:

A New Commit Appeared

Checking my GitHub repository, I saw:

Commit: Add or update the Azure App Service build and deployment workflow config Author: Azure GitHub Actions Files Changed: 1 file

  • main_pinnaclewear-api.yml

Azure had pushed code to my repository.

At first, I thought: "Wait, did I give it write access?"

Then I realized: This is EXACTLY what Azure is supposed to do.

What Azure Auto-Generated

Here's what the file looked like:

# .github/workflows/main_pinnaclewear-api.yml
# AUTO-GENERATED BY AZURE

name: Build and deploy Node.js app to Azure Web App - pinnaclewear-api

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js version
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'

      - name: npm install, build, and test
        run: |
          npm install
          npm run build --if-present
          npm run test --if-present

      - name: Zip artifact for deployment
        run: zip release.zip ./* -r

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v3
        with:
          name: node-app
          path: release.zip

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'Production'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v3
        with:
          name: node-app

      - name: Unzip artifact for deployment
        run: unzip release.zip

      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: 'pinnaclewear-api'
          slot-name: 'Production'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_XXXXX }}
          package: .

Impressive! Azure had created:

  • βœ… Multi-stage build and deploy jobs
  • βœ… Proper Node.js environment setup
  • βœ… Artifact handling with zip/unzip
  • βœ… Deployment secrets configuration
  • βœ… Environment and URL tracking

All optimized for my specific stack.


The Problem: Two Workflows, One Repository

Here's what I didn't realize: My old manual deployment workflow was still active.

My Repository Structure Before Azure

.github/ workflows/ manual-deploy.yml ← My original workflow

My Repository Structure After Azure

.github/ workflows/ manual-deploy.yml ← Still there! main_pinnaclewear-api.yml ← New Azure file

Both Workflows Triggered on Push

My old workflow:

on:
  push:
    branches: [ main ]

Azure's workflow:

on:
  push:
    branches: [ main ]

Result: Every push to main triggered BOTH workflows simultaneously.


The Chaos: Deployment Conflicts

My next deployment attempt looked like this:

git add .
git commit -m "Update API endpoint"
git push origin main

What Happened in GitHub Actions

Two workflow runs started simultaneously:

βœ… Manual Deploy Workflow - In Progress βœ… Build and deploy Node.js app - In Progress

Then...

❌ Manual Deploy Workflow - Failed ❌ Build and deploy Node.js app - Failed

The Error Messages

GitHub Actions Logs:

Error: Invalid workflow file (Line: 21, Col: 1): 'name' is already defined, (Line: 23, Col: 1): 'on' is already defined

Azure Build Logs showed:

Update Azure workflow to use manual secrets deleting duplicate deployment file Merge branch 'main' of https://github.com/anupamkushwaha85/pinnaclewear-shop Add or update the Azure App Service build and deployment workflow config Fix TypeError: Failed to fetch

The Git Graph Chaos

My commit history became a mess of merge commits:

  • Merge branch 'main' | | * Add or update the Azure App Service build...
  • | Update Azure workflow to use manual secrets |/
  • deleting duplicate deployment file
  • Merge branch 'main'

Production was stuck on an old version. Deployments were failing. Time to debug.


The Investigation: Understanding the Root Cause

I examined both workflow files side by side:

The Differences

| Aspect | Manual Workflow | Azure Workflow | |--------|----------------|----------------| | Docker? | Yes, multi-stage build | No, direct Node deployment | | Registry | Azure Container Registry | N/A | | Secrets | Manual ACR credentials | Azure publish profile | | Optimization | Custom | Azure-optimized | | Maintenance | Manual updates | Auto-managed by Azure |

The Conflict Points

Both workflows:

  • Triggered on the same event (push to main)
  • Tried to deploy to the same Azure App Service
  • Used different deployment mechanisms
  • Competed for deployment slots

The Solution: Merge and Consolidate

I decided to keep Azure's auto-generated workflow (better optimized) and migrate my custom configurations.

Step 1: Extract Custom Configurations

From my manual-deploy.yml, I identified what needed to be preserved:

# Custom environment variables I had configured
env:
  NODE_ENV: production
  API_VERSION: v1
  
# Custom build step
- name: Run database migrations
  run: npm run migrate:prod

Step 2: Merge into Azure's Workflow

I updated main_pinnaclewear-api.yml:

jobs:
  build:
    runs-on: ubuntu-latest
    
    # ADDED: Custom environment variables
    env:
      NODE_ENV: production
      API_VERSION: v1

    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js version
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'

      - name: npm install, build, and test
        run: |
          npm install
          npm run build --if-present
          npm run test --if-present
      
      # ADDED: Custom migration step
      - name: Run database migrations
        run: npm run migrate:prod

      - name: Zip artifact for deployment
        run: zip release.zip ./* -r

      # ... rest of Azure's config

Step 3: Delete Duplicate Workflow

git rm .github/workflows/manual-deploy.yml
git commit -m "Remove duplicate deployment workflow, merged configs into Azure-generated file"
git push origin main

Step 4: Validate

Checked GitHub Actions:

βœ… Build and deploy Node.js app to Azure Web App - Success (2m 47s)

Deployment succeeded! Production updated automatically.


The Results: Automated CI/CD Achieved

Before vs. After

BEFORE (Manual): Code ready β†’ Build locally β†’ Push to ACR β†’ Manual deploy β†’ 8-10 minutes

AFTER (Automated): Push to GitHub β†’ Auto build β†’ Auto deploy β†’ 3 minutes β†’ LIVE

Benefits Realized

βœ… Faster deployments: 8 minutes β†’ 3 minutes
βœ… Zero manual steps: Push and forget
βœ… Full audit trail: Every deployment logged in GitHub Actions
βœ… Easy rollbacks: Revert commit = auto-rollback
βœ… Team-friendly: Anyone can deploy
βœ… Build verification: Tests run automatically


The Lessons: What I Learned

1. Azure's Auto-Generation is Standard Behavior

This isn't a quirk. Every platform does this:

| Platform | Auto-Generates | Location | |----------|---------------|----------| | Azure | GitHub Actions workflow | workflows | | Vercel | Build config + workflow | vercel.json + .github | | Netlify | Build config | netlify.toml | | Railway | Railway config | railway.json | | Render | Render config | render.yaml |

2. Always Audit Before Connecting

The checklist I now follow:

# Before connecting ANY CI/CD platform:

# 1. Check existing workflows
ls -la .github/workflows/

# 2. Backup current configs
git mv .github/workflows/current.yml .github/workflows/current.yml.backup

# 3. Document custom configurations
# Note any env vars, secrets, or custom steps

# 4. THEN connect the platform

# 5. Review auto-generated file

# 6. Migrate custom configs

# 7. Test in staging first

# 8. Delete old workflows

3. Platform Automation is Actually Brilliant

Azure's auto-generation handled:

  • βœ… Optimal workflow structure for Node.js
  • βœ… Multi-stage build and deployment
  • βœ… Artifact management (zip/unzip)
  • βœ… Secret configuration via publish profiles
  • βœ… Environment tracking
  • βœ… Production deployment slots

I would have spent hours writing this manually. Azure did it in seconds.

4. Git History is Your Friend

When deployments broke, I used:

# See what changed
git log --oneline --graph

# Compare workflow files
git diff HEAD~5 .github/workflows/

# Check which commit introduced the conflict
git blame .github/workflows/main_pinnaclewear-api.yml

Git's history made debugging trivial.


Best Practices: How to Avoid This

For Migrating Existing Projects

# Migration Checklist

preparation:
  - Audit existing .github/workflows/ folder
  - Document all custom configurations
  - Test platform in staging environment first
  - Create backup branch: git checkout -b backup-workflows

connection:
  - Connect GitHub to platform (Azure/Vercel/etc.)
  - Review auto-generated configurations
  - DO NOT push to production yet

validation:
  - Compare old vs. new workflow files
  - Migrate custom environment variables
  - Migrate custom build/deployment steps
  - Test deployment in staging

cleanup:
  - Delete duplicate workflow files
  - Update documentation
  - Monitor first few production deployments
  - Keep backup branch for 2 weeks

For New Projects

# Start Clean

initial_setup:
  - Connect platform FIRST (let it auto-generate)
  - Review generated workflow
  - Customize as needed
  - Never create manual workflows if platform can auto-generate

For Teams

## Team Documentation Template

### Our CI/CD Setup

**Platform:** Azure + GitHub Actions
**Auto-Generated:** Yes (DO NOT manually create workflows)
**Workflow File:** `.github/workflows/main_app-name.yml`
**Maintained By:** Azure (auto-updated when platform changes)
**Custom Configs:** Documented in `docs/deployment.md`

### Making Changes

1. Never edit workflow file directly
2. Use Azure Deployment Center for configuration
3. For custom steps, discuss with team first
4. Test in staging before production

Technical Deep Dive: How Azure Auto-Generation Works

For those curious about the mechanics:

What Happens When You Click "Save"

  1. Azure validates GitHub connection ↓
  2. Azure analyzes your repository
    • Detects language/framework (Node.js, Python, .NET, etc.)
    • Identifies build system (npm, pip, maven, etc.)
    • Checks for Dockerfile ↓
  3. Azure selects optimal workflow template
    • Node.js β†’ Node.js + zip deployment template
    • Docker β†’ Docker build + container deployment
    • .NET β†’ .NET build + publish template ↓
  4. Azure generates workflow YAML
    • Injects app name, subscription details
    • Creates deployment secrets in GitHub
    • Adds Azure publish profile to GitHub Secrets ↓
  5. Azure commits file to GitHub
    • Uses GitHub API with your authorized token
    • Creates commit as "Azure GitHub Actions"
    • Pushes to your selected branch ↓
  6. GitHub Actions triggered immediately
    • First deployment runs automatically
    • Azure monitors deployment status

The Secrets Azure Configures

# Azure automatically creates this secret in your GitHub repo:

AZUREAPPSERVICE_PUBLISHPROFILE_XXXXXXXXXX

# This contains:
- Publishing URL
- Username/Password for deployment
- Site name and configuration
- FTP credentials (if enabled)

Why This Approach?

Pros:

  • βœ… Zero manual YAML writing
  • βœ… Optimized for your specific stack
  • βœ… Auto-updated when Azure improves templates
  • βœ… Less chance of configuration errors

Cons:

  • ❌ Can surprise developers (like it did me!)
  • ❌ May conflict with existing workflows
  • ❌ Less control over workflow structure

Conclusion: Embrace Platform Automation

This experience taught me that modern cloud platforms are DESIGNED to automate.

Azure didn't break my deployment - it did exactly what it promised: created automated CI/CD with zero manual YAML writing.

The "problem" was my existing manual workflow, which I should have cleaned up first.

Key Takeaways

  1. Auto-generation is standard - Every major platform does this
  2. Audit before connecting - Check workflows first
  3. Merge, don't fight - Combine custom configs with platform templates
  4. Trust platform optimization - Auto-generated workflows are usually better
  5. Document for your team - Prevent others from repeating your mistakes

Going Forward

I now follow a simple rule:

If a platform can auto-generate it, let it. Customize after, not before.

My deployments are faster, more reliable, and fully automated. The hour spent debugging was worth the permanent efficiency gain.


Resources & Further Reading

Official Documentation