Back to skills
SkillHub ClubShip Full StackFull Stack

azure-upgrade

Assess and upgrade Azure workloads between plans, tiers, or SKUs within Azure. Generates assessment reports and automates upgrade steps. WHEN: upgrade Consumption to Flex Consumption, upgrade Azure Functions plan, migrate hosting plan, upgrade Functions SKU, move to Flex Consumption, upgrade Azure service tier, change hosting plan, upgrade function app plan, migrate App Service to Container Apps.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
401
Hot score
99
Updated
March 20, 2026
Overall rating
C3.5
Composite score
3.5
Best-practice grade
C62.8

Install command

npx @skill-hub/cli install microsoft-azure-skills-azure-upgrade

Repository

microsoft/azure-skills

Skill path: .github/plugins/azure-skills/skills/azure-upgrade

Assess and upgrade Azure workloads between plans, tiers, or SKUs within Azure. Generates assessment reports and automates upgrade steps. WHEN: upgrade Consumption to Flex Consumption, upgrade Azure Functions plan, migrate hosting plan, upgrade Functions SKU, move to Flex Consumption, upgrade Azure service tier, change hosting plan, upgrade function app plan, migrate App Service to Container Apps.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: MIT.

Original source

Catalog source: SkillHub Club.

Repository owner: microsoft.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install azure-upgrade into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/microsoft/azure-skills before adding azure-upgrade to shared team environments
  • Use azure-upgrade for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: azure-upgrade
description: "Assess and upgrade Azure workloads between plans, tiers, or SKUs within Azure. Generates assessment reports and automates upgrade steps. WHEN: upgrade Consumption to Flex Consumption, upgrade Azure Functions plan, migrate hosting plan, upgrade Functions SKU, move to Flex Consumption, upgrade Azure service tier, change hosting plan, upgrade function app plan, migrate App Service to Container Apps."
license: MIT
metadata:
  author: Microsoft
  version: "1.0.0"
---

# Azure Upgrade

> This skill handles **assessment and automated upgrades** of existing Azure workloads from one Azure service, hosting plan, or SKU to another — all within Azure. This includes plan/tier upgrades (e.g. Consumption → Flex Consumption), cross-service migrations (e.g. App Service → Container Apps), and SKU changes. This is NOT for cross-cloud migration — use `azure-cloud-migrate` for that.

## Triggers

| User Intent | Example Prompts |
|-------------|-----------------|
| Upgrade Azure Functions plan | "Upgrade my function app from Consumption to Flex Consumption" |
| Change hosting tier | "Move my function app to a better plan" |
| Assess upgrade readiness | "Is my function app ready for Flex Consumption?" |
| Automate plan migration | "Automate the steps to upgrade my Functions plan" |

## Rules

1. Follow phases sequentially — do not skip
2. Generate an assessment before any upgrade operations
3. Load the scenario reference and follow its rules
4. Use `mcp_azure_mcp_get_bestpractices` and `mcp_azure_mcp_documentation` MCP tools
5. Destructive actions require `ask_user` — [global-rules](references/global-rules.md)
6. Always confirm the target plan/SKU with the user before proceeding
7. Never delete or stop the original app without explicit user confirmation
8. All automation scripts must be idempotent and resumable

## Upgrade Scenarios

| Source | Target | Reference |
|--------|--------|-----------|
| Azure Functions Consumption Plan | Azure Functions Flex Consumption Plan | [consumption-to-flex.md](references/services/functions/consumption-to-flex.md) |

> No matching scenario? Use `mcp_azure_mcp_documentation` and `mcp_azure_mcp_get_bestpractices` tools to research the upgrade path.

## MCP Tools

| Tool | Purpose |
|------|---------|
| `mcp_azure_mcp_get_bestpractices` | Get Azure best practices for the target service |
| `mcp_azure_mcp_documentation` | Look up Azure documentation for upgrade scenarios |
| `mcp_azure_mcp_appservice` | Query App Service and Functions plan details |
| `mcp_azure_mcp_applicationinsights` | Verify monitoring configuration |

## Steps

1. **Identify** — Determine the source and target Azure plans/SKUs. Ask user to confirm.
2. **Assess** — Analyze existing app for upgrade readiness → load scenario reference (e.g., [consumption-to-flex.md](references/services/functions/consumption-to-flex.md))
3. **Pre-migrate** — Collect settings, identities, configs from the existing app
4. **Upgrade** — Execute the automated upgrade steps (create new resources, migrate settings, deploy code)
5. **Validate** — Hit the function app default URL to confirm the app is reachable, then verify endpoints and monitoring
6. **Ask User** — "Upgrade complete. Would you like to verify performance, clean up the old app, or update your IaC?"
7. **Hand off** to `azure-validate` for deep validation or `azure-deploy` for CI/CD setup

Track progress in `upgrade-status.md` inside the workspace root.

## References

- [Global Rules](references/global-rules.md)
- [Workflow Details](references/workflow-details.md)
- **Functions**
  - [Consumption to Flex Consumption](references/services/functions/consumption-to-flex.md)
  - [Assessment](references/services/functions/assessment.md)
  - [Automation Scripts](references/services/functions/automation.md)

## Next

After upgrade is validated, hand off to:
- `azure-validate` — for thorough post-upgrade validation
- `azure-deploy` — if the user wants to set up CI/CD for the new app


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/global-rules.md

```markdown
# Global Rules

These rules apply to ALL phases of the azure-upgrade skill.

## Destructive Action Policy

⛔ **NEVER** perform destructive actions without explicit user confirmation via `ask_user`:
- Deleting apps, services, or resource groups
- Stopping or disabling the original app/service
- Overwriting app settings or configuration in the new app
- Removing the original hosting plan or service tier
- Modifying DNS or custom domain bindings

## User Confirmation Required

Always use `ask_user` before:
- Selecting target Azure subscription
- Selecting target Azure region/location
- Creating new Azure resources
- Stopping or deleting the original app/service
- Modifying custom domains or network restrictions
- Any irreversible configuration change

## Best Practices

- Always use `mcp_azure_mcp_get_bestpractices` tool before generating upgrade commands
- Prefer managed identity over connection strings — upgrades are a good time to improve security
- **Always target the latest supported runtime version** — check Azure docs for the newest GA version
- Keep the original app/service running until the upgraded one is fully validated
- Use the same resource group for the new resource to maintain access to existing dependencies
- Follow Azure naming conventions for all new resources

## Identity-First Authentication (Zero API Keys)

> Enterprise subscriptions commonly enforce policies that block local auth. Always design for identity-based access from the start.

- Prefer managed identity connections over connection strings/keys
- Use `DefaultAzureCredential` in code — works locally and in Azure
- When using User Assigned Managed Identity, always pass `managedIdentityClientId` explicitly
- See service-specific identity configuration in the scenario reference files

## Rollback Policy

- Always document rollback steps before executing upgrade
- Keep the original app intact and running until upgrade is validated
- If upgrade fails, guide the user to restart the original app
- Never delete the original app automatically — always require `ask_user`

```

### references/services/functions/consumption-to-flex.md

