> ## Documentation Index
> Fetch the complete documentation index at: https://next-safe-env.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Use next-safe-env in Edge Runtime and Middleware

> Validate env vars for Vercel Edge Runtime and Next.js Middleware. Only NEXT_PUBLIC_ variables are available at runtime in the edge environment.

The Edge Runtime environment used by Next.js Middleware and Vercel Edge Functions is not a full Node.js process. It runs a Web API subset and only exposes `NEXT_PUBLIC_` variables at runtime - server-only secrets are never available there. `next-safe-env` provides a dedicated `edge` adapter that reflects this constraint: server vars are validated at startup but unconditionally stripped from the returned object, so your types match what is actually accessible.

<Steps>
  <Step title="Install next-safe-env">
    Add the package to your project.

    ```bash theme={null}
    npm install next-safe-env
    ```
  </Step>

  <Step title="Create your env config in middleware.ts">
    Define your schema with `adapter: 'edge'`. Keep the `server` schema empty or omit server vars - they are validated but never returned.

    ```typescript theme={null}
    // middleware.ts
    import { createEnv, str, url } from 'next-safe-env'

    export const env = createEnv({
      server: {},  // prefer empty - server vars are validated but stripped from the result
      client: {
        NEXT_PUBLIC_API_URL:  url(),
        NEXT_PUBLIC_APP_NAME: str().default('My App'),
      },
      runtimeEnv: {
        NEXT_PUBLIC_API_URL:  process.env.NEXT_PUBLIC_API_URL,
        NEXT_PUBLIC_APP_NAME: process.env.NEXT_PUBLIC_APP_NAME,
      },
      adapter: 'edge',
    })
    ```
  </Step>

  <Step title="Use env in your middleware logic">
    After `createEnv` runs, only `NEXT_PUBLIC_` vars are present on the returned object. Access them directly.

    ```typescript theme={null}
    // middleware.ts (continued)
    import { NextResponse } from 'next/server'
    import type { NextRequest } from 'next/server'

    export function middleware(request: NextRequest) {
      const apiUrl = env.NEXT_PUBLIC_API_URL    // string
      const appName = env.NEXT_PUBLIC_APP_NAME  // string

      // use apiUrl or appName in your middleware logic
      return NextResponse.next()
    }
    ```
  </Step>
</Steps>

## Edge adapter behavior

The `edge` adapter applies two rules to the validation pipeline:

**Before validation** - if your `server` schema contains any keys, the adapter emits a `console.warn` to alert you that those vars will not be accessible:

```
[next-safe-env] Edge adapter: server vars (API_SIGNING_KEY) will be validated
but stripped from the result - they are not accessible in Edge Runtime.
```

Validation still runs for those server vars. If a server var is required and missing, `createEnv` still fails at startup with a validation error. The warning is informational, not a skip.

**After validation** - the adapter unconditionally strips every key that does not start with `NEXT_PUBLIC_` from the returned object. This always happens, regardless of `typeof window`, because the Edge Runtime has no `window` object.

<Warning>
  Do not put secrets in your `server` schema when using the `edge` adapter. They are validated but never returned, so accessing them on the `env` object at runtime will yield `undefined` despite passing validation. Keep your edge `server` schema empty, or move secrets to a separate `createEnv` call used only in a Node.js context.
</Warning>

## Edge adapter vs nextjs adapter

Both adapters strip server vars from the result, but they do so under different conditions:

| Adapter  | When server vars are stripped                             |
| -------- | --------------------------------------------------------- |
| `nextjs` | Only in browser context (`typeof window !== 'undefined'`) |
| `edge`   | Always, unconditionally                                   |

Use `adapter: 'nextjs'` for App Router routes and Server Components, where you need server vars to be available in the Node.js context. Use `adapter: 'edge'` in `middleware.ts` and any Vercel Edge Function, where server vars are structurally inaccessible regardless of context.

<Tip>
  Set `adapter: 'edge'` explicitly rather than relying on auto-detection. The auto-detection heuristic selects `edge` when `process` is undefined or has no `version`, but Middleware runs in a constrained environment where the detection can be ambiguous. Being explicit makes your intent clear and avoids unexpected adapter selection.
</Tip>
