If you host on Azure Static Web Apps, HSTS looks deceptively simple. You want one header:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Done, right?

Not quite.

Azure Static Web Apps is great for shipping frontend apps fast, but once you care about security headers, especially HSTS, you run into a design constraint: you do not get full control over the edge like you would with a custom reverse proxy, Nginx, or a tuned CDN setup.

So the real question is not “should I use HSTS?” For any production HTTPS site, yes, you probably should. The real question is: what is the least painful way to enforce HSTS on Azure Static Web Apps, and what tradeoffs come with each option?

Quick refresher: what HSTS actually does

HSTS tells browsers: “for this domain, always use HTTPS for a period of time.”

Example:

Strict-Transport-Security: max-age=31536000; includeSubDomains

That means:

  • max-age=31536000: remember this rule for 1 year
  • includeSubDomains: apply it to subdomains too
  • preload: ask browsers to hardcode your domain into preload lists

HSTS protects against protocol downgrade and cookie leakage over HTTP. It is one of those headers that gives solid security value with almost no runtime cost.

The catch is that HSTS is sticky. If you set it wrong, browsers keep enforcing it until max-age expires. If you add includeSubDomains and one forgotten subdomain does not support HTTPS, you just created a problem for yourself.

The Azure Static Web Apps reality

For Azure Static Web Apps, your practical HSTS options usually fall into three buckets:

  1. Set HSTS directly in staticwebapp.config.json
  2. Put Azure Front Door in front and manage HSTS there
  3. Use another reverse proxy or CDN layer in front of Static Web Apps

If your goal is “simple, native, and good enough,” option 1 is where I would start.

Option 1: HSTS in staticwebapp.config.json

Azure Static Web Apps supports custom response headers in route rules. That gives you a native way to return Strict-Transport-Security without adding extra infrastructure.

Example:

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
  }
}

Or with routes:

{
  "routes": [
    {
      "route": "/*",
      "headers": {
        "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
      }
    }
  ]
}

If you can use globalHeaders, I prefer that. Less room for mistakes.

Official docs for config behavior live here:

Pros

  • Native to Azure Static Web Apps
  • No extra cost
  • No extra hop or infrastructure
  • Easy to version in Git
  • Works well for straightforward frontend deployments

Cons

  • Header control is not as flexible as a dedicated edge layer
  • If you need more advanced traffic policies, this will feel limiting
  • Rollback still has HSTS’s normal browser caching problem
  • You need to be careful with environment differences, especially preview environments and custom domains

When I would choose this

I would use this for most small to medium sites on Azure Static Web Apps, especially if:

  • you have one production custom domain
  • all subdomains are already HTTPS-only, or you are not using includeSubDomains
  • you do not need complex edge logic

Safe rollout advice

Do not jump straight to a preload-style policy unless you are absolutely sure.

Start with something conservative:

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=300"
  }
}

Then move to:

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=86400"
  }
}

Then:

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
  }
}

And only consider preload if you actually meet preload requirements and want that level of commitment.

Option 2: Put Azure Front Door in front

If you want stronger edge control, Azure Front Door is the cleanest Azure-native upgrade path. Static Web Apps stays as the origin, and Front Door becomes the public entry point.

That lets you centralize headers, redirects, WAF policy, caching behavior, and custom domain handling.

Official docs:

Pros

  • Much better control at the edge
  • Easier to standardize headers across multiple apps
  • Pairs nicely with WAF and redirect policy
  • Good fit for organizations already using Front Door
  • Lets you keep security policy separate from app code

Cons

  • More cost
  • More moving parts
  • More configuration overhead
  • More places to misconfigure hostnames, TLS, and caching
  • Can be overkill for a simple marketing site or SPA

When I would choose this

I would pick Front Door when:

  • multiple apps need the same security header policy
  • the site is business-critical
  • you already need WAF, custom routing, bot mitigation, or advanced caching
  • your platform team wants centralized control instead of per-repo config

