Skip to content

docs: improve docs around cache control order and redirects #7744

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/docs/src/routes/docs/(qwikcity)/caching/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ contributors:
- chsanch
- hamatoyogi
- Jemsco
- FHachez
updated_at: '2023-10-03T18:53:23Z'
created_at: '2023-05-24T03:52:24Z'
---
Expand Down Expand Up @@ -83,6 +84,20 @@ export const onGet: RequestHandler = async ({ cacheControl }) => {

You can see the full [API reference](https://qwik.dev/api/qwik-city-middleware-request-handler/) of options you can pass to `request.cacheControl`.

### `cacheControl` Order

Qwik City executes request handlers in a specific order. This is important because if multiple handlers set the cache control policy, **the last one to execute wins**.

The execution order is as follows:

1. **Middleware (`src/middleware/index.ts`)**
2. **Layouts (from the root layout downwards)**
3. **Page endpoints (`src/routes/..../index.tsx`)**

This means that the cache control set in a page's `onGet` handler will override any cache control set in a layout or middleware. For example, you can set a default cache policy in a root layout, and then override it in a specific page.

When using `redirect()`, there is a special case for caching. See [redirects and caching](/docs/(qwikcity)/guides/redirects/#caching) for more information.

## When not to cache

Caching is generally beneficial, but not right for every page all the time. If your site has URLs that will show different content to different people — for example, pages exclusive to logged-in users or pages that show content based on a user's location — you should avoid using cache-control headers to cache these pages. Instead, render the content of these pages on the server side on a per-visitor basis.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ contributors:
- mhevery
- mrhoodz
- hamatoyogi
- FHachez
updated_at: '2023-06-25T19:43:33Z'
created_at: '2023-03-20T23:45:13Z'
---
Expand Down Expand Up @@ -53,6 +54,29 @@ If you do not provide a status code, Qwik City will default to a `302` Found sta

Read more about redirect status codes [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages).

## Caching

When you issue a redirect using the `redirect()` method from the `RequestEvent`, Qwik City applies a default cache control policy if one hasn't been explicitly set. This includes `Cache-Control` headers set in a higher-level layout or middleware. For more details on the order of execution, see the [caching documentation](/docs/caching/).

If the redirect's status code is greater than `301` (e.g., `302`, `307`), and you haven't called `cacheControl()` for that request, the `Cache-Control` header will automatically be set to `'no-store'`. This prevents the redirect from being cached by the browser or intermediate caches.

```typescript
export const onGet: RequestHandler = ({ redirect }) => {
// This will result in a `Cache-Control: no-store` header
throw redirect(302, '/new-location');
};
```

To override this default behavior and explicitly set a cache control policy for a redirect, you can call `cacheControl()` before throwing the redirect.

```typescript
export const onGet: RequestHandler = ({ redirect, cacheControl }) => {
// To override the default, set it explicitly
cacheControl('day');
throw redirect(302, '/new-location');
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah looking at it like that on this code snippet, it really does look like a footgun and seems unintuitive. Will discuss this with the core team before merging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably separate this code snippet into two code snippets each with its own explanation.

Copy link
Author

@FHachez FHachez Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah looking at it like that on this code snippet, it really does look like a footgun and seems unintuitive. Will discuss this with the core team before merging.

Indeed

I would probably separate this code snippet into two code snippets each with its own explanation.

Good idea, I've updated the PR.

```

## Managing multiple redirects

In some cases, you may need to manage multiple redirects based on different conditions. For example, you might want to redirect users from old URLs to new URLs after a site restructure. Additionally, you may want editors in a CMS to manage these redirects as well. Here's one of the ways you can handle multiple redirects in Qwik:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ export const onGet: RequestHandler = async ({ status, getWritableStream }) => {

Redirect to a new URL. Notice the importance of throwing to prevent other middleware functions from running. The `redirect()` method will automatically set the `Location` header to the redirect URL.

> **Note**: When using `redirect()`, Qwik City applies a default `Cache-Control` header of `no-store` for redirects with a status code greater than 301. You can learn more about this behavior in the [redirects guide](/docs/guides/redirects/#caching).

<CodeSandbox src="/src/routes/demo/qwikcity/middleware/redirect/index.tsx">
```tsx
import { type RequestHandler } from '@builder.io/qwik-city';
Expand Down