```markdown
# Consumption Plan to Flex Consumption Plan Upgrade

> **Source**: Azure Functions Consumption Plan (Y1/Dynamic) on Linux
> **Target**: Azure Functions Flex Consumption Plan (FC1/FlexConsumption)
> **Platform**: Linux only (Windows support planned for future)
> **Docs**: [Linux migration guide](https://learn.microsoft.com/en-us/azure/azure-functions/migration/migrate-plan-consumption-to-flex?pivots=platform-linux)

## Why Upgrade?

- **Faster cold starts** — always-ready instances mean functions respond more quickly
- **Better scaling** — per-function scaling and concurrency controls
- **Virtual network support** — connect to private networks and use private endpoints
- **Active investment** — Flex Consumption is where new features land first

## What to Expect

1. Your **code stays the same** — no rewriting required if on a supported language version
2. You'll **create a new app** alongside the existing one
3. New app runs in the **same resource group** with access to the same dependencies
4. You **control the timing** — test thoroughly before switching over

## Platform Notes

- Linux Consumption is being **retired September 30, 2028**
- Azure CLI provides automated migration commands: `az functionapp flex-migration list` and `az functionapp flex-migration start`
- The `flex-migration` commands handle assessment, app creation, and most configuration migration automatically
- Deployment packages are in `squashfs` format stored in `scm-releases` blob container

## Prerequisites

- Azure CLI v2.77.0+
- `resource-graph` extension: `az extension add --name resource-graph`
- `jq` tool for JSON processing
- Owner or Contributor role in the resource group
- Permissions to create and manage function apps, storage accounts, App Insights resources, and managed identity role assignments

## Compatibility Requirements

### Supported Language Stacks

| Stack ID | Language | Supported? |
|----------|----------|------------|
| `dotnet-isolated` | .NET (isolated worker model) | ✅ Yes |
| `node` | JavaScript/TypeScript | ✅ Yes |
| `java` | Java | ✅ Yes |
| `python` | Python | ✅ Yes |
| `powershell` | PowerShell | ✅ Yes |
| `dotnet` | .NET (in-process model) | ❌ No — must migrate to isolated first |
| `custom` | Custom handlers | ✅ Yes |

### Known Limitations (Flex Consumption)

| Feature | Status | Impact |
|---------|--------|--------|
| Deployment slots | ❌ Not supported | Rearchitect to use separate apps |
| TLS/SSL certificates | ❌ Not supported | Wait for support or find alternative |
| Blob trigger (polling) | ❌ Only EventGrid source | Convert `LogsAndContainerScan` → `EventGrid` |
| Azure Government | ❌ Not available | Cannot migrate yet |

## Upgrade Phases

### Phase 1: Assessment

Run all checks from [assessment.md](assessment.md). Use the automated eligibility check:

```bash
# Automated eligibility check — scans all Linux Consumption apps
az functionapp flex-migration list
```

This returns `eligible_apps` and `ineligible_apps` arrays with specific reasons for any incompatibilities. For detailed manual checks, see [automation.md](automation.md).

### Phase 2: Pre-migration (Collect Everything)

Collect all settings and configurations from the existing app before creating the new one. See **Step-by-step scripts** in [automation.md](automation.md):

1. Collect app settings
2. Collect application configurations (CORS, custom domains, HTTP version, TLS, client certs, etc.)
3. Identify managed identities and RBAC role assignments
4. Identify built-in authentication settings
5. Review inbound access restrictions
6. Get the code deployment package (if source code not in version control)

### Phase 3: Create Flex Consumption App

Run the automated migration command from [automation.md](automation.md) — Step 4.

The `flex-migration start` command automatically:
- Assesses your source app for Flex Consumption compatibility
- Creates a new function app in the Flex Consumption plan
- Migrates app settings, identity assignments, storage mounts, CORS, custom domains, and access restrictions

> 💡 Use Microsoft Entra ID + managed identities instead of connection strings when creating the new app.

### Identity-First Configuration (Functions)

Enterprise subscriptions commonly enforce policies blocking local auth. Configure identity-based access:

- **Storage accounts**: Use `AzureWebJobsStorage__credential`, `__clientId`, and service-specific URIs (`__blobServiceUri`, `__queueServiceUri`, `__tableServiceUri`)
- **Application Insights**: Use `APPLICATIONINSIGHTS_AUTHENTICATION_STRING` with `Authorization=AAD`
- When using User Assigned Managed Identity, pass `managedIdentityClientId` explicitly

### Phase 4: Verify and Configure the New App

The `flex-migration start` command handles most configuration. Verify the results and manually configure anything it doesn't cover (see [automation.md](automation.md)):

1. **Verify** migrated app settings, identities, custom domains
2. **Configure** built-in authentication (if used — not auto-migrated)
3. **Configure** scale and concurrency settings (if custom values needed)
4. **Enable** Application Insights monitoring

### Phase 5: Deploy Code

> ⚠️ **Code is NOT automatically migrated.** The new app is created with config only — you must deploy code separately.

**Use `ask_user` to present these options:**

> Your new Flex Consumption app `<NEW_APP_NAME>` has been created and configured. Now we need to deploy your function code. How would you like to proceed?
>
> 1. **Update CI/CD pipeline** — I'll help you update your Azure Pipelines or GitHub Actions workflow to target the new app
> 2. **Deploy from local project** — I'll run `func azure functionapp publish <NEW_APP_NAME>` from your project directory
> 3. **Deploy existing package** — I'll deploy the package we downloaded earlier from the original app

After user selects an option, execute the corresponding deployment method from [automation.md](automation.md) — Step 5.

> ⚠️ After deployment, triggers immediately start processing. Review mitigation strategies for your trigger types.

**After successful deployment, inform the user:**

> Code deployed! Next steps to consider:
>
> - The original app is still running — keep it as rollback for a few days
> - Update any clients/pipelines to point to the new URL
> - Enable HTTPS-only and managed identity on the new app for better security
> - When confident, you can delete the original app

### Phase 6: Post-Upgrade Validation

1. **Smoke test** — Get the app’s default hostname via `az functionapp show --query defaultHostName -o tsv`, then hit that URL and confirm it returns a non-error response (HTTP 2xx/4xx, not connection refused or 503). This is the minimum bar before proceeding.
2. Verify the app is running on Flex Consumption (`az functionapp show --query sku`)
3. Test HTTP trigger endpoints (e.g. `curl https://<DEFAULT_HOST>/api/<FUNCTION_NAME>`)
4. Capture and compare performance benchmarks
5. Set up monitoring dashboards
6. Refine scale/concurrency settings
7. Update IaC (Bicep/Terraform) to reflect new plan

### Phase 7: Cleanup (Optional)

