Functions, bindings, and operations

Bind resources and debug production

Inject D1, KV, R2, services, variables, and secrets through environment bindings, then verify production without exposing credentials.

8 minute lesson

~~~

Pages Functions access configured resources through context.env. A KV namespace, a D1 database, an R2 bucket, a service binding, plain variables, and secrets all arrive as properties on that object:

export async function onRequestGet(context) {
  const settings = await context.env.CONFIG.get('settings', 'json')
  return Response.json({ theme: settings?.theme ?? 'default' })
}

The binding name (CONFIG here) is configuration, defined per project and per environment. Preview and production can point the same name at different namespaces, which is exactly what you want — and exactly why you must test both targets separately. If you use TypeScript, regenerate types with npx wrangler types whenever bindings change.

The missing-binding failure

This is the error you will meet first:

TypeError: Cannot read properties of undefined (reading 'get')

context.env.CONFIG was undefined because the deployed environment has no binding with that name. Locally everything worked, because your local configuration had it. A successful local simulation does not prove the production binding exists or points at the intended resource. Check the project’s bindings for the specific environment before reading any stack trace further.

Secrets are not vars

Plain-text vars are for public values, like a Turnstile site key. Anything private goes into encrypted secrets, set per environment:

npx wrangler pages secret put RESEND_API_KEY --project-name my-site
# ✨ Success! Uploaded secret RESEND_API_KEY

Store secrets in encrypted project settings, not vars or source. For local development, put them in a gitignored .dev.vars file. Both appear identically as context.env.RESEND_API_KEY in code; only their storage differs.

Debug production without leaking it

Stream live Function logs from a deployment:

npx wrangler pages deployment tail --project-name my-site

Every request and console.log appears as it happens. Make those logs useful and safe: attach a request ID so you can follow one request, log the resource name you resolved, and return safe errors to clients — a generic 500 message outside, the detail in the log. Never log the secret values themselves.

Now bind a practice KV namespace to a Pages project, read one non-secret value from a Function, deploy, and verify from logs and safe metadata that production resolved the resource name and environment you intended.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →