Understanding Azure Static Web Apps Routing
Azure Static Web Apps provides globally distributed hosting for static frontends with integrated serverless API backends. Routing and API integration issues are the most frequently reported problems, often caused by misconfigured route rules, incorrect API paths, or missing navigation fallback settings. This guide covers every common routing and API issue with tested solutions.
Diagnostic Context
When encountering Azure Static Web Apps routing and API integration, the first step is understanding what changed. In most production environments, errors do not appear spontaneously. They are triggered by a change in configuration, code, traffic patterns, or the platform itself. Review your deployment history, recent configuration changes, and Azure Service Health notifications to identify potential triggers.
Azure maintains detailed activity logs for every resource operation. These logs capture who made a change, what was changed, when it happened, and from which IP address. Cross-reference the timeline of your error reports with the activity log entries to establish a causal relationship. Often, the fix is simply reverting the most recent change that correlates with the error onset.
If no recent changes are apparent, consider external factors. Azure platform updates, regional capacity changes, and dependent service modifications can all affect your resources. Check the Azure Status page and your subscription’s Service Health blade for any ongoing incidents or planned maintenance that coincides with your issue timeline.
Common Pitfalls to Avoid
When fixing Azure service errors under pressure, engineers sometimes make the situation worse by applying changes too broadly or too quickly. Here are critical pitfalls to avoid during your remediation process.
First, avoid making multiple changes simultaneously. If you change the firewall rules, the connection string, and the service tier all at once, you cannot determine which change actually resolved the issue. Apply one change at a time, verify the result, and document what worked. This disciplined approach builds reliable operational knowledge for your team.
Second, do not disable security controls to bypass errors. Opening all firewall rules, granting overly broad RBAC permissions, or disabling SSL enforcement might eliminate the error message, but it creates security vulnerabilities that are far more dangerous than the original issue. Always find the targeted fix that resolves the error while maintaining your security posture.
Third, test your fix in a non-production environment first when possible. Azure resource configurations can be exported as ARM or Bicep templates and deployed to a test resource group for validation. This extra step takes minutes but can prevent a failed fix from escalating the production incident.
Fourth, document the error message exactly as it appears, including correlation IDs, timestamps, and request IDs. If you need to open a support case with Microsoft, this information dramatically speeds up the investigation. Azure support engineers can use correlation IDs to trace the exact request through Microsoft’s internal logging systems.
The Configuration File
All routing configuration lives in staticwebapp.config.json, placed in the output folder of your app (or the root for frameworks without a build step).
Important: The older
routes.jsonfile is deprecated. If you have both files,staticwebapp.config.jsontakes precedence. Migrate tostaticwebapp.config.jsonto avoid unexpected behavior.
{
"routes": [],
"navigationFallback": {},
"responseOverrides": {},
"globalHeaders": {},
"mimeTypes": {},
"networking": {},
"platform": {},
"trailingSlash": "auto"
}
Route Matching Rules
Routes are evaluated in order — first match wins. Understanding the matching rules prevents most routing issues:
- Exact paths are matched first (e.g.,
/about) - Wildcard paths use
*at the end (e.g.,/admin/*) /calendar/*matches/calendar/januarybut NOT/calendar/calendar*matches both/calendarand/calendar/january- Route order matters — put more specific routes before wildcard routes
{
"routes": [
{
"route": "/admin/settings",
"allowedRoles": ["admin"]
},
{
"route": "/admin/*",
"allowedRoles": ["admin"]
},
{
"route": "/profile",
"allowedRoles": ["authenticated"]
},
{
"route": "/login",
"rewrite": "/.auth/login/github"
}
]
}
SPA Navigation Fallback
Single-page applications (React, Angular, Vue) need a navigation fallback so that client-side routes like /dashboard or /users/123 serve index.html instead of returning 404.
{
"navigationFallback": {
"rewrite": "/index.html",
"exclude": [
"/images/*.{png,jpg,gif,svg}",
"/css/*",
"/js/*",
"/api/*",
"*.{css,js,map,ico,txt,xml,json}"
]
}
}
Common Mistake: Missing Exclude Patterns
Without the exclude property, all requests — including API calls and static assets — are rewritten to index.html. This causes:
- API calls returning HTML instead of JSON
- CSS/JS files serving HTML content
- Images appearing broken
API Integration Issues
API Route Prefix
All API routes in Azure Static Web Apps are served under the /api prefix. This is mandatory and cannot be changed.
Frontend: https://myapp.azurestaticapps.net/
API: https://myapp.azurestaticapps.net/api/
// Frontend code — always use /api prefix
const response = await fetch('/api/products');
const products = await response.json();
// WRONG — this won't work
const response = await fetch('/products');
Linked API Backend
Azure Static Web Apps supports two API backend options:
| Option | Description | Limitations |
|---|---|---|
| Managed Functions | Azure Functions in /api folder |
HTTP triggers only, 45-second timeout |
| Linked backend | Existing App Service, Container App, or API Management | Must be in same region, Standard plan required |
# Link an existing Azure Functions app
az staticwebapp backends link \
--name myStaticApp \
--resource-group myRG \
--backend-resource-id /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/sites/myFuncApp \
--backend-region eastus2
# Verify linked backend
az staticwebapp backends show \
--name myStaticApp \
--resource-group myRG
45-Second API Timeout
Managed Functions (built-in API) have a 45-second request timeout. For longer operations:
- Use a linked backend with Azure Functions Premium plan
- Implement async patterns (return 202 Accepted with status URL)
- Break long operations into smaller chunks
No WebSocket Support
Azure Static Web Apps does not support WebSocket connections. For real-time features, use:
- Azure SignalR Service
- Azure Web PubSub
- Server-Sent Events (SSE) via a linked backend
Authentication and Authorization Routes
{
"routes": [
{
"route": "/login",
"rewrite": "/.auth/login/github"
},
{
"route": "/logout",
"redirect": "/.auth/logout"
},
{
"route": "/.auth/login/twitter",
"statusCode": 404
}
],
"responseOverrides": {
"401": {
"redirect": "/login",
"statusCode": 302
},
"403": {
"rewrite": "/unauthorized.html"
}
}
}
Role-Based Access
{
"routes": [
{
"route": "/admin/*",
"allowedRoles": ["admin"]
},
{
"route": "/members/*",
"allowedRoles": ["authenticated"]
}
]
}
Built-in roles:
anonymous— all users (default)authenticated— any logged-in user- Custom roles — assigned via invitation or custom auth
Maximum of 50 distinct roles per app.
Custom Domain and HTTPS Issues
# Add a custom domain
az staticwebapp hostname set \
--name myStaticApp \
--resource-group myRG \
--hostname www.example.com
# Check domain validation status
az staticwebapp hostname list \
--name myStaticApp \
--resource-group myRG \
--output table
DNS Configuration
| Domain Type | DNS Record | Value |
|---|---|---|
| Subdomain (www) | CNAME | myapp.azurestaticapps.net |
| Apex/root | ALIAS or ANAME | myapp.azurestaticapps.net |
| Validation | TXT | Provided by Azure |
Root Cause Analysis Framework
After applying the immediate fix, invest time in a structured root cause analysis. The Five Whys technique is a simple but effective method: start with the error symptom and ask “why” five times to drill down from the surface-level cause to the fundamental issue.
For example, considering Azure Static Web Apps routing and API integration: Why did the service fail? Because the connection timed out. Why did the connection timeout? Because the DNS lookup returned a stale record. Why was the DNS record stale? Because the TTL was set to 24 hours during a migration and never reduced. Why was it not reduced? Because there was no checklist for post-migration cleanup. Why was there no checklist? Because the migration process was ad hoc rather than documented.
This analysis reveals that the root cause is not a technical configuration issue but a process gap that allowed undocumented changes. The preventive action is creating a migration checklist and review process, not just fixing the DNS TTL. Without this depth of analysis, the team will continue to encounter similar issues from different undocumented changes.
Categorize your root causes into buckets: configuration errors, capacity limits, code defects, external dependencies, and process gaps. Track the distribution over time. If most of your incidents fall into the configuration error bucket, invest in infrastructure-as-code validation and policy enforcement. If they fall into capacity limits, improve your monitoring and forecasting. This data-driven approach focuses your improvement efforts where they will have the most impact.
Global Headers and CORS
{
"globalHeaders": {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Content-Security-Policy": "default-src 'self'; script-src 'self'",
"Cache-Control": "public, max-age=3600"
}
}
CORS for API Routes
CORS is automatically handled for managed APIs — the frontend domain is allowed by default. For linked backends, configure CORS on the backend service.
Custom MIME Types
{
"mimeTypes": {
".json": "application/json",
".wasm": "application/wasm",
".woff2": "font/woff2",
".webmanifest": "application/manifest+json"
}
}
Trailing Slash Configuration
{
"trailingSlash": "always"
}
| Setting | Behavior | SEO Impact |
|---|---|---|
auto (default) |
No redirection | Possible duplicate content |
always |
Redirects /about to /about/ |
Consistent URLs |
never |
Redirects /about/ to /about |
Consistent URLs |
Network Restrictions
{
"networking": {
"allowedIpRanges": [
"203.0.113.0/24",
"198.51.100.0/24",
"AzureFrontDoor.Backend"
]
}
}
Configuration File Limits
- Maximum config file size: 20 KB
- Maximum distinct roles: 50
- Maximum routes: No hard limit, but keep under 100 for maintainability
- API timeout (managed): 45 seconds
Debugging Routing Issues
Local Development with SWA CLI
# Install SWA CLI
npm install -g @azure/static-web-apps-cli
# Run locally with API
swa start ./build --api-location ./api
# Run with custom config
swa start ./build \
--api-location ./api \
--swa-config-location ./
Check Deployment Logs
# View deployment logs
az staticwebapp show \
--name myStaticApp \
--resource-group myRG \
--query "defaultHostname"
# Check build/deploy status in GitHub Actions
# Look for "Build And Deploy" step in the workflow run
Common Debugging Checklist
- Is
staticwebapp.config.jsonin the correct output folder? - Is
routes.jsonstill present? Remove it. - Are routes ordered correctly (specific before wildcard)?
- Does the navigation fallback exclude
/api/*? - Are API functions in the
/apifolder with correct folder structure? - Is the config file under 20 KB?
- Are there JSON syntax errors in the config?
# Validate JSON syntax
npx jsonlint staticwebapp.config.json
# Or with PowerShell
Get-Content staticwebapp.config.json | ConvertFrom-Json
Complete Configuration Example
{
"routes": [
{ "route": "/login", "rewrite": "/.auth/login/github" },
{ "route": "/logout", "redirect": "/.auth/logout" },
{ "route": "/admin/*", "allowedRoles": ["admin"] },
{ "route": "/api/*", "allowedRoles": ["authenticated"] },
{ "route": "/.auth/login/twitter", "statusCode": 404 }
],
"navigationFallback": {
"rewrite": "/index.html",
"exclude": ["/api/*", "/images/*", "*.{css,js,map,ico,json,svg,png,jpg}"]
},
"responseOverrides": {
"401": { "redirect": "/login", "statusCode": 302 },
"403": { "rewrite": "/403.html" },
"404": { "rewrite": "/404.html" }
},
"globalHeaders": {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "SAMEORIGIN"
},
"trailingSlash": "never",
"platform": {
"apiRuntime": "node:18"
}
}
Post-Resolution Validation and Hardening
After applying the fix, perform a structured validation to confirm the issue is fully resolved. Do not rely solely on the absence of error messages. Actively verify that the service is functioning correctly by running health checks, executing test transactions, and monitoring key metrics for at least 30 minutes after the change.
Validate from multiple perspectives. Check the Azure resource health status, run your application’s integration tests, verify that dependent services are receiving data correctly, and confirm that end users can complete their workflows. A fix that resolves the immediate error but breaks a downstream integration is not a complete resolution.
Implement defensive monitoring to detect if the issue recurs. Create an Azure Monitor alert rule that triggers on the specific error condition you just fixed. Set the alert to fire within minutes of recurrence so you can respond before the issue impacts users. Include the remediation steps in the alert’s action group notification so that any on-call engineer can apply the fix quickly.
Finally, conduct a brief post-incident review. Document the root cause, the fix applied, the time to detect, diagnose, and resolve the issue, and any preventive measures that should be implemented. Share this documentation with the broader engineering team through a blameless post-mortem process. This transparency transforms individual incidents into organizational learning that raises the entire team’s operational capability.
Consider adding the error scenario to your integration test suite. Automated tests that verify the service behaves correctly under the conditions that triggered the original error provide a safety net against regression. If a future change inadvertently reintroduces the problem, the test will catch it before it reaches production.
Summary
Azure Static Web Apps routing issues usually come down to three things: missing or misconfigured staticwebapp.config.json, incorrect route ordering (remember first match wins), and missing navigation fallback for SPAs. For API integration, ensure all API paths use the /api prefix, exclude /api/* from navigation fallback, and be aware of the 45-second timeout for managed Functions. Use the SWA CLI for local testing to catch routing issues before deployment.
For more details, refer to the official documentation: What is Azure Static Web Apps?, Configure Azure Static Web Apps.