My opinionated take

If your team already knows Azure networking, Front Door is a solid answer. If not, adding it solely for HSTS is usually too much ceremony. I have seen teams spend way more time debugging edge behavior than the header was worth.

Option 3: Another proxy/CDN in front

You can also place another reverse proxy or CDN in front of Azure Static Web Apps and inject HSTS there. This could be useful if your company already standardizes on a specific edge provider.

Pros

  • Potentially the most flexible option
  • Can unify security policy across non-Azure workloads
  • Lets you add HSTS even if app platform controls are awkward

Cons

  • Extra cost and operational burden
  • More DNS and TLS complexity
  • Troubleshooting becomes less fun very quickly
  • You are now depending on two platforms for one website path

When I would choose this

Only when the edge layer already exists for other reasons. I would not introduce a new CDN or proxy just to set HSTS for one Static Web App.

Comparison table

Here is the practical breakdown:

Option Best for Pros Cons
staticwebapp.config.json Most single-app deployments Simple, cheap, Git-managed, native Limited edge features
Azure Front Door Enterprise or multi-app setups Centralized control, WAF, richer edge policy Cost, complexity
External proxy/CDN Existing standardized edge layer Maximum flexibility Operational overhead

My default recommendation:

  • Use staticwebapp.config.json first
  • Use Front Door when you already need edge features
  • Avoid extra proxy layers unless they already exist

What about preload?

A lot of developers see preload and think “more secure, so I should add it.”

Slow down.

A preload-ready header looks like this:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

That is a strong commitment. To safely use it, you need confidence that:

  • your apex domain always supports HTTPS
  • www always supports HTTPS if relevant
  • all subdomains support HTTPS because of includeSubDomains
  • you are not going to need an HTTP-only subdomain later

For many teams, includeSubDomains is already the risky part. preload raises the stakes.

My advice: if you manage a clean, tightly controlled domain portfolio, preload can be great. If your organization has random legacy subdomains from 2017 that nobody owns, do not touch it yet.

Conservative production setup

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=86400"
  }
}

Good for first rollout.

Strong production setup

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
  }
}

Good when you are confident all relevant subdomains are HTTPS-only.

Preload-oriented setup

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload"
  }
}

Use only when you have done the domain hygiene work.

How to verify HSTS is actually being sent

After deployment, check the response headers in your browser dev tools or with curl:

curl -I https://yourdomain.com

You should see:

Strict-Transport-Security: max-age=31536000; includeSubDomains

You can also run a quick scan with HeaderTest to confirm HSTS and other headers are present.

If you are using a proxy in front, verify the header on the public hostname, not the internal Azure hostname.

Common mistakes

Setting HSTS on a domain before HTTPS is fully ready

This is the classic self-own. Make sure certificates, redirects, and custom domain bindings are correct first.

Using includeSubDomains too early

If blog.example.com, old-api.example.com, or status.example.com is not HTTPS-clean, browsers will enforce HSTS there too.

Assuming preview environments should use the same policy

Be careful with non-production hostnames. HSTS on temporary or preview domains can create confusion during testing.

Forgetting that browsers cache HSTS

Removing the header does not instantly undo the policy for users who already received it.

My recommendation

For Azure Static Web Apps, the best default is:

  1. configure HSTS directly in staticwebapp.config.json
  2. start with a small max-age
  3. increase gradually
  4. add includeSubDomains only after checking your domain estate
  5. treat preload as a deliberate, high-confidence decision

If your app already sits behind Azure Front Door, then manage HSTS there and keep edge policy centralized. That is cleaner operationally.

But for most developer teams, native config wins. Fewer moving parts, fewer surprises, and one less “platform architecture” meeting nobody wanted.

If you want the smallest useful starting point, use this:

{
  "globalHeaders": {
    "Strict-Transport-Security": "max-age=300"
  }
}

Then verify, wait, and scale it up.

That is the right kind of boring security change.