Fix Azure Static Web Apps: Deployment & Config Issues

Microsoft Fix Intermediate 14 min read Official Docs Grounded Updated April 20, 2026

Why This Is Happening

I've spent years watching developers , sharp, experienced people , hit a wall with Azure Static Web Apps and assume they did something wrong. They didn't. Azure Static Web Apps has a genuinely clever architecture, but it also has a handful of sharp edges that bite almost everyone the first time (and often the second). The error messages it throws are frequently vague, the GitHub Actions workflow output can be cryptic, and the gap between "it works locally" and "it works on Azure" is wider than you'd expect.

Here's the core thing to understand: Azure Static Web Apps separates your static front-end assets, your HTML, CSS, JavaScript, images, from your API layer entirely. Your static files get distributed globally across Azure's CDN points of presence, and your API endpoints run on a serverless Azure Functions backend. That's a fundamentally different model from deploying to a traditional VM or App Service, and a lot of common fixes people know from those environments just don't apply here.

The most frequent issues I see fall into a few buckets. First, build failures in the GitHub Actions or Azure DevOps pipeline, usually because the app_location, api_location, or output_location values in your workflow YAML don't match your actual project structure. Second, API calls returning 404 or CORS errors even though the endpoint exists, almost always a routing misconfiguration or a misunderstanding of how the managed Functions integration works. Third, custom domain and SSL issues where the DNS hasn't fully propagated or the certificate renewal hit a snag. Fourth, confusion around the Free vs. Standard plan limits, the 250 MB app size cap on the Free plan catches people off guard when their production build grows unexpectedly.

Who sees these problems most? Frontend developers deploying a React app to Azure Static Web Apps for the first time, teams migrating from Netlify or Vercel who expect identical behavior, and enterprise shops trying to bolt on private endpoints or custom authentication providers, both of which require the Standard plan, not Free.

What makes this especially frustrating is that Azure's error messages don't tell you which of these buckets you're in. A build failure log might say "Error: ENOENT" without naming the directory it couldn't find. A 404 on your API route doesn't distinguish between a missing function, a misconfigured route, and a plan-tier limitation. I know that ambiguity is maddening when you have a deadline.

The good news: every one of these issues has a concrete fix. Browse all Microsoft fix guides →

The Quick Fix, Try This First

If your Azure Static Web Apps deployment just failed and you need it running now, start here. Seventy percent of the deployment issues I've seen come from one root cause: the workflow YAML file generated by Azure doesn't match your actual project's output directory.

Open your repository and navigate to .github/workflows/. You'll find a YAML file that looks something like azure-static-web-apps-[random-name].yml. Open it and look for this block:

- name: Build And Deploy
  uses: Azure/static-web-apps-deploy@v1
  with:
    azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
    repo_token: ${{ secrets.GITHUB_TOKEN }}
    action: "upload"
    app_location: "/"
    api_location: "api"
    output_location: "dist"

The three values you need to verify against your actual project:

  • app_location, the folder containing your source code. For a Vite project scaffolded with npm create vite@latest, this is typically /. For a monorepo, it might be /frontend or /client.
  • api_location, the folder containing your Azure Functions API code. If you have no API, set this to an empty string: "". Leaving it as api when no such folder exists will cause your build to fail every time.
  • output_location, the build output folder relative to app_location. Vite outputs to dist. Create React App outputs to build. Angular outputs to dist/[project-name]. Get this wrong and your deployment will succeed but serve a blank page.

Fix those three values, commit the change, and push. Watch the Actions tab in GitHub, a fresh run will trigger automatically. If it goes green and your site loads, you're done.

Pro Tip
Before you touch anything in Azure, run your build locally first: npm run build and then check exactly which folder gets created. Whatever folder name appears, dist, build, out, public, that's your output_location. Azure will never guess it for you, and the default value in the generated YAML is frequently wrong for non-standard frameworks.
1
Verify Your Azure Static Web Apps Resource and API Token

Before debugging your code, confirm the Azure side is healthy. I've seen developers spend hours on their YAML when the real problem was a deleted or expired deployment token.

Sign into the Azure Portal. In the search bar at the top, type Static Web Apps and select it from the results. You should see your app listed. Click it to open the resource overview.

