Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
1 change: 1 addition & 0 deletions pages/cloudflare/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"caching": "",
"howtos": "How-Tos",
"examples": "",
"perf": "Performance Tips",
"community": "Community projects",
"known-issues": "Known issues",
"troubleshooting": "",
Expand Down
16 changes: 13 additions & 3 deletions pages/cloudflare/caching.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,11 @@ import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue";
import { purgeCache } from "@opennextjs/cloudflare/overrides/cache-purge/index";

export default defineCloudflareConfig({
incrementalCache: withRegionalCache(r2IncrementalCache, { mode: "long-lived" }),
incrementalCache: withRegionalCache(r2IncrementalCache, {
mode: "long-lived",
// Setting `bypassTagCacheOnCacheHit` to `true` requires enabling cache purge
bypassTagCacheOnCacheHit: true,
}),
queue: doQueue,
// This is only required if you use On-demand revalidation
tagCache: doShardedTagCache({
Expand Down Expand Up @@ -264,7 +268,7 @@ Next.js also generates _immutable_ files that don't change between builds. Those
There are 3 storage options for the incremental cache:

- **R2 Object Storage:** A [cost-effective](https://developers.cloudflare.com/r2/pricing/) S3-compatible object storage option for large amounts of unstructured data. Data is stored in a single region, meaning cache interactions may be slower - this can be mitigated with a regional cache.
- **Workers KV:** A [fast](https://blog.cloudflare.com/faster-workers-kv) key value store, it uses Cloudflare's [Tiered Cache](https://developers.cloudflare.com/cache/how-to/tiered-cache/) to increase cache hit rates. When you write cached data to Workers KV, you write to storage that can be read by any Cloudflare location. This means your app can fetch data, cache it in KV, and then subsequent requests anywhere around the world can read from this cache.
- **Workers KV:** A [fast](https://blog.cloudflare.com/faster-workers-kv) key value store, it uses Cloudflare's [Tiered Cache](https://developers.cloudflare.com/cache/how-to/tiered-cache/) to increase cache hit rates. When you write cached data to Workers KV, you write to storage that can be read by any Cloudflare location. This means your app can fetch data, cache it in KV, and then subsequent requests anywhere around the world can read from this cache. We do not recommend using KV because it is eventually consistent.
- **Workers Static Assets:** A read-only store for the incremental cache, serving build-time values from [Workers Static Assets](https://developers.cloudflare.com/workers/static-assets/). Revalidation is not supported with this cache.

<Tabs items={["R2 Object Storage", "Workers KV", "Workers Static Assets"]}>
Expand Down Expand Up @@ -329,7 +333,7 @@ import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-
export default defineCloudflareConfig({
incrementalCache: withRegionalCache(r2IncrementalCache, {
mode: "long-lived",
shouldLazilyUpdateOnCacheHit: true,
bypassTagCacheOnCacheHit: true,
}),
// ...
});
Expand Down Expand Up @@ -751,3 +755,9 @@ If you want to use the durable object option, you will need to add the following
```

You can customize the duration of the cache purge buffering with the `NEXT_CACHE_DO_PURGE_BUFFER_TIME_IN_SECONDS` environment variable. The default is 5 seconds. It works by buffering the purge requests for a given amount of time and then sending them all at once. This is useful to avoid hitting the API rate limits.

### Debugging

You can add `NEXT_PRIVATE_DEBUG_CACHE=1` to your app `.env` file to debug any cache issue.
The app will output logs whenever the cache is accessed - those logs are generated by both Next and the cache adapter.
You can find more details in [the Next documentation](https://nextjs.org/docs/app/guides/incremental-static-regeneration#verifying-correct-production-behavior)
96 changes: 96 additions & 0 deletions pages/cloudflare/perf.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Callout } from "nextra/components";

## Performance tips

They are a lot of features and knobs you can tune to improve the performance of your app. This page lists some of the recommend settings.

### General

You should regularly update to the latest available version of [`@opennextjs/cloudflare`](https://www.npmjs.com/package/@opennextjs/cloudflare) to benefit from the latest performance and security updates.

### Caching

Caching can drastically improves the performance of your application by only fetching data / re-generating your pages when they change.

To get the most out of caching, you should start by reading how Next.js implements caching. The ["Caching in Next.js" guide](https://nextjs.org/docs/app/guides/caching) is a good place to start.

You should then check [how to configure caching](/cloudflare/caching) for the OpenNext adapter. See below for some advice.

#### [Incremental Cache](/cloudflare/caching#incremental-static-regeneration-isr)

The Incremental cache is the store containing all the cached data (i.e. pages, `fetch`, `unstable_cache`).

You should use the Workers Static Assets based cache if your site is SSG. It is the fastest available option. Note that as Workers Static Assets are read-only, this option can not be used with revalidation.
Copy link
Contributor

Choose a reason for hiding this comment

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

We could add a note about the data cache here, you could use static assets if you only have SSG route (that you don't revalidate) and SSR route with absolutely no data cache (or one that don't change after build).
If they use that they should also not use the tag cache


When your app uses re-validation, use the R2 based store instead. We recommend the following settings to get the best perfomance:

- use regional cache by wrapping the handler into `withRegionalCache(...)`
- use the `long-lived` mode
- you should not need to explicitly set `shouldLazilyUpdateOnCacheHit` nor `bypassTagCacheOnCacheHit` as they are set to the most performant mode by default
- setup [automatic cache purge](/cloudflare/caching#automatic-cache-purge)

<Callout type="info">Using KV is not recommended as it is eventually consistent.</Callout>

#### [Tag Cache](/cloudflare/caching#tag-cache-for-on-demand-revalidation)

The Tag Cache is not properly a cache. It only stores the timestamp at which tags have been revalidated.

It should be configured for App-Router based app using `revalidateTag` or `revalidatePath`.

The D1 based tag cache should only be used if your site receives low traffic. The Durable Object based tag cache is the recommend option for most sites. See [the reference guide](/cloudflare/caching#tag-cache-for-on-demand-revalidation) for the available configuration options.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we say low traffic ? Do we want to add some numbers here ? I feel like a lot of people just testing OpenNext should use D1
And I think that a lot of people actually have low enough traffic for D1, D1 is still pretty capable


Copy link
Contributor

Choose a reason for hiding this comment

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

We should definitely add some notes here about the DO tag cache around the sizing of it, a lot of people issues with that is probably about bad sizing actually. Maybe in another PR, because it is a big subject

Application using `revalidateTag` exclusively (and not `revalidatePath`) will benefit from using the `withFilter` wrapper with the `softTagFilter` filter.

#### [Static Assets](/cloudflare/caching#static-assets-caching)

You should add a `public/_headers` file to cache the static assets served by your app.

See the [Cloudflare documentation](https://developers.cloudflare.com/workers/static-assets/headers/) for a detailed explanation of the default and the syntax.

### [Multiple Workers](https://opennext.js.org/cloudflare/howtos/multi-worker)

Deploying the middleware and the main server to distinct Workers can help with performance. As when a page can be retrieved from the cache, the main server can be fully bypassed.

### Troubleshooting performance

You can profile the code to troubleshoot performance issues.

#### Building unminified code

Code profiles are much easier to read when the code is not minified, you can use the following settings to generate unminified code

**next.config.ts**

```ts
const nextConfig = {
// ...
experimental: {
serverMinification: false,
},
webpack: (config) => {
config.optimization.minimize = false;
return config;
},
compress: false,
};
```

**CLI**

Use the `--noMinify` option when building the app:

```bash
opennextjs-cloudflare build --noMinify
```

#### Record a profile

You should first launch a local version of your application by running

```bash
opennextjs-cloudflare preview
```

Once the app is running, follow [the steps from the Workers doc](https://developers.cloudflare.com/workers/observability/dev-tools/cpu-usage/) to record a CPU profile.

You can then inspect the profile and check if any particular section of the application is unexpectedly slow.
8 changes: 0 additions & 8 deletions pages/cloudflare/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ import { Callout } from "nextra/components";

## Troubleshooting

### Trying to deploy to Cloudflare Pages, instead of Cloudflare Workers?

`@opennextjs/cloudflare` is specifically built for deploying Next.js apps to [Cloudflare Workers](https://developers.cloudflare.com/workers/)

Cloudflare Workers now support the majority of functionality from Cloudflare Pages, and have features that are not yet supported by Cloudflare Pages. Refer to the [Compatibility Matrix](https://developers.cloudflare.com/workers/static-assets/compatibility-matrix/) in the Cloudflare Workers docs.

If you need to deploy to Cloudflare Pages, you can use `@cloudflare/next-on-pages`, and follow the [Cloudflare Pages guides for deploying Next.js apps](https://developers.cloudflare.com/pages/framework-guides/nextjs/).

### "Your Worker exceeded the size limit of 3 MiB"

The Cloudflare Account you are deploying to is on the Workers Free plan, which [limits the size of each Worker to 3 MiB](https://developers.cloudflare.com/workers/platform/limits/#worker-size). When you subscribe to the Workers Paid plan, each Worker can be up to 10 MiB.
Expand Down