diff --git a/pages/cloudflare/_meta.json b/pages/cloudflare/_meta.json index 0b730ce..e509557 100644 --- a/pages/cloudflare/_meta.json +++ b/pages/cloudflare/_meta.json @@ -7,6 +7,6 @@ "examples": "", "community": "Community projects", "troubleshooting": "", - "migrate-from-0.5-to-0.6": "Migrate from 0.5 to 0.6", + "migrate-from-0.6-to-1.0.0-beta": "Migrate from 0.6 to 1.0.0-beta", "former-releases": "Former releases" } diff --git a/pages/cloudflare/caching.mdx b/pages/cloudflare/caching.mdx index 9636b8b..aaeb62c 100644 --- a/pages/cloudflare/caching.mdx +++ b/pages/cloudflare/caching.mdx @@ -21,28 +21,30 @@ There are two storage options to use for the incremental cache. reflected globally, when using the default TTL of 60 seconds. - + -##### 1. Create a KV namespace + +##### 1. Create an R2 Bucket ``` -npx wrangler@latest kv namespace create +npx wrangler@latest r2 bucket create ``` -##### 2. Add the KV namespace and Service Binding to your Worker +##### 2. Add the R2 Bucket and Service Binding to your Worker -The binding name used in your app's worker is `NEXT_INC_CACHE_KV`. -The `WORKER_SELF_REFERENCE` service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. +The binding name used in your app's worker is `NEXT_INC_CACHE_R2_BUCKET`. The service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. + +The prefix used by the R2 bucket can be configured with the `NEXT_INC_CACHE_R2_PREFIX` environment variable, and defaults to `incremental-cache`. ```jsonc // wrangler.jsonc { // ... "name": "", - "kv_namespaces": [ + "r2_buckets": [ { - "binding": "NEXT_INC_CACHE_KV", - "id": "", + "binding": "NEXT_INC_CACHE_R2_BUCKET", + "bucket_name": "", }, ], "services": [ @@ -56,46 +58,62 @@ The `WORKER_SELF_REFERENCE` service binding should be a self reference to your w ##### 3. Configure the cache -In your project's OpenNext config, enable the KV cache. +In your project's OpenNext config, enable the R2 cache. + +You can optionally setup a regional cache to use with the R2 incremental cache. This will enable faster retrieval of cache entries and reduce the amount of requests being sent to object storage. + +The regional cache has two modes: + +- `short-lived`: Responses are re-used for up to a minute. +- `long-lived`: Fetch responses are re-used until revalidated, and ISR/SSG responses are re-used for up to 30 minutes. + +Additionally, lazy updating of the regional cache can be enabled with the `shouldLazilyUpdateOnCacheHit` option. When requesting data from the cache, it sends a background request to the R2 bucket to get the latest entry. This is enabled by default for the `long-lived` mode. ```ts // open-next.config.ts import { defineCloudflareConfig } from "@opennextjs/cloudflare"; -import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; +import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"; +import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; // ... +// With regional cache enabled: export default defineCloudflareConfig({ - incrementalCache: kvIncrementalCache, + incrementalCache: withRegionalCache(r2IncrementalCache, { + mode: "long-lived", + shouldLazilyUpdateOnCacheHit: true, + }), + // ... +}); + +// Without regional cache: +export default defineCloudflareConfig({ + incrementalCache: r2IncrementalCache, // ... }); ``` - - -##### 1. Create an R2 Bucket +##### 1. Create a KV namespace ``` -npx wrangler@latest r2 bucket create +npx wrangler@latest kv namespace create ``` -##### 2. Add the R2 Bucket and Service Binding to your Worker - -The binding name used in your app's worker is `NEXT_INC_CACHE_R2_BUCKET`. The service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. +##### 2. Add the KV namespace and Service Binding to your Worker -The prefix used by the R2 bucket can be configured with the `NEXT_INC_CACHE_R2_PREFIX` environment variable, and defaults to `incremental-cache`. +The binding name used in your app's worker is `NEXT_INC_CACHE_KV`. +The `WORKER_SELF_REFERENCE` service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. ```jsonc // wrangler.jsonc { // ... "name": "", - "r2_buckets": [ + "kv_namespaces": [ { - "binding": "NEXT_INC_CACHE_R2_BUCKET", - "bucket_name": "", - "preview_bucket_name": "", + "binding": "NEXT_INC_CACHE_KV", + "id": "", }, ], "services": [ @@ -109,36 +127,16 @@ The prefix used by the R2 bucket can be configured with the `NEXT_INC_CACHE_R2_P ##### 3. Configure the cache -In your project's OpenNext config, enable the R2 cache. - -You can optionally setup a regional cache to use with the R2 incremental cache. This will enable faster retrieval of cache entries and reduce the amount of requests being sent to object storage. - -The regional cache has two modes: - -- `short-lived`: Responses are re-used for up to a minute. -- `long-lived`: Fetch responses are re-used until revalidated, and ISR/SSG responses are re-used for up to 30 minutes. - -Additionally, lazy updating of the regional cache can be enabled with the `shouldLazilyUpdateOnCacheHit` option. When requesting data from the cache, it sends a background request to the R2 bucket to get the latest entry. This is enabled by default for the `long-lived` mode. +In your project's OpenNext config, enable the KV cache. ```ts // open-next.config.ts import { defineCloudflareConfig } from "@opennextjs/cloudflare"; -import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"; -import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; +import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; // ... -// With regional cache enabled: export default defineCloudflareConfig({ - incrementalCache: withRegionalCache(r2IncrementalCache, { - mode: "long-lived", - shouldLazilyUpdateOnCacheHit: true, - }), - // ... -}); - -// Without regional cache: -export default defineCloudflareConfig({ - incrementalCache: r2IncrementalCache, + incrementalCache: kvIncrementalCache, // ... }); ``` @@ -172,14 +170,14 @@ You will also need to add some binding to your `wrangler.jsonc` file. "bindings": [ { "name": "NEXT_CACHE_DO_QUEUE", - "class_name": "DurableObjectQueueHandler" + "class_name": "DOQueueHandler" } ] }, "migrations": [ { "tag": "v1", - "new_sqlite_classes": ["DurableObjectQueueHandler"] + "new_sqlite_classes": ["DOQueueHandler"] } ], ``` @@ -189,7 +187,7 @@ You can customize the behaviors of the queue with environment variables: - The max number of revalidations that can be processed by an instance of durable object at the same time (`NEXT_CACHE_DO_QUEUE_MAX_REVALIDATION`) - The max time in milliseconds that a revalidation can take before being considered as failed (`NEXT_CACHE_DO_QUEUE_REVALIDATION_TIMEOUT_MS`) - The amount of time after which a revalidation will be attempted again if it failed. If it fails again it will exponentially back off until it reaches the max retry interval (`NEXT_CACHE_DO_QUEUE_RETRY_INTERVAL_MS`) -- The maximum number of attempts that can be made to revalidate a path (`NEXT_CACHE_DO_QUEUE_MAX_NUM_REVALIDATIONS`) +- The maximum number of attempts that can be made to revalidate a path (`NEXT_CACHE_DO_QUEUE_MAX_RETRIES`) - Disable SQLite for this durable object. It should only be used if your incremental cache is not eventually consistent (`NEXT_CACHE_DO_QUEUE_DISABLE_SQLITE`) @@ -216,7 +214,7 @@ To use on-demand revalidation, you should also follow the [ISR setup steps](#inc You can also skip this step if your app doesn't to use `revalidateTag` nor `revalidatePath`. -There are 3 different options to choose from for the tag cache: `d1NextTagCache`, `doShardedTagCache` and `d1TagCache`. +There are 2 different options to choose from for the tag cache: `d1NextTagCache`, `doShardedTagCache`. Which one to choose should be based on two key factors: 1. **Expected Load**: Consider the volume of traffic or data you anticipate. @@ -224,7 +222,7 @@ Which one to choose should be based on two key factors: If either of these factors is significant, opting for a sharded database is recommended. Additionally, incorporating a regional cache can further enhance performance. - + ##### 1. Create a D1 database and Service Binding @@ -256,22 +254,43 @@ The D1 tag cache requires a `revalidations` table that tracks On-Demand revalida ##### 3. Configure the cache -In your project's OpenNext config, enable the KV cache and set up a queue (see above). The queue will send a revalidation request to a page when needed, but it will not dedupe requests. +In your project's OpenNext config, enable the R2 cache and set up a queue (see above). The queue will send a revalidation request to a page when needed, but it will not dedupe requests. ```ts // open-next.config.ts import { defineCloudflareConfig } from "@opennextjs/cloudflare"; -import kvIncrementalCache from "@opennextjs/cloudflare/kv-cache"; -import d1NextTagCache from "@opennextjs/cloudflare/d1-next-tag-cache"; -import memoryQueue from "@opennextjs/cloudflare/memory-queue"; +import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"; +import d1NextTagCache from "@opennextjs/cloudflare/overrides/tag-cache/d1-next-tag-cache"; +import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue"; export default defineCloudflareConfig({ - incrementalCache: kvIncrementalCache, + incrementalCache: r2IncrementalCache, tagCache: d1NextTagCache, - queue: memoryQueue, + queue: doQueue, }); ``` +##### 4. Initialise the cache during deployments + +In order for the cache to be properly initialised with the build-time revalidation data, you need to run a command as part of your deploy step. This should be run as part of each deployment to ensure that the cache is being populated with each build's data. + +To populate remote bindings and deploy your application at the same time, you can use the `deploy` command. Similarly, the `preview` command will populate your local bindings and start a Wrangler dev server. + +```sh +# Populate remote and deploy. +opennextjs-cloudflare deploy + +# Populate local and start dev server. +opennextjs-cloudflare preview +``` + +It is possible to only populate the cache without any other steps with the `populateCache` command. + +```sh +# The target is passed as an option, either `local` or `remote`. +opennextjs-cloudflare populateCache local +``` + @@ -286,10 +305,10 @@ The service binding should be a self reference to your worker where ` - - - - - The `d1TagCache` is not recommended for production use, as it does not scale well with the number of tags. - - -##### 1. Create a D1 database and Service Binding - -The binding name used in your app's worker is `NEXT_TAG_CACHE_D1`. The service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. - -```jsonc -// wrangler.jsonc -{ - // ... - "name": "", - "d1_databases": [ - { - "binding": "NEXT_TAG_CACHE_D1", - "database_id": "", - "database_name": "", - }, - ], - "services": [ - { - "binding": "WORKER_SELF_REFERENCE", - "service": "", - }, - ], -} -``` - -The D1 database uses two tables, created when initialising the cache: - -- the "tags" table keeps a record of the tag/path mappings -- the "revalidations" table tracks revalidation times - -##### 2. Configure the cache - -In your project's OpenNext config, enable the KV cache and set up a queue. The queue will send a revalidation request to a page when needed, but it will not dedupe requests. - -```ts -// open-next.config.ts -import { defineCloudflareConfig } from "@opennextjs/cloudflare"; -import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; -import d1TagCache from "@opennextjs/cloudflare/overrides/tag-cache/d1-tag-cache"; -import memoryQueue from "@opennextjs/cloudflare/overrides/queue/memory-queue"; - -export default defineCloudflareConfig({ - incrementalCache: kvIncrementalCache, - tagCache: d1TagCache, - queue: memoryQueue, -}); -``` - -##### 3. Initialise the cache during deployments - -In order for the cache to be properly initialised with the build-time revalidation data, you need to run a command as part of your deploy step. This should be run as part of each deployment to ensure that the cache is being populated with each build's data. - -To populate remote bindings and deploy your application at the same time, you can use the `deploy` command. Similarly, the `preview` command will populate your local bindings and start a Wrangler dev server. - -```sh -# Populate remote and deploy. -opennextjs-cloudflare deploy - -# Populate local and start dev server. -opennextjs-cloudflare preview -``` - -It is possible to only populate the cache without any other steps with the `populateCache` command. - -```sh -# The target is passed as an option, either `local` or `remote`. -opennextjs-cloudflare populateCache local -``` - diff --git a/pages/cloudflare/former-releases/0.6/_meta.json b/pages/cloudflare/former-releases/0.6/_meta.json new file mode 100644 index 0000000..53a20a0 --- /dev/null +++ b/pages/cloudflare/former-releases/0.6/_meta.json @@ -0,0 +1,7 @@ +{ + "index": "Overview", + "get-started": "", + "bindings": "", + "caching": "", + "examples": "" +} diff --git a/pages/cloudflare/former-releases/0.6/bindings.mdx b/pages/cloudflare/former-releases/0.6/bindings.mdx new file mode 100644 index 0000000..df0a480 --- /dev/null +++ b/pages/cloudflare/former-releases/0.6/bindings.mdx @@ -0,0 +1,74 @@ +import { Callout } from "nextra/components"; + +### Bindings + +[Bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/) allow your Worker to interact with resources on the Cloudflare Developer Platform. When you declare a binding on your Worker, you grant it a specific capability, such as being able to read and write files to an [R2](https://developers.cloudflare.com/r2/) bucket. + +#### How to configure your Next.js app so it can access bindings + +Install [@opennextjs/cloudflare](https://www.npmjs.com/package/@opennextjs/cloudflare), and then add a [wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/) in the root directory of your Next.js app, as described in [Get Started](/cloudflare/get-started#3-create-a-wranglerjson-file). + +#### How to access bindings in your Next.js app + +You can access [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/) from any route of your Next.js app via `getCloudflareContext`: + +```js +import { getCloudflareContext } from "@opennextjs/cloudflare"; + +export async function GET(request) { + let responseText = "Hello World"; + + const myKv = getCloudflareContext().env.MY_KV_NAMESPACE; + await myKv.put("foo", "bar"); + const foo = await myKv.get("foo"); + + return new Response(foo); +} +``` + + + `getCloudflareContext` can only be used in SSG routes in "async mode" (making it return a promise), to run the function in such a way simply provide an options argument with `async` set to `true`: + ```js + const context = await getCloudflareContext({ async: true }); + ``` + + **WARNING**: During SSG caution is advised since secrets (stored in `.dev.vars` files) and local development + values from bindings (like values saved in a local KV) will be used for the pages static generation. + + + +#### How to add bindings to your Worker + +Add bindings to your Worker by adding them to your [wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/). + +## TypeScript type declarations for bindings + +To ensure that the `env` object from `getCloudflareContext().env` above has accurate TypeScript types, run the following Wrangler command to [generate types that match your Worker's configuration](https://developers.cloudflare.com/workers/languages/typescript/#generate-types-that-match-your-workers-configuration-experimental): + +``` +npx wrangler types --experimental-include-runtime +``` + +This will generate a `d.ts` file and (by default) save it to `.wrangler/types/runtime.d.ts`. You will be prompted in the command's output to add that file to your `tsconfig.json`'s `compilerOptions.types` array. + +If you would like to commit the file to git, you can provide a custom path. Here, for instance, the `runtime.d.ts` file will be saved to the root of your project: + +```bash +npx wrangler types --experimental-include-runtime="./runtime.d.ts" +``` + +To ensure that your types are always up-to-date, make sure to run `wrangler types --experimental-include-runtime` after any changes to your config file. + +## Other Cloudflare APIs (`cf`, `ctx`) + +You can access context about the incoming request from the [`cf` object](https://developers.cloudflare.com/workers/runtime-apis/request/#the-cf-property-requestinitcfproperties), as well as lifecycle methods from the [`ctx` object](https://developers.cloudflare.com/workers/runtime-apis/context) from the return value of [`getCloudflareContext()`](https://github.com/opennextjs/opennextjs-cloudflare/blob/main/packages/cloudflare/src/api/get-cloudflare-context.ts): + +```js +import { getCloudflareContext } from "@opennextjs/cloudflare"; + +export async function GET(request) { + const { env, cf, ctx } = getCloudflareContext(); + + // ... +} +``` diff --git a/pages/cloudflare/former-releases/0.6/caching.mdx b/pages/cloudflare/former-releases/0.6/caching.mdx new file mode 100644 index 0000000..0f642d3 --- /dev/null +++ b/pages/cloudflare/former-releases/0.6/caching.mdx @@ -0,0 +1,418 @@ +import { Callout } from "nextra/components"; +import { Tabs } from "nextra/components"; + +## Caching + +`@opennextjs/cloudflare` supports [caching](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#caching-data). + +### How to enable caching + +`@opennextjs/cloudflare` supports multiple caching mechanisms through a project's OpenNext configuration. + +#### Incremental Static Regeneration (ISR) + +There are two storage options to use for the incremental cache. + +- **Workers KV:** A [fast](https://blog.cloudflare.com/faster-workers-kv) and 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. The build time values are serverd by the [Workers Assets](https://developers.cloudflare.com/workers/static-assets/). Pricing information can be found in the Cloudflare [docs](https://developers.cloudflare.com/workers/platform/pricing/#workers-kv). +- **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 is eventually consistent, which means that it can take up to 60 seconds for updates to be + reflected globally, when using the default TTL of 60 seconds. + + + + +##### 1. Create a KV namespace + +``` +npx wrangler@latest kv namespace create +``` + +##### 2. Add the KV namespace and Service Binding to your Worker + +The binding name used in your app's worker is `NEXT_INC_CACHE_KV`. +The `WORKER_SELF_REFERENCE` service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. + +```jsonc +// wrangler.jsonc +{ + // ... + "name": "", + "kv_namespaces": [ + { + "binding": "NEXT_INC_CACHE_KV", + "id": "", + }, + ], + "services": [ + { + "binding": "WORKER_SELF_REFERENCE", + "service": "", + }, + ], +} +``` + +##### 3. Configure the cache + +In your project's OpenNext config, enable the KV cache. + +```ts +// open-next.config.ts +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; +// ... + +export default defineCloudflareConfig({ + incrementalCache: kvIncrementalCache, + // ... +}); +``` + + + + + +##### 1. Create an R2 Bucket + +``` +npx wrangler@latest r2 bucket create +``` + +##### 2. Add the R2 Bucket and Service Binding to your Worker + +The binding name used in your app's worker is `NEXT_INC_CACHE_R2_BUCKET`. The service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. + +The prefix used by the R2 bucket can be configured with the `NEXT_INC_CACHE_R2_PREFIX` environment variable, and defaults to `incremental-cache`. + +```jsonc +// wrangler.jsonc +{ + // ... + "name": "", + "r2_buckets": [ + { + "binding": "NEXT_INC_CACHE_R2_BUCKET", + "bucket_name": "", + "preview_bucket_name": "", + }, + ], + "services": [ + { + "binding": "WORKER_SELF_REFERENCE", + "service": "", + }, + ], +} +``` + +##### 3. Configure the cache + +In your project's OpenNext config, enable the R2 cache. + +You can optionally setup a regional cache to use with the R2 incremental cache. This will enable faster retrieval of cache entries and reduce the amount of requests being sent to object storage. + +The regional cache has two modes: + +- `short-lived`: Responses are re-used for up to a minute. +- `long-lived`: Fetch responses are re-used until revalidated, and ISR/SSG responses are re-used for up to 30 minutes. + +Additionally, lazy updating of the regional cache can be enabled with the `shouldLazilyUpdateOnCacheHit` option. When requesting data from the cache, it sends a background request to the R2 bucket to get the latest entry. This is enabled by default for the `long-lived` mode. + +```ts +// open-next.config.ts +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"; +import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; +// ... + +// With regional cache enabled: +export default defineCloudflareConfig({ + incrementalCache: withRegionalCache(r2IncrementalCache, { + mode: "long-lived", + shouldLazilyUpdateOnCacheHit: true, + }), + // ... +}); + +// Without regional cache: +export default defineCloudflareConfig({ + incrementalCache: r2IncrementalCache, + // ... +}); +``` + + + + +##### 4. Configure the queue + +In your project's OpenNext config, enable the cache and set up a queue. + +The Durable Object Queue will send revalidation requests to a page when needed, and offers support for de-duplicating requests. +By default there will be a maximum of 10 instance of the Durables Object Queue and they can each process up to 5 requests in parallel, for up to 50 concurrent ISR revalidations. + +```ts +// open-next.config.ts +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +// ... +import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue"; + +export default defineCloudflareConfig({ + // ... + queue: doQueue, +}); +``` + +You will also need to add some binding to your `wrangler.jsonc` file. + +```jsonc +"durable_objects": { + "bindings": [ + { + "name": "NEXT_CACHE_DO_QUEUE", + "class_name": "DurableObjectQueueHandler" + } + ] + }, + "migrations": [ + { + "tag": "v1", + "new_sqlite_classes": ["DurableObjectQueueHandler"] + } + ], +``` + +You can customize the behaviors of the queue with environment variables: + +- The max number of revalidations that can be processed by an instance of durable object at the same time (`NEXT_CACHE_DO_QUEUE_MAX_REVALIDATION`) +- The max time in milliseconds that a revalidation can take before being considered as failed (`NEXT_CACHE_DO_QUEUE_REVALIDATION_TIMEOUT_MS`) +- The amount of time after which a revalidation will be attempted again if it failed. If it fails again it will exponentially back off until it reaches the max retry interval (`NEXT_CACHE_DO_QUEUE_RETRY_INTERVAL_MS`) +- The maximum number of attempts that can be made to revalidate a path (`NEXT_CACHE_DO_QUEUE_MAX_NUM_REVALIDATIONS`) +- Disable SQLite for this durable object. It should only be used if your incremental cache is not eventually consistent (`NEXT_CACHE_DO_QUEUE_DISABLE_SQLITE`) + + + There is 2 additional modes that you can use for the queue `direct` and the memory queue + +- The memory queue will dedupe request but only on a per isolate basis. It is not fully suitable for production deployments, you + can use it at your own risk! + +- The `direct` mode for the queue is intended for debugging purposes and is not recommended for use in + production. It only works in preview mode (i.e. `wrangler dev`) + + For apps using the Page Router, `res.revalidate` requires to provide a self reference service binding named `WORKER_SELF_REFERENCE`. + + + +#### On-Demand Revalidation + +The tag revalidation mechanism can use either a [Cloudflare D1](https://developers.cloudflare.com/d1/) database or [Durable Objects](https://developers.cloudflare.com/durable-objects/) with `SqliteStorage` as its backing store for information about tags, paths, and revalidation times. + +To use on-demand revalidation, you should also follow the [ISR setup steps](#incremental-static-regeneration-isr). + + + If your app **only** uses the pages router, it does not need to have a tag cache and should skip this step. + You can also skip this step if your app doesn't to use `revalidateTag` nor `revalidatePath`. + + +There are 3 different options to choose from for the tag cache: `d1NextTagCache`, `doShardedTagCache` and `d1TagCache`. +Which one to choose should be based on two key factors: + +1. **Expected Load**: Consider the volume of traffic or data you anticipate. +2. **Usage of** `revalidateTag` / `revalidatePath`: Evaluate how frequently these features will be utilized. + +If either of these factors is significant, opting for a sharded database is recommended. Additionally, incorporating a regional cache can further enhance performance. + + + +##### 1. Create a D1 database and Service Binding + +The binding name used in your app's worker is `NEXT_TAG_CACHE_D1`. The `WORKER_SELF_REFERENCE` service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. + +```jsonc +// wrangler.jsonc +{ + // ... + "d1_databases": [ + { + "binding": "NEXT_TAG_CACHE_D1", + "database_id": "", + "database_name": "", + }, + ], + "services": [ + { + "binding": "WORKER_SELF_REFERENCE", + "service": "", + }, + ], +} +``` + +##### 2. Create table for tag revalidations + +The D1 tag cache requires a `revalidations` table that tracks On-Demand revalidation times. + +##### 3. Configure the cache + +In your project's OpenNext config, enable the KV cache and set up a queue (see above). The queue will send a revalidation request to a page when needed, but it will not dedupe requests. + +```ts +// open-next.config.ts +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +import kvIncrementalCache from "@opennextjs/cloudflare/kv-cache"; +import d1NextTagCache from "@opennextjs/cloudflare/d1-next-tag-cache"; +import memoryQueue from "@opennextjs/cloudflare/memory-queue"; + +export default defineCloudflareConfig({ + incrementalCache: kvIncrementalCache, + tagCache: d1NextTagCache, + queue: memoryQueue, +}); +``` + + + + +##### 1. Create a Durable Object and Service Binding +The service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. + +```jsonc +// wrangler.jsonc +{ + // ... + "durable_objects": { + "bindings": [ + { + "name": "NEXT_CACHE_DO_QUEUE", + "class_name": "DurableObjectQueueHandler", + }, + { + "name": "NEXT_TAG_CACHE_DO_SHARDED", + "class_name": "DOShardedTagCache", + }, + ], + }, + "migrations": [ + { + "tag": "v1", + "new_sqlite_classes": ["DurableObjectQueueHandler", "DOShardedTagCache"], + }, + ], + "services": [ + { + "binding": "WORKER_SELF_REFERENCE", + "service": "", + }, + ], +} +``` + +##### 2. Configure the cache + +In your project's OpenNext config, enable the KV cache and set up a queue. The queue will send a revalidation request to a page when needed, but it will not dedupe requests. + +```ts +// open-next.config.ts +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; +import memoryQueue from "@opennextjs/cloudflare/overrides/queue/do-queue"; +import doShardedTagCache from "@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache"; + +export default defineCloudflareConfig({ + incrementalCache: kvIncrementalCache, + tagCache: doShardedTagCache({ baseShardSize: 12, regionalCache: true }), + queue: memoryQueue, +}); +``` + +doShardedTagCache tahes the following options: + +- `baseShardSize` - The number of shards to use for the cache. The more shards you have, the more evenly the cache will be distributed across the shards. The default is 4. Soft (internal next tags used for `revalidatePath`) and hard tags (the one you define in your app) will be split in different shards +- `regionalCache` - Whether to use regional cache for the cache. The default is false. This option is useful when you want to reduce the stress on the durable object +- `regionalCacheTtlSec` - The TTL for the regional cache. The default is 5 seconds. Increasing this value will increase the time it takes for the cache to be invalidated across regions +- `enableShardReplication`: Enable replicating the Shard. Shard replication will duplicate each shards into replicas to spread the load even more +- `shardReplicationOptions.numberOfSoftReplicas`: Number of replicas for the soft tag shards +- `shardReplicationOptions.numberOfHardReplicas`: Number of replicas for the hard tag shards +- `maxWriteRetries`: The number of retries to perform when writing tags + + + + + + + The `d1TagCache` is not recommended for production use, as it does not scale well with the number of tags. + + +##### 1. Create a D1 database and Service Binding + +The binding name used in your app's worker is `NEXT_TAG_CACHE_D1`. The service binding should be a self reference to your worker where `` is the name in your wrangler configuration file. + +```jsonc +// wrangler.jsonc +{ + // ... + "name": "", + "d1_databases": [ + { + "binding": "NEXT_TAG_CACHE_D1", + "database_id": "", + "database_name": "", + }, + ], + "services": [ + { + "binding": "WORKER_SELF_REFERENCE", + "service": "", + }, + ], +} +``` + +The D1 database uses two tables, created when initialising the cache: + +- the "tags" table keeps a record of the tag/path mappings +- the "revalidations" table tracks revalidation times + +##### 2. Configure the cache + +In your project's OpenNext config, enable the KV cache and set up a queue. The queue will send a revalidation request to a page when needed, but it will not dedupe requests. + +```ts +// open-next.config.ts +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; +import d1TagCache from "@opennextjs/cloudflare/overrides/tag-cache/d1-tag-cache"; +import memoryQueue from "@opennextjs/cloudflare/overrides/queue/memory-queue"; + +export default defineCloudflareConfig({ + incrementalCache: kvIncrementalCache, + tagCache: d1TagCache, + queue: memoryQueue, +}); +``` + +##### 3. Initialise the cache during deployments + +In order for the cache to be properly initialised with the build-time revalidation data, you need to run a command as part of your deploy step. This should be run as part of each deployment to ensure that the cache is being populated with each build's data. + +To populate remote bindings and deploy your application at the same time, you can use the `deploy` command. Similarly, the `preview` command will populate your local bindings and start a Wrangler dev server. + +```sh +# Populate remote and deploy. +opennextjs-cloudflare deploy + +# Populate local and start dev server. +opennextjs-cloudflare preview +``` + +It is possible to only populate the cache without any other steps with the `populateCache` command. + +```sh +# The target is passed as an option, either `local` or `remote`. +opennextjs-cloudflare populateCache local +``` + + + diff --git a/pages/cloudflare/former-releases/0.6/examples.mdx b/pages/cloudflare/former-releases/0.6/examples.mdx new file mode 100644 index 0000000..e44bee0 --- /dev/null +++ b/pages/cloudflare/former-releases/0.6/examples.mdx @@ -0,0 +1,24 @@ +import { Callout } from "nextra/components"; + +## Examples + +To create a new Next.js app, pre-configured to run on Cloudflare using `@opennextjs/cloudflare`, run: + +``` +npm create cloudflare@latest -- my-next-app --framework=next --experimental +``` + +### Basic starter projects + +Basic example apps are included in the repository for `@opennextjs/cloudflare` package: + +- [_`create-next-app`_](https://github.com/opennextjs/opennextjs-cloudflare/tree/main/examples/create-next-app) — a Next.js project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +- [_`api`_](https://github.com/opennextjs/opennextjs-cloudflare/tree/main/examples/api) — a minimal Next.js project with a single API route +- [_`middleware`_](https://github.com/opennextjs/opennextjs-cloudflare/tree/main/examples/middleware) — a minimal Next.js project using middleware +- [_`vercel-blog-starter`_](https://github.com/opennextjs/opennextjs-cloudflare/tree/main/examples/vercel-blog-starter) — a blog project using SSG + +You can use these to understand how to configure your Next.js app to use `@opennextjs/cloudflare`, or refer to [Get Started](/cloudflare/get-started). + +### Next.js Commerce Demo + +The [Next.js Commerce demo app](https://github.com/vercel/commerce/tree/v1) works with `@opennextjs/cloudflare`. You can view a deployed version of it [here](https://vercel-commerce-on-workers.web-experiments.workers.dev/). diff --git a/pages/cloudflare/former-releases/0.6/get-started.mdx b/pages/cloudflare/former-releases/0.6/get-started.mdx new file mode 100644 index 0000000..5b1e9b0 --- /dev/null +++ b/pages/cloudflare/former-releases/0.6/get-started.mdx @@ -0,0 +1,197 @@ +import { Callout } from "nextra/components"; + +### Get Started + +#### New apps + +To create a new Next.js app, pre-configured to run on Cloudflare using `@opennextjs/cloudflare`, run: + +```sh +npm create cloudflare@latest -- my-next-app --framework=next --experimental +``` + +#### Existing Next.js apps + +##### 1. Install @opennextjs/cloudflare + +First, install [@opennextjs/cloudflare](https://www.npmjs.com/package/@opennextjs/cloudflare): + +```sh +npm install --save-dev @opennextjs/cloudflare@latest +``` + +##### 2. Install Wrangler + +Install the [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) as a devDependency: + +```sh +npm install --save-dev wrangler@latest +``` + + + You must use Wrangler version `3.99.0` or later to deploy Next.js apps using `@opennextjs/cloudflare`. + + +##### 3. Create a wrangler configuration file + + + This step is optional since `@opennextjs/cloudflare` creates this file for you during the build process (if + not already present). + + +A [wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/) is needed for your +application to be previewed and deployed, it is also where you configure your Worker and define what resources it can access via [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings). + +You can create one yourself in the root directory of your Next.js app with the name `wrangler.jsonc` and the following content: + +```jsonc +{ + "$schema": "node_modules/wrangler/config-schema.json", + "main": ".open-next/worker.js", + "name": "my-app", + "compatibility_date": "2024-12-30", + "compatibility_flags": ["nodejs_compat"], + "assets": { + "directory": ".open-next/assets", + "binding": "ASSETS", + }, + "services": [ + { + "binding": "WORKER_SELF_REFERENCE", + // The service should match the "name" of your worker + "service": "my-app", + }, + ], + "kv_namespaces": [ + // Create a KV binding with the binding name "NEXT_INC_CACHE_KV" + // to enable the KV based caching: + // { + // "binding": "NEXT_INC_CACHE_KV", + // "id": "" + // } + ], +} +``` + + + As shown above: - You must enable the [`nodejs_compat` compatibility + flag](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) *and* set your [compatibility + date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/) to `2024-09-23` or + later, in order for your Next.js app to work with @opennextjs/cloudflare - The `main` and `assets` values + should also not be changed unless you modify the build output result in some way - You can add a binding + named `NEXT_INC_CACHE_KV` to make use of Next.js' caching as described in the [Caching + docs](/cloudflare/caching) + + +##### 4. Add an `open-next.config.ts` file + + + This step is optional since `@opennextjs/cloudflare` creates this file for you during the build process (if + not already present). + + +Add a [`open-next.config.ts`](https://opennext.js.org/aws/config) file to the root directory of your Next.js app: + +```ts +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; + +export default defineCloudflareConfig({ + incrementalCache: kvIncrementalCache, +}); +``` + + + To use the `OpenNextConfig` type as illustrated above (which is not necessary), you need to install the + `@opennextjs/aws` NPM package as a dev dependency. + + +##### 5. Add a `.dev.vars` file + +Then, add a [`.dev.vars`](https://developers.cloudflare.com/workers/testing/local-development/#local-only-environment-variables) file to the root directory of your Next.js app: + +```text +NEXTJS_ENV=development +``` + +The `NEXTJS_ENV` variable defines the environment to use when loading Next.js `.env` files. It defaults to "production" when not defined. + +##### 6. Update the `package.json` file + +Add the following to the scripts field of your `package.json` file: + +```json +"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview", +"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", +"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts", +``` + +- `npm run preview`: Builds your app and serves it locally, allowing you to quickly preview your app running locally in the Workers runtime, via a single command. +- `npm run deploy`: Builds your app, and then deploys it to Cloudflare +- `cf-typegen`: Generates a `cloudflare-env.d.ts` file at the root of your project containing [the types for the `env`](https://developers.cloudflare.com/workers/wrangler/commands/#types). + +##### 7. Add caching with Workers KV + +See the [Caching docs](/cloudflare/caching) for information on enabling Next.js caching in your OpenNext project. + +##### 8. Remove any `export const runtime = "edge";` if present + +Before deploying your app, remove the `export const runtime = "edge";` line from any of your source files. + +The edge runtime is not supported yet with `@opennextjs/cloudflare`. + +##### 9. Add `.open-next` to `.gitignore` + +You should add `.open-next` to your `.gitignore` file to prevent the build output from being committed to your repository. + +##### 10. Remove `@cloudflare/next-on-pages` (if necessary) + +If your Next.js app currently uses `@cloudflare/next-on-pages`, you'll want to remove it, and make a few changes. + +Uninstalling the [`@cloudflare/next-on-pages`](https://www.npmjs.com/package/@cloudflare/next-on-pages) package as well as the [`eslint-plugin-next-on-pages`](https://www.npmjs.com/package/eslint-plugin-next-on-pages) package if present. + +Remove any reference of these packages from your source and configuration files. +This includes: + +- `setupDevPlatform()` calls in your Next.js config file +- `getRequestContext` imports from `@cloudflare/next-on-pages` from your source files + (those can be replaced with `getCloudflareContext` calls from `@opennextjs/cloudflare`) +- next-on-pages eslint rules set in your Eslint config file + +##### 11. Develop locally + +You can continue to run `next dev` when developing locally. + +Modify your Next.js configuration file to import and call the `initOpenNextCloudflareForDev` utility +from the `@opennextjs/cloudflare` package. This makes sure that the Next.js dev server can optimally integrate with the open-next cloudflare adapter and it is necessary for using bindings during local development. + +This is an example of a Next.js configuration file calling the utility: + +```ts +// next.config.ts +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; + +import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare"; +initOpenNextCloudflareForDev(); +``` + +After having added the `initOpenNextCloudflareForDev()` call in your Next.js configuration file, you will be able, during local development, to access in any of your server code, local versions of Cloudflare bindings as indicated in the [bindings documentation](./bindings). + +In step 3, we also added the `npm run preview`, which allows you to quickly preview your app running locally in the Workers runtime, +rather than in Node.js. This allows you to test changes in the same runtime as your app will run in when deployed to Cloudflare. + +##### 12. Deploy to Cloudflare Workers + +Either deploy via the command line: + +```sh +npm run deploy +``` + +Or [connect a Github or Gitlab repository](https://developers.cloudflare.com/workers/ci-cd/), and Cloudflare will automatically build and deploy each pull request you merge to your production branch. diff --git a/pages/cloudflare/former-releases/_meta.json b/pages/cloudflare/former-releases/_meta.json index fcfac6d..1186ae9 100644 --- a/pages/cloudflare/former-releases/_meta.json +++ b/pages/cloudflare/former-releases/_meta.json @@ -1,4 +1,6 @@ { + "0.6": "Release 0.6", + "migrate-from-0.5-to-0.6": "", "0.5": "Release 0.5", "migrate-from-0.4-to-0.5": "", "migrate-from-0.3-to-0.4": "", diff --git a/pages/cloudflare/migrate-from-0.5-to-0.6.mdx b/pages/cloudflare/former-releases/migrate-from-0.5-to-0.6.mdx similarity index 100% rename from pages/cloudflare/migrate-from-0.5-to-0.6.mdx rename to pages/cloudflare/former-releases/migrate-from-0.5-to-0.6.mdx diff --git a/pages/cloudflare/get-started.mdx b/pages/cloudflare/get-started.mdx index 5b1e9b0..f260672 100644 --- a/pages/cloudflare/get-started.mdx +++ b/pages/cloudflare/get-started.mdx @@ -62,13 +62,12 @@ You can create one yourself in the root directory of your Next.js app with the n "service": "my-app", }, ], - "kv_namespaces": [ - // Create a KV binding with the binding name "NEXT_INC_CACHE_KV" - // to enable the KV based caching: + "r2_buckets": [ + // Create a R2 binding with the binding name "NEXT_INC_CACHE_R2_BUCKET" // { - // "binding": "NEXT_INC_CACHE_KV", - // "id": "" - // } + // "binding": "NEXT_INC_CACHE_R2_BUCKET", + // "bucket_name": "", + // }, ], } ``` @@ -79,7 +78,7 @@ You can create one yourself in the root directory of your Next.js app with the n date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/) to `2024-09-23` or later, in order for your Next.js app to work with @opennextjs/cloudflare - The `main` and `assets` values should also not be changed unless you modify the build output result in some way - You can add a binding - named `NEXT_INC_CACHE_KV` to make use of Next.js' caching as described in the [Caching + named `NEXT_INC_CACHE_R2_BUCKET` to make use of Next.js' caching as described in the [Caching docs](/cloudflare/caching) @@ -94,10 +93,10 @@ Add a [`open-next.config.ts`](https://opennext.js.org/aws/config) file to the ro ```ts import { defineCloudflareConfig } from "@opennextjs/cloudflare"; -import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; +import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"; export default defineCloudflareConfig({ - incrementalCache: kvIncrementalCache, + incrementalCache: r2IncrementalCache, }); ``` @@ -130,7 +129,7 @@ Add the following to the scripts field of your `package.json` file: - `npm run deploy`: Builds your app, and then deploys it to Cloudflare - `cf-typegen`: Generates a `cloudflare-env.d.ts` file at the root of your project containing [the types for the `env`](https://developers.cloudflare.com/workers/wrangler/commands/#types). -##### 7. Add caching with Workers KV +##### 7. Add caching with Cloudflare R2 See the [Caching docs](/cloudflare/caching) for information on enabling Next.js caching in your OpenNext project. diff --git a/pages/cloudflare/migrate-from-0.6-to-1.0.0-beta.mdx b/pages/cloudflare/migrate-from-0.6-to-1.0.0-beta.mdx new file mode 100644 index 0000000..521550c --- /dev/null +++ b/pages/cloudflare/migrate-from-0.6-to-1.0.0-beta.mdx @@ -0,0 +1,46 @@ +import { Callout } from "nextra/components"; + +### Migrate from 0.6 to 1.0.0-beta + +The codebase has been refactored with some breaking changes, read-on to update your apps: + +#### Name changes + +`DurableObjectQueueHandler` was renamed to `DOQueueHandler`. Durable object bindings should be updated in the wrangler configuration file. + +#### Environment variables + +`NEXT_CACHE_DO_QUEUE_MAX_NUM_REVALIDATIONS` was renamed to `NEXT_CACHE_DO_QUEUE_MAX_RETRIES`. + +#### API changes + +`D1TagCache` was removed. You should use `D1NextModeTagCache` instead which is more efficient and also based on D1. + +The `enableShardReplication` and `shardReplicationOptions` options passed to `ShardedDOTagCache` +have been folded into `shardReplication`. A value for `shardReplication` must be specified to enable +replications. The value must be an object with the number of soft and hard replicas. + +Before: + +```ts +shardedDOTagCache({ + baseShardSize: 4, + enableShardReplication: true, + shardReplicationOptions: { + numberOfSoftReplicas: 4, + numberOfHardReplicas: 2, + }, +}); +``` + +After: + +```ts +shardedDOTagCache({ + baseShardSize: 4, + shardReplication: { + numberOfSoftReplicas: 4, + numberOfHardReplicas: 2, + }, +}); +```