- Keep the original app for a few days/weeks as rollback
- Consumption plan charges only for actual usage — low cost to keep idle
- When confident, delete using the command in [automation.md](automation.md) — Step 7

## Trigger Migration Risks

| Trigger Type | Risk | Mitigation |
|-------------|------|------------|
| Azure Blob storage | High | Create separate container for event-based trigger in new app |
| Azure Cosmos DB | High | Create dedicated lease container for new app; set `StartFromBeginning: false` |
| Azure Event Grid | Medium | Recreate event subscriptions; ensure idempotent functions |
| Azure Event Hubs | Medium | Create new consumer group for new app |
| Azure Service Bus | High | Create new topic/queue; update senders; drain original before shutdown |
| Azure Storage Queue | High | Create new queue; update senders; drain original before shutdown |
| HTTP | Low | Update clients to target new app URL |
| Timer | Low | Offset schedules during cutover to avoid simultaneous execution |

## IaC Key Differences

| Property | Consumption | Flex Consumption |
|----------|-------------|------------------|
| SKU | `Y1` (Dynamic) | `FC1` (FlexConsumption) |
| Plan required | Optional (auto-created) | Required (must be explicit) |
| OS | Linux | Linux only |
| Configuration | App settings | `functionAppConfig` section |
| Storage | `WEBSITE_CONTENTSHARE` setting | `deployment.storage` in `functionAppConfig` |

## Deprecated Settings (Do NOT Migrate)

These app settings are NOT supported in Flex Consumption and should be filtered out:

- `WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED`
- `AzureWebJobsStorage*` (replaced by identity-based config)
- `WEBSITE_MOUNT_ENABLED`
- `ENABLE_ORYX_BUILD`
- `FUNCTIONS_EXTENSION_VERSION` (set via `functionAppConfig`)
- `FUNCTIONS_WORKER_RUNTIME` (set via `functionAppConfig`)
- `FUNCTIONS_WORKER_RUNTIME_VERSION`
- `FUNCTIONS_MAX_HTTP_CONCURRENCY`
- `FUNCTIONS_WORKER_PROCESS_COUNT`
- `FUNCTIONS_WORKER_DYNAMIC_CONCURRENCY_ENABLED`
- `SCM_DO_BUILD_DURING_DEPLOYMENT`
- `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`
- `WEBSITE_CONTENTOVERVNET`
- `WEBSITE_CONTENTSHARE`
- `WEBSITE_DNS_SERVER`
- `WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT`
- `WEBSITE_NODE_DEFAULT_VERSION`
- `WEBSITE_RUN_FROM_PACKAGE`
- `WEBSITE_SKIP_CONTENTSHARE_VALIDATION`
- `WEBSITE_VNET_ROUTE_ALL`
- `APPLICATIONINSIGHTS_CONNECTION_STRING` (already created in new app)

## Troubleshooting

| Issue | Remediation |
|-------|-------------|
| Cold start performance issues | Review concurrency settings; check for missing dependencies |
| Missing bindings | Verify extension bundles; update binding configurations |
| Permission errors | Check identity assignments and role permissions |
| Network connectivity | Validate access restrictions and networking settings |
| Missing App Insights | Recreate the Application Insights connection |
| App fails to start | Check portal Diagnose & Solve; review App Insights Failures blade |
| Triggers not processing | Verify binding configs, connection strings, consumer groups |

## Rollback

1. Restart the original app: `az functionapp start --name <ORIGINAL_APP_NAME> --resource-group <RESOURCE_GROUP>`
2. Redirect clients back to original resources (queues/topics/containers)
3. Revert DNS or custom domain changes
4. Delete the new Flex Consumption app if needed

## References