On the left sidebar, under Settings, click Deployment tokens. You'll see your current token. Here's the thing: if someone on your team regenerated this token and didn't update the GitHub secret, every deployment will fail with an authentication error. Copy the token value.

Now go to your GitHub repository. Click SettingsSecrets and variablesActions. Find the secret named AZURE_STATIC_WEB_APPS_API_TOKEN (the exact name referenced in your workflow YAML). Click Update and paste the token from the Azure Portal.

Back in the Azure Portal, also check your app's Overview tab. Look at the URL field, it should show a live URL ending in .azurestaticapps.net. If the resource shows as unhealthy or the URL field is blank, the resource itself may need to be recreated. Also check the Source field, it should point to your correct GitHub repo and branch. If it's pointing to the wrong branch, that's why your pushes to main aren't triggering deployments.

If everything looks correct here, trigger a manual re-run of the last failed workflow in GitHub Actions by clicking Re-run all jobs. Watch the output in real time. If it passes now, a stale token was your issue.

2
Fix the GitHub Actions Build Configuration

Your workflow YAML is the single most important configuration file for Azure Static Web Apps deployments, and it's also the one Azure generates with the most assumptions baked in. Let's make sure every field is right.

Open .github/workflows/azure-static-web-apps-[name].yml in your editor. The full build step should look something like this for a standard Vite + React project:

- name: Build And Deploy
  id: builddeploy
  uses: Azure/static-web-apps-deploy@v1
  with:
    azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
    repo_token: ${{ secrets.GITHUB_TOKEN }}
    action: "upload"
    app_location: "/"
    api_location: ""
    output_location: "dist"
    app_build_command: "npm run build"

Key things to check beyond the three location fields:

  • Node.js version: Azure's build environment defaults to a Node version that may not match your local setup. Add an explicit version step before the build: uses: actions/setup-node@v3 with node-version: '20'. The official docs specify Node 20.0 or later as the requirement for the Azure CLI, and your app should match.
  • app_build_command: If your project uses a non-standard build script, say npm run build:prod, specify it explicitly here. Omitting it causes the action to fall back to a generic build attempt that may not produce the right output.
  • skip_app_build: If you're pre-building in an earlier CI step and just want to deploy the artifact, set this to true and point output_location at the folder containing the already-built files.

After saving your changes, commit and push. You should see the Actions run turn green within a few minutes. If it fails again, click into the failed step, the raw log output will show the exact npm or build error that needs addressing next.

3
Configure Routing Rules for Single-Page Applications

This is the most common issue people hit after a successful deployment: the site loads on the homepage, but any direct URL, like navigating to https://yourapp.azurestaticapps.net/dashboard, returns a 404. Azure Static Web Apps doesn't automatically know you're running a single-page app that handles routing client-side.

The fix is a staticwebapp.config.json file placed at the root of your output folder (or in your app source root, depending on your setup). Here's the essential routing rule for SPAs:

{
  "navigationFallback": {
    "rewrite": "/index.html",
    "exclude": ["/images/*.{png,jpg,gif}", "/css/*", "/js/*"]
  }
}

This tells Azure: if a request comes in for a path that doesn't correspond to a real file on disk, serve index.html instead and let the front-end router handle it. The exclude array prevents static assets from accidentally getting rewritten to index.html, make sure it covers all your asset file types.

You can also add response headers, custom error pages, and redirect rules in the same file. For example, to set a global security header:

{
  "globalHeaders": {
    "X-Frame-Options": "SAMEORIGIN",
    "X-Content-Type-Options": "nosniff"
  },
  "navigationFallback": {
    "rewrite": "/index.html"
  }
}

Commit this file, push, and wait for the deployment to complete. Then test a direct URL, you should land on your app instead of a 404 page. If you're still seeing 404s, double-check the file is being included in your build output folder, not left behind in the source directory.

4
Troubleshoot Azure Static Web Apps API Endpoints Not Responding

Your front end loaded fine, but your API calls are returning 404, 500, or hanging entirely. API issues with Azure Static Web Apps tend to fall into one of three scenarios, and the fix is different for each.

Scenario A: Managed Functions not deploying. If you're using the built-in managed Azure Functions, your api_location in the workflow YAML must point to a folder containing valid Azure Functions code. The folder needs a host.json at its root and at least one function subfolder. If this structure is missing or broken, the managed API simply won't deploy, and you'll get 404s on every /api/* route with no obvious error message.

