We chose 308 over 301, and the reason was POST
Ask anyone how to move a URL permanently and the answer is 301. It is the right answer for almost every case and it has one behaviour that is not widely known, is entirely legal, and quietly destroys form submissions.
| Code | Permanence | Method and body |
|---|---|---|
| 301 | Permanent | May be changed. In practice a POST becomes a GET. |
| 302 | Temporary | May be changed. Same in practice. |
| 307 | Temporary | Preserved. Guaranteed. |
| 308 | Permanent | Preserved. Guaranteed. |
The historical reason for the first two rows is that early clients did this, and the specification eventually described the behaviour rather than forbidding it. 307 and 308 were introduced precisely so that a redirect could be issued without that ambiguity.
What the method change actually does
A visitor submits a login form. The request is a POST carrying a username and a password. The server answers 301 pointing at the same path on another host.
The browser follows the redirect and issues a GET. The body is gone: no username, no password, nothing. The destination receives a plain request for the login page and does the only sensible thing, which is to render the login page.
From the user's side, they typed their credentials, pressed the button, and got the login form back. No error, no message, no indication that anything was discarded. They assume they mistyped the password, try again, and get the same result.
That is the failure mode worth remembering: not a broken page, a form that silently does nothing. It is close to undiagnosable from a support ticket, because everything in the logs looks like a user who cannot type their password.
Where we hit this
On 31 July 2026 we split this site across two hosts: the marketing pages on the apex, and the application behind app.. Twelve families of application paths that had previously answered on the apex needed to redirect to the new host.
Four of those families receive POST requests: /login, /register, /logout and the password reset paths. Anyone with a page already open on the apex, from a bookmark or a stale tab, would have submitted a form into that redirect. With 301, every one of those submissions would have arrived at the new host as an empty GET, and the person would have seen a login form with no explanation.
So the redirects are 308. The method and the body survive the hop, the form works from either host, and the transition is invisible to anyone who had a page open.
Two details made that safe to do in one step rather than in stages. The session cookie was already scoped to the parent domain, so a session established on one host is valid on the other and the redirected POST arrives authenticated. And after the change, every affected path was requested against both hosts and its code and destination recorded, rather than testing the two or three that were easy to reach by clicking.
The reverse direction, four marketing pages that had been duplicated under app., uses 301. Those are GET-only pages where the method question does not arise, and 301 is the more widely understood code.
The search engine question
The usual objection to 308 is that it might not consolidate ranking signals the way 301 does.
It does. Google's documentation lists 301 and 308 together as permanent redirects and describes them as equivalent for its purposes (Google Search Central, "Redirects and Google Search", consulted 1 August 2026). There is no ranking argument for preferring 301, only a familiarity argument.
The familiarity argument is not nothing. A 308 in an access log will make a colleague pause, and some older tooling reports it as an unrecognised code. That is worth a comment in the configuration file next to the rule, which is what we did, rather than a reason to pick the code that can eat a form submission.
When 301 is still the right choice
Three cases.
The path can only ever be a GET. A content page, a category, a retired article. No form posts there, so the method question is moot and 301 is the code everybody recognises.
You want the method to change. Rare and real: an endpoint that used to accept submissions and has been replaced by a page explaining where to go instead. Preserving the POST would send a body to something that cannot use it.
Very old clients. 308 postdates the original specification, and a client that does not recognise it is required not to follow it automatically. Browsers have understood it for a long time; embedded devices, payment terminals and old libraries in a client's back office may not. If the redirect is on a path that machines rather than people use, check what those machines are.
The rule that decides it in one question
Does anything ever POST to this path?
If yes, or if you are not certain, use 308. The cost of being wrong in that direction is a code somebody has to look up. The cost of being wrong in the other direction is form submissions vanishing without a trace.
And whichever you choose, check the whole chain rather than the single hop, because a 308 followed by a 301 has still lost the body at the second step. Each redirect is individually correct and the sequence is what the client experiences: the chain is the thing that costs you.