- [Flex Consumption plan overview](https://learn.microsoft.com/en-us/azure/azure-functions/flex-consumption-plan)
- [How to use the Flex Consumption plan](https://learn.microsoft.com/en-us/azure/azure-functions/flex-consumption-how-to)
- [Azure CLI flex-migration commands](https://learn.microsoft.com/en-us/cli/azure/functionapp/flex-migration) (Linux only)
- [Flex Consumption IaC samples](https://github.com/Azure-Samples/azure-functions-flex-consumption-samples/tree/main/IaC)
- [Flex Consumption plan deprecations](https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings#flex-consumption-plan-deprecations)

```

### references/workflow-details.md

```markdown
# Workflow Details

## Upgrade Workflow Phases

The azure-upgrade skill follows a structured workflow to ensure safe, repeatable upgrades.

## Phase Overview

```
┌──────────┐    ┌──────────┐    ┌─────────────┐    ┌─────────┐    ┌──────────┐
│ Identify │───▶│  Assess  │───▶│ Pre-migrate │───▶│ Upgrade │───▶│ Validate │
└──────────┘    └──────────┘    └─────────────┘    └─────────┘    └──────────┘
```

## Progress Tracking

Create and maintain `upgrade-status.md` in the workspace root:

```markdown
# Upgrade Status

## Upgrade Details

| Property | Value |
|----------|-------|
| **Source App** | <app-name> |
| **Source Plan** | <current-plan> |
| **Target Plan** | <target-plan> |
| **Resource Group** | <resource-group> |
| **Region** | <region> |
| **Started** | <date> |

## Phase Status

- [ ] Phase 1: Identify — Determine source/target plans
- [ ] Phase 2: Assess — Check readiness and compatibility
- [ ] Phase 3: Pre-migrate — Collect settings and configurations
- [ ] Phase 4: Upgrade — Execute upgrade automation
- [ ] Phase 5: Validate — Verify new app functionality

## Notes

<any issues, decisions, or observations during upgrade>
```

## Error Handling

If any phase fails:
1. Log the error in `upgrade-status.md`
2. Do NOT proceed to the next phase
3. Inform the user of the failure and suggest remediation
4. Offer to retry the failed phase or rollback

## Hand-off

After successful validation:
- Offer to hand off to `azure-validate` for deeper testing
- Offer to hand off to `azure-deploy` for CI/CD pipeline setup
- Ask if the user wants to clean up the original app

```

### references/services/functions/assessment.md

```markdown
# Assessment: Functions Plan Upgrade

Generate an upgrade assessment report before any changes to Azure resources.

## Prerequisites

- User has an existing Azure Functions app on a Consumption or other plan
- User has Azure CLI v2.77.0+ installed
- User has Owner or Contributor role in the target resource group
- The `resource-graph` extension is installed (`az extension add --name resource-graph`)

## Assessment Steps

1. **Identify Source App** — Confirm the function app name, resource group, region, and current hosting plan
2. **Check Region Compatibility** — Verify the target plan is available in the app's region
3. **Verify Language Stack** — Confirm the app's runtime is supported on the target plan
4. **Verify Stack Version** — Confirm the runtime version is supported on the target plan in the region
5. **Check Deployment Slots** — Determine if slots are in use (Flex Consumption doesn't support slots)
6. **Check Certificates** — Determine if TLS/SSL certificates are in use (not yet supported in Flex Consumption)
7. **Check Blob Triggers** — Verify blob triggers use EventGrid source (container polling not supported in Flex Consumption)
8. **Assess Dependencies** — Review upstream and downstream service dependencies and plan mitigation strategies
9. **Generate Report** — Create `upgrade-assessment-report.md`

## Assessment Report Format

> ⚠️ **MANDATORY**: Use these exact section headings in every assessment report. Do NOT rename, reorder, or omit sections.

The report MUST be saved as `upgrade-assessment-report.md` in the workspace root.

```markdown
# Upgrade Assessment Report

## 1. Executive Summary

| Property | Value |
|----------|-------|
| **App Name** | <app-name> |
| **Resource Group** | <resource-group> |
| **Current Plan** | <current-plan (e.g., Consumption / Y1 Dynamic)> |
| **Target Plan** | <target-plan (e.g., Flex Consumption / FC1)> |
| **Region** | <region> |
| **Runtime** | <runtime and version> |
| **OS** | <Linux / Windows> |
| **Upgrade Readiness** | <Ready / Needs Attention / Blocked> |
| **Assessment Date** | <date> |

## 2. Compatibility Checks

| Check | Status | Details |
|-------|--------|---------|
| Region supported | ✅ / ❌ | |
| Language stack supported | ✅ / ❌ | |
| Stack version supported | ✅ / ❌ | |
| No deployment slots | ✅ / ⚠️ | |
| No TLS/SSL certificates | ✅ / ⚠️ | |
| Blob triggers use EventGrid | ✅ / ⚠️ / N/A | |
| .NET isolated (not in-process) | ✅ / ❌ / N/A | |

## 3. App Settings Inventory

| Setting | Value | Migrate? | Notes |
|---------|-------|----------|-------|
| | | Yes / No / Convert | |

## 4. Managed Identities

| Type | Principal ID | Roles | Action |
|------|-------------|-------|--------|
| System-assigned | | | Recreate in new app |
| User-assigned | | | Reassign to new app |

## 5. Application Configurations

| Configuration | Current Value | Migrate? | Notes |
|---------------|---------------|----------|-------|
| CORS settings | | | |
| Custom domains | | | |
| HTTP version | | | |
| HTTPS only | | | |
| TLS version | | | |
| Client certificates | | | |
| Access restrictions | | | |
| Built-in auth | | | |

## 6. Trigger & Binding Analysis

| Function | Trigger Type | Source | Migration Risk | Mitigation |
|----------|-------------|--------|----------------|------------|
| | | | Low / Medium / High | |

## 7. Dependent Services

| Service | Dependency Type | Migration Risk | Mitigation Strategy |
|---------|----------------|----------------|---------------------|
| | Upstream / Downstream | | |

## 8. Blockers & Warnings

### Blockers (must fix before upgrade)
- [ ] <any blocking issues>

### Warnings (should address but not blocking)
- [ ] <any non-blocking concerns>

## 9. Recommendations

1. **Plan**: <recommended target plan>
2. **Auth**: <switch to Managed Identity if using connection strings>
3. **Monitoring**: <Application Insights configuration>
4. **Scaling**: <recommended instance count and concurrency settings>

## 10. Next Steps

- [ ] Review and approve this assessment
- [ ] Address any blockers listed above
- [ ] Proceed to automated upgrade (Phase 3-4)
```

> 💡 **Tip:** Use `mcp_azure_mcp_get_bestpractices` to get the latest recommendations for the target hosting plan.

```

### references/services/functions/automation.md

```markdown
# Automation: Consumption to Flex Consumption Upgrade

> These are the Azure CLI scripts to automate the upgrade from Linux Consumption plan to Flex Consumption plan.
> All scripts use `bash` syntax compatible with Azure Cloud Shell. For PowerShell, adapt accordingly.
>
> **Source docs**: [Linux migration guide](https://learn.microsoft.com/en-us/azure/azure-functions/migration/migrate-plan-consumption-to-flex?pivots=platform-linux)

## Prerequisites

```bash
# Ensure Azure CLI v2.77.0+
az --version

# Install resource-graph extension
az extension add --name resource-graph

# Login and set subscription
az login
az account set --subscription <SUBSCRIPTION_ID>
```

---

## Step 1: Identify Candidate Apps

```bash
# List all Linux Consumption apps with eligibility status
az functionapp flex-migration list
```

This returns two arrays:
- `eligible_apps` — apps that can be migrated to Flex Consumption
- `ineligible_apps` — apps with specific reasons why not

The output includes app name, resource group, location, and runtime stack for each app.

---

## Step 2: Assessment Checks

Set variables for your app:

```bash
appName=<APP_NAME>
rgName=<RESOURCE_GROUP>
```

### 2a. Confirm Region Compatibility

```bash
# List all regions where Flex Consumption is available
az functionapp list-flexconsumption-locations --query "sort_by(@, &name)[].{Region:name}" -o table
```

### 2b. Verify Language Stack Compatibility

Supported stacks: `dotnet-isolated`, `node`, `java`, `python`, `powershell`, `custom`.
**Not supported**: `dotnet` (in-process) — must migrate to isolated first.

### 2c. Verify Stack Version Compatibility

```bash
# Check supported versions for a specific runtime in a specific region
az functionapp list-flexconsumption-runtimes --location <REGION> --runtime <LANGUAGE_STACK> \
    --query '[].{version:version}' -o tsv
```

Replace `<REGION>` with the app's region and `<LANGUAGE_STACK>` with one of: `dotnet-isolated`, `java`, `node`, `powershell`, `python`.

### 2d. Check Deployment Slots

```bash
# List any deployment slots
az functionapp deployment slot list --name $appName --resource-group $rgName --output table
```

If this returns entries, the app has slots. Flex Consumption does NOT support slots — plan accordingly.

### 2e. Check TLS/SSL Certificates

```bash
# List certificates available to the app
az webapp config ssl list --resource-group $rgName
```

If this returns output, the app likely uses certificates. Flex Consumption does NOT support certs yet.

### 2f. Check Blob Storage Triggers

```bash
# Find blob triggers NOT using EventGrid source
az functionapp function list --name $appName --resource-group $rgName \
  --query "[?config.bindings[0].type=='blobTrigger' && config.bindings[0].source!='EventGrid'].{Function:name,TriggerType:config.bindings[0].type,Source:config.bindings[0].source}" \
  --output table
```

If this returns rows, convert those blob triggers from `LogsAndContainerScan` to `EventGrid` before upgrading.

---

## Step 3: Pre-Migration — Collect Settings

### 3a. Collect App Settings

```bash
appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

# Get all app settings as JSON
app_settings=$(az functionapp config appsettings list --name $appName --resource-group $rgName)
echo "$app_settings"
```

### 3b. Collect Application Configurations

```bash
appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

echo "Getting commonly used site settings..."
az functionapp config show --name $appName --resource-group $rgName \
    --query "{http20Enabled:http20Enabled, httpsOnly:httpsOnly, minTlsVersion:minTlsVersion, \
    minTlsCipherSuite:minTlsCipherSuite, clientCertEnabled:clientCertEnabled, \
    clientCertMode:clientCertMode, clientCertExclusionPaths:clientCertExclusionPaths}"

echo "Checking for SCM basic publishing credentials policies..."
az resource show --resource-group $rgName --name scm --namespace Microsoft.Web \
    --resource-type basicPublishingCredentialsPolicies --parent sites/$appName --query properties

echo "Checking for the maximum scale-out limit configuration..."
az functionapp config appsettings list --name $appName --resource-group $rgName \
    --query "[?name=='WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT'].value" -o tsv

echo "Checking for any file share mount configurations..."
az webapp config storage-account list --name $appName --resource-group $rgName

echo "Checking for any custom domains..."
az functionapp config hostname list --webapp-name $appName --resource-group $rgName \
    --query "[?contains(name, 'azurewebsites.net')==\`false\`]" --output table

echo "Checking for any CORS settings..."
az functionapp cors show --name $appName --resource-group $rgName
```

### 3c. Identify Managed Identities and Role Assignments

```bash
appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

echo "Checking for a system-assigned managed identity..."
systemUserId=$(az functionapp identity show --name $appName --resource-group $rgName \
    --query "principalId" -o tsv)

if [[ -n "$systemUserId" ]]; then
    echo "System-assigned identity principal ID: $systemUserId"
    echo "Checking for role assignments..."
    az role assignment list --assignee $systemUserId --all
else
    echo "No system-assigned identity found."
fi

echo "Checking for user-assigned managed identities..."
userIdentities=$(az functionapp identity show --name $appName --resource-group $rgName \
    --query 'userAssignedIdentities' -o json)

if [[ "$userIdentities" != "{}" && "$userIdentities" != "null" ]]; then
    echo "$userIdentities" | jq -c 'to_entries[]' | while read -r identity; do
        echo "User-assigned identity: $(echo "$identity" | jq -r '.key' | sed 's|.*/userAssignedIdentities/||')"
        echo "Checking for role assignments..."
        az role assignment list --assignee $(echo "$identity" | jq -r '.value.principalId') --all --output json
        echo
    done
else
    echo "No user-assigned identities found."
fi
```

### 3d. Check Built-in Authentication

```bash
az webapp auth show --name $appName --resource-group $rgName
```

### 3e. Review Inbound Access Restrictions

```bash
az functionapp config access-restriction show --name $appName --resource-group $rgName
```

### 3f. Get Deployment Package (if needed)

Ideally your project files are in source control and you can redeploy from there. If not:

#### Check WEBSITE_RUN_FROM_PACKAGE

```bash
az functionapp config appsettings list --name $appName --resource-group $rgName \
    --query "[?name=='WEBSITE_RUN_FROM_PACKAGE'].value" -o tsv
```

If this returns a URL, download the package from that remote location.

#### Download from scm-releases blob container

Linux Consumption apps store deployment packages in the `scm-releases` blob container (in `squashfs` format).

```bash
appName=<APP_NAME>
rgName=<RESOURCE_GROUP>

echo "Getting the storage account connection string..."
storageConnection=$(az functionapp config appsettings list --name $appName --resource-group $rgName \
    --query "[?name=='AzureWebJobsStorage'].value" -o tsv)

echo "Getting the package name..."
packageName=$(az storage blob list --connection-string $storageConnection --container-name scm-releases \
    --query "[0].name" -o tsv)

echo "Downloading package: $packageName"
az storage blob download --connection-string $storageConnection --container-name scm-releases \
    --name $packageName --file $packageName
```

> 💡 If your storage account is restricted to managed identity access only, you may need to grant your Azure account the `Storage Blob Data Reader` role.

---

## Step 4: Create the Flex Consumption App

```bash
# Automated migration — creates new app and migrates most configurations
az functionapp flex-migration start \
    --source-name <SOURCE_APP_NAME> \
    --source-resource-group <SOURCE_RESOURCE_GROUP> \
    --name <NEW_APP_NAME> \
    --resource-group <RESOURCE_GROUP>
```

**Optional flags**:
- `--storage-account <ACCOUNT>` — use a different storage account
- `--maximum-instance-count <COUNT>` — set max scale-out instances
- `--skip-access-restrictions` — skip migrating IP access restrictions
- `--skip-cors` — skip migrating CORS settings
- `--skip-hostnames` — skip migrating custom domains
- `--skip-managed-identities` — skip migrating managed identity configurations
- `--skip-storage-mount` — skip migrating storage mount configurations

The command automatically:
- Assesses your source app for Flex Consumption compatibility
- Creates a new function app in the Flex Consumption plan
- Migrates app settings, identity assignments, storage mounts, CORS, custom domains, and access restrictions

### Verify Migration Results

```bash
# Verify new app exists and is configured
az functionapp show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --query "{name:name, kind:kind, sku:properties.sku}" --output table

# Review migrated app settings
az functionapp config appsettings list --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --output table

# Check managed identity
az functionapp identity show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP>

# Check custom domains
az functionapp config hostname list --webapp-name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --output table
```

### Configure Items Not Auto-Migrated

The `flex-migration start` command handles most settings, but these may need manual configuration:

#### Built-in Authentication

```bash
# Recreate auth settings if your original app used Easy Auth
az webapp auth update --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --enabled true --action <AUTH_ACTION>
```

#### Scale and Concurrency (if custom values needed)

```bash
# Set maximum scale-out (default: 100, range: 1-1000)
az functionapp scale config set --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --maximum-instance-count <MAX_SCALE_SETTING>
```

> ⚠️ Reducing below 40 for HTTP apps can cause frequent request failures.

---

## Step 5: Deploy Code

> ⚠️ **Code is NOT automatically migrated.** The new app is created with config only — you must deploy code separately.

### ask_user: Choose Deployment Method

Present these options to the user:

> Your new Flex Consumption app `<NEW_APP_NAME>` has been created and configured. Now we need to deploy your function code. How would you like to proceed?
>
> 1. **Update CI/CD pipeline** — I'll help you update your Azure Pipelines or GitHub Actions workflow to target the new app
> 2. **Deploy from local project** — I'll run `func azure functionapp publish <NEW_APP_NAME>` from your project directory  
> 3. **Deploy existing package** — I'll deploy the package we downloaded earlier from the original app

---

### Option A: Update CI/CD Pipeline (if user selects option 1)

Update your existing pipeline (Azure Pipelines or GitHub Actions) to target the new app name.

- [Build and deploy with Azure Pipelines](https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-azure-devops)
- [Build and deploy with GitHub Actions](https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-github-actions)

### Option B: Deploy from Local Project (if user selects option 2)

```bash
# From your project directory
func azure functionapp publish <NEW_APP_NAME>
```

### Option C: Deploy Existing Package (if user selects option 3)

```bash
# Deploy the zip package downloaded in Step 3
az functionapp deployment source config-zip --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --src <PACKAGE_PATH.zip>
```

### After Successful Deployment

Inform the user:

> Code deployed! Next steps to consider:
>
> - The original app is still running — keep it as rollback for a few days
> - Update any clients/pipelines to point to the new URL
> - Enable HTTPS-only and managed identity on the new app for better security
> - When confident, you can delete the original app

---

## Step 6: Post-Upgrade Validation

### Smoke Test (run this first)

```bash
# Minimum viability check — confirm the app is reachable at all
DEFAULT_HOST=$(az functionapp show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> \
    --query "defaultHostName" -o tsv)

HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://$DEFAULT_HOST")
echo "App responded with HTTP $HTTP_STATUS"

# Expected: 2xx or 401/404 (means the host is up). 
# If 503 or connection refused → the app failed to start. Check logs:
#   az functionapp log tail --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP>
```

### Verify Plan

```bash
az functionapp show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --query "serverFarmId"
```

### Test HTTP Endpoints

```bash
# Test an HTTP trigger function
curl -s -o /dev/null -w "%{http_code}" "https://$DEFAULT_HOST/api/<FUNCTION_NAME>"
```

### Performance Benchmarks (Application Insights KQL)

```kql
requests
| where timestamp > ago(1d)
| summarize percentiles(duration, 50, 95, 99) by bin(timestamp, 1h)
| render timechart
```

### Check for Errors

```kql
traces
| where severityLevel == 3
| where cloud_RoleName == "<NEW_APP_NAME>"
| where timestamp > ago(1d)
| project timestamp, message, operation_Name, customDimensions
| order by timestamp desc
```

---

## Step 7: Cleanup (Optional)

```bash
# ⛔ REQUIRES ask_user confirmation before executing

# Delete the original function app
az functionapp delete --name <ORIGINAL_APP_NAME> --resource-group <RESOURCE_GROUP>
```

> 💡 No rush. The Consumption plan only charges for actual usage, so keeping the old app (with triggers disabled) costs very little. We recommend keeping it for a few days/weeks.

---

## Rollback

```bash
# Restart the original app if it was stopped
az functionapp start --name <ORIGINAL_APP_NAME> --resource-group <RESOURCE_GROUP>

# Optionally delete the new Flex Consumption app
az functionapp delete --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP>
```

```