Two services, one outcome
If all you need is to put a folder of HTML, CSS and JavaScript on the internet behind a custom domain and a TLS certificate, Azure will do that in at least two ways. You can enable the static website feature on a storage account and point a CDN or Azure Front Door at it, or you can create an Azure Static Web Apps resource and let it own the whole arrangement.
Teams frequently choose between them on the basis of price, which is the least interesting difference. The useful question is how much of the surrounding arrangement — routing, redirects, response headers, deployment, preview environments, certificates — you want to assemble yourself.
What Static Web Apps adds
Static Web Apps is best understood as a bundle. The file serving is the least of it. What you are actually buying is a set of conventions that you would otherwise have to build:
- A deployment pipeline. Connecting a repository generates a workflow that builds and publishes on every push to the tracked branch.
- Preview environments. Each pull request gets its own URL, created and destroyed automatically. This changes review behaviour more than any other single feature.
- A configuration file that owns routing, fallback behaviour, response headers, MIME types and custom error pages, versioned with the site.
- Managed certificates for custom domains, issued and renewed without intervention.
- An optional API backed by Azure Functions, served from the same origin, which removes cross-origin configuration for the one or two endpoints a brochure site typically needs.
None of these are things you cannot build on a storage account. All of them are things you would have to remember to build, document and maintain.
Note
Feature availability and limits differ between the free and standard tiers, and both have changed more than once. Check the current Microsoft documentation for your region before committing to a tier — do not rely on any article, including this one, for current limits.
Routing and configuration
The configuration file sits at the root of the deployed output and is called
staticwebapp.config.json. It is worth understanding early, because it is
where most of the behaviour that people expect a web server to provide actually lives.
staticwebapp.config.json
{
"navigationFallback": {
"rewrite": "/404.html",
"exclude": ["/assets/*", "/css/*", "/js/*", "/config/*", "/content/*"]
},
"responseOverrides": {
"404": { "rewrite": "/404.html", "statusCode": 404 }
},
"globalHeaders": {
"X-Content-Type-Options": "nosniff",
"Referrer-Policy": "strict-origin-when-cross-origin",
"Content-Security-Policy": "default-src 'self'; img-src 'self' data:; object-src 'none'"
},
"mimeTypes": {
".json": "application/json",
".svg": "image/svg+xml"
}
}
Navigation fallback is not a 404 handler
This is the single most common source of confusion. navigationFallback
exists for single-page applications: it serves a given file for any request that does
not match a physical file, with a 200 status. If you point it at
/index.html on a multi-page site, every mistyped URL returns your
homepage with a success status, and search engines will index the resulting mess.
For a multi-page static site, either exclude your asset paths and fall back to a real
404 document, or set responseOverrides so that the status code is honest.
Both are shown above.
Headers are global, and that is a limitation
globalHeaders applies to every response. There is a per-route
headers block, but route matching is simpler than a full web server's,
so a policy that varies substantially by path is awkward to express. If you need
fine-grained header control, that is an argument for putting Front Door in front.
Custom domains and certificates
Static Web Apps will issue and renew a certificate for a custom domain once the domain validates. The apex domain is the part that catches people out: an apex record cannot be a CNAME, so validation uses either an ALIAS-style record from a provider that supports one, or Azure DNS with an alias record.
Plan the DNS before the launch date rather than during it. Propagation and validation are usually quick, but they are not instant, and a launch that waits on DNS is a launch that has already gone wrong.
When a storage account is enough
A storage account with static website hosting enabled, fronted by a CDN profile, is still a completely reasonable choice. It suits you if:
- you already run a mature deployment pipeline and do not want a second one;
- you need header or caching behaviour that is easier to express at the CDN;
- the site is one origin among several behind a single Front Door instance;
- your organisation's landing zone standards constrain which resources you may create, which is common in regulated environments.
What you give up is preview environments, managed certificates on the origin, and the configuration file. You will end up re-implementing the parts you need, which is fine if you were going to do that anyway.
Choosing between them
| Consideration | Static Web Apps | Storage account + CDN |
|---|---|---|
| Deployment | Generated pipeline, opinionated | Whatever you already have |
| Preview environments | Per pull request, automatic | Build it yourself |
| Routing and headers | Config file in the repository | CDN or Front Door rules engine |
| Certificates | Managed | Managed at the CDN layer |
| Serverless API | Integrated, same origin | Separate Function App and CORS |
| Governance fit | One more resource type to approve | Usually already approved |
Our default for a corporate website is Static Web Apps, because preview environments genuinely improve review quality and the configuration file keeps routing decisions in version control where they can be reviewed. Our default for a site that must sit behind an existing Front Door instance alongside other origins is the storage account, because consistency at the edge is worth more than convenience at the origin.
Watch out
Whichever you choose, do not put configuration containing secrets into the deployed output. Everything published to a static host is public, including any JSON file you only meant your own JavaScript to read. Configuration in the browser is configuration in the newspaper.
Where to start
Deploy something trivial first — a single page and a stylesheet — and take it all the way through to a custom domain and a working 404. The interesting problems are all in that path, and they are considerably cheaper to meet with a two-file site than with a completed one.