Scenario B: Bringing your own Functions app. On the Standard plan, you can link an existing Azure Functions app instead of using the managed Functions. In the Azure Portal, go to your Static Web Apps resource → SettingsAPIs. Click Link and select your existing Functions app. Be aware: linking a Functions app is only available on the Standard plan. If you're on Free and trying to link an external app, it won't work, you need to upgrade first.

Scenario C: Route prefix mismatch. Azure Static Web Apps proxies all API calls through /api by default. If your front-end code is calling /functions/myEndpoint or /v1/myEndpoint, those calls will never reach your Functions. Make sure your front-end API calls use the /api/[function-name] pattern. You can verify the correct path by opening your Static Web App in the Azure Portal and looking under Functions in the left sidebar, each function listed shows its URL pattern.

# Correct API call format from your front end
fetch('/api/getUserData')
  .then(res => res.json())
  .then(data => console.log(data));

One more thing: Azure Static Web Apps handles CORS for API calls automatically when going through the built-in reverse proxy. If you're getting CORS errors, it likely means your front end is calling the API directly by full URL rather than through the relative /api path. Switch to relative paths and the CORS errors should disappear.

5
Set Up Custom Domains and Resolve SSL Certificate Errors

Custom domains are one of the most polished features of Azure Static Web Apps, free SSL certificates, automatically renewed, no configuration required on your end. But there are a few specific ways the setup can go sideways, and the portal's error messages aren't always clear about which one you're hitting.

First, understand the plan limits. On the Free plan, you get 2 custom domains per app. On the Standard plan, you get 5. If you're trying to add a third domain on the Free plan, the portal will reject it. The fix is to either remove an existing domain or upgrade to Standard.

To add a custom domain, go to your Static Web App in the Azure Portal → SettingsCustom domainsAdd. Enter your domain name and follow the DNS validation steps Azure provides. You'll need to add either a CNAME record (for subdomains like www.yourdomain.com) or a TXT record plus an ALIAS/ANAME record (for apex domains like yourdomain.com).

The most common sticking point is DNS propagation. Azure will show your domain as "Validating" for up to 48 hours while it waits for DNS changes to propagate globally. Don't panic if it stays in this state for a few hours. You can check propagation status using a tool like nslookup:

nslookup www.yourdomain.com
# Should return your Static Web Apps hostname, e.g.:
# [your-app-name].azurestaticapps.net

Once DNS resolves correctly, Azure automatically provisions the SSL certificate via its certificate authority. This usually completes within 10-15 minutes of successful validation. If the certificate shows as "Failed" after DNS is confirmed correct, try removing and re-adding the custom domain, this triggers a fresh certificate request. If it fails a second time, check that your DNS provider doesn't have CAA records that block Azure's certificate authority from issuing certificates for your domain.

Advanced Troubleshooting

You've worked through the standard steps and things still aren't right. Let's go deeper.

Diagnosing Build Failures with Detailed Logs

The default GitHub Actions log output truncates a lot. When a build fails, click the failing step in the Actions run view to expand it. Look for lines prefixed with [ORYX], that's the build system Azure uses under the hood. ORYX errors often reveal the real issue: a missing lock file, an incompatible package manager version, or a build script that exited with a non-zero code. If you see Error: ORYX build failed followed by a cryptic path error, 90% of the time ORYX can't find your package.json because app_location is set incorrectly.

Staging Environments and Pull Request Previews

Azure Static Web Apps generates a separate staging environment for every pull request automatically, this is one of the genuinely excellent features of the platform. On the Free plan you get 3 staging environments per app; Standard gives you 10. If your PR preview URLs are returning 404 or not generating at all, check that the workflow YAML has the pull_request trigger configured:

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches:
      - main

The closed event type is important, it's what triggers cleanup of the staging environment when the PR is merged or closed. Without it, staging environments pile up and you'll hit the plan limit.

Authentication Configuration Issues

Azure Static Web Apps includes built-in authentication with Microsoft Entra ID and GitHub as preconfigured providers. On the Free plan, you're limited to these preconfigured providers. If you need a custom identity provider, say, Auth0, Okta, or your own Azure AD B2C tenant, you must be on the Standard plan, which supports custom provider registrations.

