Skip to content
StackSiren

What is HSTS? (Strict-Transport-Security explained)

By StackSiren · Published

HTTP Strict Transport Security (HSTS) is a response header that tells supporting browsers to speak HTTPS only to your domain for the next max-age seconds — skipping cleartext http:// even if the user or a link asks for it. Add includeSubDomains and preload only when every subdomain you care about already serves HTTPS correctly.

HSTS does not encrypt anything by itself. TLS on the current connection does that. HSTS protects future visits from SSL-stripping and accidental http bookmarks after the browser has seen the header once over a trusted HTTPS response. Full header set: security headers guide. Host recipes: Vercel, Netlify.

What it does

MDN documents the header as:

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

After a browser receives that on an HTTPS response for https://yourapp.com:

  1. For max-age seconds it will upgrade http://yourapp.com/... navigations to HTTPS internally.
  2. It will refuse to proceed through some certificate errors on that host (details vary by browser) — which is why mis-set HSTS on a broken cert can lock users out until the age expires or they clear HSTS state.
  3. Subdomains are included only if you sent includeSubDomains.
  4. preload is a signal for inclusion in browser preload lists (see below); it is not magic on its own.

First visit over plain HTTP still has no HSTS protection — the browser has not seen the header yet. That is why preload lists exist for high-value domains.

Choosing max-age

max-age Typical use
0 Turn HSTS off (browser forgets after it sees this over HTTPS)
86400 (1 day) Careful rollout on a new domain
31536000 (1 year) Common steady state
63072000 (2 years) Often required by preload submission policies

Start short while you verify HTTPS on apex and www (and any app subdomains). Raise the value once curl and real browsers show a clean cert chain. Do not jump straight to two years + preload on a side project with random review apps on subdomains.

includeSubDomains and preload risks

includeSubDomains applies the policy to every subdomain of the host that sent the header. If https://yourapp.com sends it, then http://staging.yourapp.com will be upgraded too. If staging only listens on HTTP, or uses a broken cert, users and bots break. Inventory subdomains before enabling this flag.

preload means you intend to submit the domain to a browser preload list (for Chromium-based browsers, hstspreload.org is the usual entry point). Requirements change; historically they include HTTPS on the apex, www if it exists, a minimum max-age, includeSubDomains, and the preload token. Removal from the list is slow — measured in months for some browsers — so treat preload as hard to undo.

For most small SaaS and vibe-coded apps: HSTS with a 1–2 year max-age and includeSubDomains if all subdomains are ready is enough. Skip preload until you are sure.

Per host

Confirm what you already send:

curl -sI https://yourapp.com/ | grep -i strict-transport

Vercel

Vercel's encryption docs describe HSTS for *.vercel.app hostnames. Do not assume the same automatic policy for your custom domain — check with curl -I on the custom hostname. Set an explicit header in vercel.json or next.config.js when you want a known max-age on the apex you market to users. See add security headers on Vercel.

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Strict-Transport-Security",
          "value": "max-age=63072000; includeSubDomains"
        }
      ]
    }
  ]
}

Add ; preload only when you meet the preload list rules and intend to submit.

Netlify / Bolt exports

# _headers
/*
  Strict-Transport-Security: max-age=63072000; includeSubDomains

Or netlify.toml [[headers]] — same value. Details: Netlify security headers.

Lovable / managed builders

If the host does not document a headers UI, verify with curl. You may need a CDN or external host in front of the custom domain to set HSTS yourself (same approach as other headers on managed builders).

Rollout checklist

  1. HTTPS works on apex, www, and every subdomain you will cover.
  2. Ship HSTS with a modest max-age (1 day–1 week) and watch errors.
  3. Raise max-age; add includeSubDomains when ready.
  4. Consider preload only for long-lived production domains you control end-to-end.
  5. Keep HSTS beside CSP, frame-ancestors / X-Frame-Options, and nosniff — HSTS alone is not a full header pack. CSP walkthrough: CSP for React + Vite.

StackSiren's free first scan of a site you own flags missing security headers; the security headers checker is the focused tool for this cluster.

Clearing a bad policy

If you shipped an oversized max-age before a subdomain was ready:

  1. Fix HTTPS on every covered host (cert, redirect, mixed content).
  2. Redeploy with Strict-Transport-Security: max-age=0 (and the same includeSubDomains flag you used before, if any) over HTTPS so browsers expire the policy.
  3. Verify with a fresh browser profile or by clearing HSTS for the domain in browser settings (Chrome: chrome://net-internals/#hsts).
  4. Roll forward again with a short max-age, then raise it.

Preloaded domains cannot be fixed with max-age=0 alone — follow the preload list removal process. That asymmetry is why this post keeps recommending preload as optional for small apps.

How HSTS interacts with cookies and CSP

HSTS does not set Secure on cookies for you, but once browsers only use HTTPS, cookies without Secure are less likely to leak on the wire for that host. Still mark session cookies Secure; HttpOnly; SameSite=… explicitly.

CSP and HSTS solve different problems: CSP constrains what the page may load; HSTS constrains the scheme used to reach you. Ship both. A site with strong CSP and no HSTS can still be SSL-stripped on a first visit; a site with HSTS and no CSP still runs any script the page loads.

FAQ

Does HSTS replace needing a redirect from HTTP to HTTPS? No. Keep the redirect for clients that have never seen HSTS. HSTS protects repeat visitors and preload clients.

Can I set HSTS on an HTTP response? Browsers ignore HSTS over cleartext. Send it only on HTTPS responses.

What if I brick myself with preload? Fix HTTPS on all covered hosts first. Use max-age=0 over HTTPS to clear non-preloaded HSTS. Preload removal follows the list operator's process and is slow — another reason to delay preload.

*Is Vercel's .vercel.app HSTS enough for my marketing domain? Check the custom domain separately. Platform defaults on *.vercel.app do not automatically prove what www.yourproduct.com sends.

Does HSTS stop certificate phishing on a lookalike domain? No. It only affects hosts that have already sent the policy (or are preloaded). Lookalike domains are a different problem (monitoring, brand defenses).

Should every API subdomain send HSTS? If browsers call those hosts directly, yes once HTTPS is solid. Machine-only API clients ignore HSTS; browsers do not.

Check your app now

Free passive scan, results in under a minute.

Run a free scan

Fix guides for this topic

Platform checklists: Vercel · Bolt

Related posts

Sources