Every guide tells you to set Strict-Transport-Security: max-age=31536000 and move on. That is the right destination, but arriving there on day one is how sites hurt themselves. The max-age value is the number of seconds a browser will refuse to speak plain HTTP to you after seeing the header — and it is a commitment you cannot recall. The sensible approach is a ramp: start with a value you could undo over a coffee break, and grow it as your confidence grows.
What max-age actually controls
When a browser receives your header over HTTPS, it records the policy and a countdown equal to max-age. For that many seconds, any http:// URL for your domain is upgraded to https:// internally, and an HTTPS failure becomes a hard error with no click-through. Two details make the value more consequential than it first appears.
First, the clock is a sliding window. Every time a returning visitor loads an HTTPS page and receives the header again, the countdown resets to the full max-age. Active users therefore stay pinned indefinitely; the value is not "how long until this expires for my audience" so much as "how long a visitor who never comes back stays locked in".
Second, there is no push channel. If you need to shorten or cancel the policy, the only way to reach a browser is for it to make a successful HTTPS request and receive a new, smaller max-age. You cannot broadcast a change to browsers that are not currently talking to you.
Why a long value is so hard to undo
Suppose you ship max-age=31536000 and, a week later, a subdomain's certificate expires or an HTTP-only host resurfaces. To back out, you would serve max-age=0. But that only clears the policy for visitors who (a) return and (b) successfully reach you over HTTPS to receive the zero. Anyone who does not come back keeps their original year counting down. Anyone whose broken host you were trying to rescue still cannot complete an HTTPS handshake, so they never receive the max-age=0 in the first place. A long max-age is, in effect, irreversible for the users it affects most. That asymmetry — cheap to set, expensive to unset — is the entire argument for ramping.
The ramp
Increase the value in stages, pausing at each step long enough for a full cycle of real traffic and a look at your error dashboards before proceeding.
max-age=300— five minutes. A live smoke test. If HTTPS is healthy across the site, nobody notices; if something is subtly broken, the blast radius expires almost immediately. You can effectively abandon the whole thing within minutes.max-age=86400— one day. Enough to expose problems that only appear under a full day of mixed traffic, cron jobs and third-party callbacks, while still being cheap to walk back.max-age=2592000— thirty days. Now you are making a real commitment. Only reach this once you are confident every host under the domain serves valid HTTPS — the moment to have resolved the includeSubDomains trap if you are extending the policy to subdomains.max-age=31536000— one year. The standard production value and the floor for preload eligibility. Some mature sites go further tomax-age=63072000(two years); beyond a year the practical difference is small, since the sliding window keeps active users pinned regardless.
At each step, verify the certificate and chain that browsers will be forced to rely on. TLS Studio confirms the live handshake and expiry, and SSL Studio checks the certificate's issuer and validity window — the things that turn into unbypassable errors once max-age is high.
Preload's one-year minimum
If your goal is the hstspreload.org list, the ramp is not optional and the endpoint is fixed. Preload requires max-age to be at least 31536000 — one year — alongside includeSubDomains and preload, with the apex redirecting HTTP to HTTPS. The one-year floor exists precisely because being on the list is a durable, hard-to-reverse commitment, and a short max-age would contradict that. Do not add the preload token until you have genuinely lived on a one-year max-age in production; that period is your last chance to catch a problem while max-age=0 can still rescue you, before the entry is baked into browsers and removal takes months.
Common mistakes with the value
A few errors show up repeatedly. The first is treating max-age as anything other than seconds — it is always seconds, so max-age=31536000 is a year and max-age=86400 is a day; there are no minute or day units to get wrong, only arithmetic. The second is skipping the ramp because the site "is definitely all HTTPS", then discovering a payment callback, an email-tracking pixel host, or a legacy admin panel that quietly was not. The third is setting a long value on a staging or throwaway environment that shares a parent domain with production, so includeSubDomains pins hosts you never meant to touch. And the fourth is forgetting the sliding window: because every HTTPS visit refreshes the countdown, you cannot "wait out" a policy on an active audience — the only lever you have is to serve a smaller value and hope enough browsers come back to receive it.
A sensible default
For a site that is already fully HTTPS and has been for a while, jumping straight to a year is defensible — the ramp mainly protects sites that are not as clean as they think. If you are unsure which camp you are in, that uncertainty is your answer: start at max-age=300, climb deliberately, and let a full year be the value you earn rather than the one you assume.