Custom authentication is configured in staticwebapp.config.json under the auth key:

{
  "auth": {
    "identityProviders": {
      "customOpenIdConnectProviders": {
        "myProvider": {
          "registration": {
            "clientIdSettingName": "MY_CLIENT_ID",
            "clientCredential": {
              "clientSecretSettingName": "MY_CLIENT_SECRET"
            },
            "openIdConnectConfiguration": {
              "wellKnownOpenIdConfiguration": "https://yourprovider.com/.well-known/openid-configuration"
            }
          }
        }
      }
    }
  }
}

The client ID and secret values are referenced by name, not value, you store the actual secrets in your Static Web App's Application settings in the Azure Portal. If authentication isn't working, first verify those application settings are present and correctly named.

Private Endpoints and Enterprise Network Scenarios

Private endpoints for Azure Static Web Apps are a Standard plan feature only. If your organization requires that the app not be publicly accessible on the internet, common in financial or healthcare enterprise scenarios, you'll need Standard plus an Azure Virtual Network. This is a significant infrastructure change and involves configuring Azure Private DNS zones alongside the private endpoint. If you're in a domain-joined or fully managed enterprise environment, your network team will need to be involved.

When to Call Microsoft Support
If your deployment token is valid, your YAML is correct, DNS has propagated, and your app still won't deploy or serve correctly after 24 hours, it's time to escalate. Particularly if you're seeing errors in the Azure Portal like "Internal server error" on the resource overview, or your SSL certificate is stuck in "Failed" state after multiple re-attempts, these indicate platform-side issues that only Microsoft can resolve. Open a support ticket at Microsoft Support, include your resource ID (visible in the portal under Properties), the GitHub Actions run ID, and the exact error text. Note that the Free plan does not include formal customer support with an SLA; if you need guaranteed response times, you'll need the Standard plan or an Azure support contract.

Checking Quota and Size Limits

The Free plan caps your app at 250 MB total file size. The Standard plan raises this to 500 MB. If your production build exceeds the limit, deployments will fail with a quota error. Run du -sh dist/ (or dir /s dist on Windows) after building locally to check your output size. Common culprits are large image assets, unminified JavaScript bundles, or accidentally including node_modules in your build output. If you genuinely need more than 500 MB, you'll need to offload large assets to Azure Blob Storage or a CDN and reference them by URL.

Prevention & Best Practices

Once you've fixed the immediate problem, here's how to set up Azure Static Web Apps deployments so they stay healthy, and so the next developer on your team doesn't hit the same walls.

Lock your Node version explicitly. Specify the exact Node.js version in your workflow YAML with a setup-node step. Azure's build environment will update its defaults over time, and a silent Node version change has broken more than a few production deployments. The official docs require Node 20.0 or later for Azure CLI work, but pin your app's runtime to whatever version you've tested against.

Test your staticwebapp.config.json locally. The Azure Static Web Apps CLI (@azure/static-web-apps-cli) lets you run a local emulator that mirrors the Azure routing behavior including authentication, API proxying, and navigation fallback rules. Install it globally with npm install -g @azure/static-web-apps-cli and run swa start from your project root. Catching routing misconfigurations locally is vastly faster than pushing and waiting for a deployment.

Use staging environments for every change. The PR preview feature isn't just a convenience, it's a safety net. Make it a team policy that nothing goes to the watched production branch without first being reviewed in a staging environment. On the Standard plan, you have 10 staging slots available, which is more than enough for a typical team's PR volume. Free plan users get 3, which works fine for smaller teams.

Monitor your app size over time. As your Azure Static Web Apps project grows, build size tends to creep up quietly. Add a size check step to your workflow that fails the build if the output exceeds a threshold you define, something like 200 MB for a Free plan app gives you a warning buffer before you hit the 250 MB hard limit. Catching this early is far better than having a deployment fail at 3 AM.

Document your authentication provider setup. Custom authentication configurations in staticwebapp.config.json reference application setting names, not actual secrets. If a new team member deploys the app to a new Static Web Apps resource and doesn't know to populate those application settings, auth will silently fail. Keep a checklist in your project README of every application setting that needs to be configured after provisioning.

Quick Wins

Frequently Asked Questions

