Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cloudflare/vinext/llms.txt

Use this file to discover all available pages before exploring further.

Route Segment Config

Route segment config options allow you to configure the behavior of a Page, Layout, or Route Handler by exporting constants.

Usage

Export configuration constants from page.tsx, layout.tsx, or route.ts:
export const dynamic = 'auto'
export const revalidate = 3600

export default function Page() {
  return <div>My Page</div>
}

Options

dynamic

Type: 'auto' | 'force-dynamic' | 'force-static' | 'error'
Default: 'auto'
Control static/dynamic rendering behavior.
export const dynamic = 'force-dynamic'

export default function Page() {
  return <div>Always server-rendered</div>
}

Values

'auto' (default)
Automatic detection. Use static rendering unless dynamic APIs are called.
'force-dynamic'
Force dynamic rendering. Page is always server-rendered on each request.
Sets Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate header.
export const dynamic = 'force-dynamic'

export default async function Dashboard() {
  const user = await getCurrentUser()
  return <div>Welcome, {user.name}</div>
}
'force-static'
Force static rendering. Page is rendered once at build time.
Sets Cache-Control: public, max-age=31536000, immutable header.
export const dynamic = 'force-static'

export default function About() {
  return <div>About us</div>
}
'error'
Throw error if dynamic APIs are used. Useful to ensure pages remain fully static.
export const dynamic = 'error'

export default function Terms() {
  // This would throw an error:
  // const headers = await headers()
  
  return <div>Terms of service</div>
}

revalidate

Type: number | false
Default: false
Time in seconds until the page is revalidated (ISR).
export const revalidate = 60 // Revalidate every 60 seconds

export default async function BlogPost({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  const post = await getPost(slug)
  return <article>{post.content}</article>
}

Values

false (default)
No revalidation. Cached indefinitely (or until manually invalidated).
0
No caching. Equivalent to dynamic = 'force-dynamic'.
number
Revalidate after N seconds. Uses stale-while-revalidate strategy:
  • Cached responses served instantly
  • Background revalidation triggered after expiry
  • New version served on next request after revalidation completes

Route Handlers

Route handlers support revalidate for ISR:
export const revalidate = 60

export async function GET() {
  const posts = await getPosts()
  return Response.json(posts)
}
Sets Cache-Control: s-maxage=60, stale-while-revalidate header.

dynamicParams

Type: boolean
Default: true
Control behavior for dynamic routes not generated by generateStaticParams.
export const dynamicParams = false

export async function generateStaticParams() {
  return [
    { slug: 'post-1' },
    { slug: 'post-2' }
  ]
}

export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  // Only post-1 and post-2 are valid
  // Other slugs will 404
  return <div>Post: {slug}</div>
}

Values

true (default)
Dynamic segments not in generateStaticParams are generated on-demand.
false
Dynamic segments not in generateStaticParams return 404.

runtime

Not supported. vinext runs on a single runtime (Node.js dev server or Cloudflare Workers in production). This option is ignored.
Next.js uses this to switch between Node.js and Edge runtimes. vinext deploys everything to the same environment.
// This is ignored in vinext
export const runtime = 'edge'

export async function GET() {
  return Response.json({ message: 'Hello' })
}

preferredRegion

Not supported. Cloudflare Workers deploy globally by default. This option is ignored.
Next.js uses this for Vercel’s regional deployments. On Cloudflare Workers, all code runs on the edge globally.
// This is ignored in vinext
export const preferredRegion = 'iad1'

export async function GET() {
  return Response.json({ message: 'Hello' })
}

Combining Options

You can export multiple segment config options:
export const dynamic = 'force-static'
export const revalidate = 3600
export const dynamicParams = true

export async function generateStaticParams() {
  return [{ id: '1' }, { id: '2' }]
}

export default async function Products() {
  const products = await getProducts()
  return <div>{/* ... */}</div>
}

ISR with Cache Handler

For production ISR, set a cache handler:
import { KVCacheHandler } from 'vinext/cloudflare'
import { setCacheHandler } from 'next/cache'
import handler from 'vinext/server/app-router-entry'

interface Env {
  VINEXT_CACHE: KVNamespace
}

export default {
  async fetch(request: Request, env: Env) {
    setCacheHandler(new KVCacheHandler(env.VINEXT_CACHE))
    return handler.fetch(request)
  }
}
See KV Cache Handler for details.

Cache-Control Headers

Route segment config automatically sets appropriate Cache-Control headers:
ConfigCache-Control
dynamic: 'force-dynamic'private, no-cache, no-store, max-age=0, must-revalidate
dynamic: 'force-static'public, max-age=31536000, immutable
revalidate: 60s-maxage=60, stale-while-revalidate
revalidate: falseNo cache header (default)

Type Safety

Import types for route segment config:
import type { Metadata } from 'vinext'

export const dynamic = 'force-dynamic' as const
export const revalidate = 60

export const metadata: Metadata = {
  title: 'My Page'
}

export default function Page() {
  return <div>Page</div>
}