In a meta-framework's route table, what is the difference between a redirect entry and a rewrite entry?
answer
- only one of them is visible
- address bar and history follow only one
- redirect costs a second request
- rewrite is an internal substitution
- relative URLs resolve against the requested path
basics
~20 sA redirect sends a response telling the client to request a different URL, so the address bar changes and a second request happens. A rewrite serves another route's content under the requested URL, invisibly, in one round trip.
solid answer
~50 sBoth say the content is not where the URL suggests, but only one tells the client. A **redirect** answers with a 3xx status and a `Location` header; the browser makes a second request, and the address bar, history entry and shareable URL all become the destination. A **rewrite** is resolved inside the routing layer: the incoming path is mapped to a different route, or even a different deployment proxied under a prefix, and that result is returned under the original URL in a single response. So a redirect costs a round trip and moves the canonical address; a rewrite costs nothing extra and hides the real structure. The usual rewrite bug follows from that hiding: relative asset paths in the returned page resolve against the URL the browser asked for, not the one the server substituted.
go deeper
Recall the one-line split: the browser is told about a redirect and is not told about a rewrite, so only a redirect changes the address bar and costs a second request.
Explain the mechanics — 3xx plus a Location header versus an internal route substitution — and the consequences for history, crawlers, caching and relative URL resolution in the returned page.
Show judgment about which outcome a real move deserves, and name the operational traps: chains, loops, duplicate content without a canonical link, and permanence you cannot easily withdraw.
Frame it as a contract question. A redirect publishes a new canonical address to everyone who links to you; a rewrite preserves the old contract and takes on the cost of maintaining two live paths indefinitely.
## A URL does not always end in a page A routing layer turns an incoming path into one of a small set of **outcomes**: a rendered page, a **redirect**, a **rewrite**, a **not-found** page, or an **error** page. Redirects and rewrites are the two that say "the address you asked for is not where the content is" — and they differ entirely in whether the client is told about it. A **redirect** is a response whose job is to send the client somewhere else. The response carries a 3xx status and a `Location` header naming the destination; its body is irrelevant and usually empty. The browser then issues a **second request** for that destination. Everything the user can see follows: the address bar, the history entry, the URL that gets bookmarked or copied into a chat, and the URL a crawler records as canonical. A **rewrite** never leaves the server. The routing layer maps the incoming path onto a *different* route internally — sometimes onto an entirely different deployment or origin proxied under a path prefix — and renders that. One request, one response, and the address bar still shows the path the user typed. The client has no way to tell a rewrite happened short of comparing the markup with the route tree. ## The comparison that gets asked | | Redirect | Rewrite | |---|---|---| | Address bar | changes to the destination | unchanged | | Network round trips | at least two | one | | Status the client sees | 3xx, then the destination's status | the destination route's own status | | Client aware of it | yes, and history records it | no | | Typical use | moved or renamed content, canonicalising a URL, sending an unauthenticated visitor to a sign-in page | serving a legacy or vanity path, putting two deployments under one domain, path-prefix proxying, experiment splits | | Main risk | chains and loops; a rule declared permanent is remembered by clients and shared caches, so it is awkward to take back | two URLs serving the same content unless one is marked canonical; relative URLs resolving against the requested path | ## Where the entries live Most meta-frameworks accept both kinds of entry in a **build-declared table**: a list of source patterns and destinations written in configuration, compiled into the build output, and executed by whatever the app is deployed onto. Some rules cannot be written that way because they depend on the request itself — who the visitor is, which experiment bucket they are in, whether a resource exists — and those are decided **per request** instead, typically inside the route's data step, which can abandon rendering and answer a redirect. The practical consequences of the split: - A build-declared rule is cheap and uniform, but changing it usually means a deploy. - A per-request redirect runs your code on every matching request, so it costs whatever a request costs on that hosting target. - A build-declared table is only as expressive as the target can implement; a rule matching on a cookie or a header often cannot be expressed by a plain file host at all. ## Traps worth knowing 1. **Relative URLs after a rewrite.** The page produced by the rewrite target may contain relative links and asset paths. The browser resolves them against the URL it *requested*, not the URL the server substituted — a very common source of broken stylesheets and images under a rewritten prefix. 2. **Duplicate content.** Because a rewrite leaves both paths serving a body, a crawler can index both. A redirect states which URL wins; a rewrite does not, so the served page needs a canonical link element if the duplicate matters. 3. **Permanence is sticky.** A redirect declared permanent is exactly the one clients and shared caches are entitled to remember for a long time, which is excellent for a genuine move and painful for a rule you may want to reverse next quarter. 4. **Chains.** Two rules that each rewrite a prefix and one redirect in the middle can produce several round trips for one navigation, and a rule pair that points at each other produces a loop the client eventually gives up on. 5. **Cross-origin rewrites.** Serving another origin's content under your domain makes your domain the origin for cookies, storage and content-security decisions on that page; it is a routing decision with security consequences, not just a convenience. ## How to talk about it in an interview Say the distinction in one line — *the browser learns about a redirect and does not learn about a rewrite* — and then reach for consequences rather than syntax: round trips, the address bar and what gets shared, what a crawler records, and which of the two you can undo later. That is the reasoning the question is actually probing, and it transfers unchanged between frameworks, because each one exposes the same two outcomes behind different names.
- Why can a rewrite hurt search ranking in a way a redirect does not?A rewrite leaves both the source and the destination path serving a body, so a crawler can index two URLs with the same content and split signals between them. A redirect states which URL wins. If you rewrite, the served page usually needs a canonical link element naming the preferred URL.
- When would you prefer a rewrite to a redirect for a legacy path?When the old address must keep working as-is for clients you cannot update — deep links in printed material, third-party integrations, or an app section served by a separate deployment. A rewrite keeps those URLs valid and saves a round trip; a redirect is better when you want the new URL to become the one people copy and share.
A redirect is mail forwarding: the letter comes back stamped with the new address and you post it again. A rewrite is a receptionist quietly walking your request to a different desk while you keep standing where you are.
saying these in an interview costs you the question
- Says a rewrite changes the address bar like a redirect does
- Thinks a redirect and a rewrite cost the same number of requests
- Believes a rewrite can only target a route in the same deployment
- Assumes relative asset paths resolve against the rewrite's target
- Treats a permanent redirect as trivially reversible later