What is Azure Static Web Apps and how is it different from Azure App Service?

Azure Static Web Apps is designed specifically for front-end applications, things built with React, Vue, Angular, Svelte, or static site generators like Gatsby and Hugo. It serves your HTML, CSS, JavaScript, and image assets from a globally distributed CDN, with optional serverless API endpoints powered by Azure Functions. Azure App Service, by contrast, is a general-purpose web hosting platform that runs a persistent server, it's built for dynamic server-rendered apps, full-stack frameworks with server components, or anything that needs server-side processing on every request. If your app is mostly static with a lightweight API, Azure Static Web Apps will be faster, cheaper (the Free tier is actually free), and simpler to manage. If you need persistent server-side logic, App Service is the right tool.

How do I build my first Azure Static Web App and deploy it to production?

The quickest path is to scaffold a project with npm create vite@latest your-app-name -- --template=vanilla, then install dependencies with npm install and verify it runs locally with npm run dev. Once that's working, sign into the Azure CLI with az login, then use the Azure Portal or CLI to create a new Static Web Apps resource and connect it to your GitHub repository. Azure will generate the GitHub Actions workflow YAML automatically. Push a commit to your watched branch and the first deployment will kick off. Within a few minutes you'll have a live URL ending in .azurestaticapps.net. From there, you can add a custom domain, configure routing rules, and set up your API layer.

What's the difference between the Free and Standard Azure Static Web Apps plans?

The main differences that matter day-to-day: the Free plan caps your app at 250 MB and allows only 2 custom domains and 3 staging environments; the Standard plan raises those to 500 MB, 5 custom domains, and 10 staging environments. More critically, the Free plan only supports preconfigured authentication providers (Microsoft Entra ID and GitHub) and doesn't support private endpoints or custom role assignment via functions. The Standard plan unlocks custom authentication provider registrations, private endpoints, and a formal SLA. There's no SLA on the Free plan at all, which makes it unsuitable for anything customer-facing in production. The Dedicated plan was officially retired effective October 31, 2025, so new deployments should target Free or Standard.

Why is my Azure Static Web Apps API returning a 404 even though my function exists?

The most common cause is a path mismatch. Azure Static Web Apps proxies API calls through the /api prefix, so a function named getUserData is accessible at /api/getUserData, not at any other path. If your front-end code is calling a different base URL or path structure, the request never reaches your function. Check your api_location value in the workflow YAML to confirm it points to a valid folder containing a host.json and your function code. Also verify your function deployed successfully by opening the Static Web App in the Azure Portal and clicking Functions in the left sidebar, if your function doesn't appear there, it didn't deploy, and no amount of path-tweaking in the front end will help.

How do I add a custom domain to my Azure Static Web App and make HTTPS work?

In the Azure Portal, open your Static Web Apps resource, go to Settings → Custom domains, and click Add. Enter your domain name and Azure will show you the DNS records to add at your registrar or DNS provider. For subdomains like www, you add a CNAME pointing to your .azurestaticapps.net URL. For apex domains (without www), you need to add a TXT record for validation and an ALIAS or ANAME record pointing to your app URL, not all DNS providers support ALIAS/ANAME records, so check yours first. Once DNS propagates (can take a few hours to 48 hours), Azure automatically provisions and renews your SSL certificate at no cost. You don't need to upload or manage any certificate files yourself.

Can I deploy a Next.js or Nuxt.js app to Azure Static Web Apps?

Yes, but with an important distinction between modes. For Next.js, the standard deployment path is the "Static HTML Export" mode, you configure output: 'export' in your next.config.js, which produces a fully static build that Azure Static Web Apps can serve normally. There is also a "Hybrid Next.js" deployment option that supports server-side rendering and API routes, but as of the official docs this is in preview and has known limitations. Nuxt.js follows a similar pattern, static generation works reliably, while server-side rendering requires more careful configuration. If you're using server components or SSR heavily, evaluate whether Azure App Service or Azure Container Apps might be a better fit for your architecture before committing to Static Web Apps.

Related Microsoft Fix Guides

H
Sai Kiran Pandrala
Our team includes certified Microsoft engineers, Azure architects, and system administrators with 10+ years of enterprise IT experience. Every guide is written from hands-on troubleshooting, not guesswork. We test every fix before publishing.