---
title: "Environment variables"
description: "What .env.local holds for the Nuxt app, the variables the Convex deployment declares, and how to set each one."
canonical_url: "https://nuxt-backend.dev/docs/reference/configuration/environment-variables"
---
# Environment variables

> What .env.local holds for the Nuxt app, the variables the Convex deployment declares, and how to set each one.

## App variables

`.env.local` is grouped by what each value is for — the shape `npx nuxt-backend init` writes. Nothing in it is required in dev:

```bash [.env.local]
# ── Backend ──────────────────────────────────────────────────────────────────
# Normally derived. Set these only to point at another deployment.
# NUXT_PUBLIC_BACKEND_URL=
# NUXT_PUBLIC_BACKEND_SITE_URL=

# ── Email ────────────────────────────────────────────────────────────────────
# Unset: sends no-op and OTP codes print in the backend dev console.
# EMAIL_API_KEY=
# EMAIL_FROM=
# EMAIL_TEST_MODE=
# EMAIL_WEBHOOK_SECRET=

# ── Billing ──────────────────────────────────────────────────────────────────
# Unset: billing reads return empty and checkout fails on invocation.
# BILLING_ACCESS_TOKEN=
# BILLING_ENVIRONMENT=
# BILLING_WEBHOOK_SECRET=

# ── Dev only ─────────────────────────────────────────────────────────────────
# Also trust the http://localhost:* origin the dev server runs on, in addition
# to SITE_URL. `env push` forwards this to dev deployments, never to production.
# AUTH_TRUST_LOCAL_ORIGINS=1

# Deployment used by `npx convex dev`
CONVEX_DEPLOYMENT=dev:your-deployment # team: your-team, project: your-project
```

Only `NUXT_PUBLIC_BACKEND_URL` and `NUXT_PUBLIC_BACKEND_SITE_URL` are read by the Nuxt process. The `EMAIL_*` and `BILLING_*` values are staged here for `npx nuxt-backend env push` to forward to the deployment ([deployment variables](#convex-deployment-variables) below). `CONVEX_DEPLOYMENT` and the comment above it are appended after those groups by `npx convex dev`, which also reads them — the module only reads the slug, to derive the two URLs from it.

<note>

The platform's own names still work. `NUXT_PUBLIC_CONVEX_URL` and `NUXT_PUBLIC_CONVEX_SITE_URL` are read directly by the underlying Convex module, and an explicitly set one wins over a derived default — `NUXT_PUBLIC_BACKEND_*` are simply this package's own names for them, and dev startup nudges you to the neutral name when only a platform name is set.

</note>

## Convex deployment variables

The backend declares ten deployment variables in two tiers (plus one dev-only flag, below). The scaffolded `convex.config.ts` **declares** them via Convex's typed [`defineApp({ env })`](https://docs.convex.dev/production/environment-variables) (`backendEnv` from `nuxt-backend/app`), so they're validated at deploy and read type-safely through `env` from `_generated/server`. `AUTH_SECRET` and `SITE_URL` are **required** — a push fails until both are set. Everything else is **optional**: the deploy succeeds and the feature degrades in a designed, observable way until configured (`npx nuxt-backend doctor` reports each). The names are service-neutral on purpose: the package hides its underlying providers behind the general capability.

<table>
<thead>
  <tr>
    <th>
      Variable
    </th>
    
    <th>
      Feature
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        AUTH_SECRET
      </code>
    </td>
    
    <td>
      Auth (required)
    </td>
    
    <td>
      Secret used to sign auth tokens (e.g. <code>
        openssl rand -base64 32
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        SITE_URL
      </code>
    </td>
    
    <td>
      Auth (required)
    </td>
    
    <td>
      App URL such as <code>
        https://nuxt-backend.localhost
      </code>
      
       — the auth base URL, the only trusted browser origin, and the base of emailed invitation links
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EMAIL_API_KEY
      </code>
    </td>
    
    <td>
      Email (powered by Resend)
    </td>
    
    <td>
      The provider API key — unset, email sends no-op, and sign-in codes and invitations to real addresses are refused (<code>
        NUXT_BACKEND_LOG_OTP=1
      </code>
      
       echoes codes to the <code>
        convex dev
      </code>
      
       console)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EMAIL_FROM
      </code>
    </td>
    
    <td>
      Email
    </td>
    
    <td>
      Sender address, e.g. <code>
        Acme <hello@yourdomain.com>
      </code>
      
       — defaults to the provider's onboarding sender
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EMAIL_TEST_MODE
      </code>
    </td>
    
    <td>
      Email
    </td>
    
    <td>
      <code>
        true
      </code>
      
       (the default) delivers only to the provider's test addresses; set to <code>
        false
      </code>
      
       once your sending domain is verified
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EMAIL_WEBHOOK_SECRET
      </code>
    </td>
    
    <td>
      Email
    </td>
    
    <td>
      Verifies delivery-event webhooks at <code>
        /email/events
      </code>
      
       — unset, events are rejected and <code>
        useEmailStatus
      </code>
      
       stays at <code>
        sent
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BILLING_ACCESS_TOKEN
      </code>
    </td>
    
    <td>
      Billing (powered by Polar)
    </td>
    
    <td>
      The provider organization access token — unset, billing queries return empty and checkout actions fail on invocation
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BILLING_WEBHOOK_SECRET
      </code>
    </td>
    
    <td>
      Billing
    </td>
    
    <td>
      Verifies billing webhooks at <code>
        /billing/events
      </code>
      
       — unset, events are rejected and entitlements refresh only on demand (<code>
        syncEntitlements
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BILLING_ENVIRONMENT
      </code>
    </td>
    
    <td>
      Billing
    </td>
    
    <td>
      <code>
        sandbox
      </code>
      
       (the default) or <code>
        production
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        AUTH_TRUST_LOCAL_ORIGINS
      </code>
    </td>
    
    <td>
      Auth (dev only)
    </td>
    
    <td>
      Set to <code>
        1
      </code>
      
       on a <strong>
        dev
      </strong>
      
       deployment to also trust <code>
        http://localhost:*
      </code>
      
       / <code>
        http://127.0.0.1:*
      </code>
      
       as browser origins (the Nuxt dev server's own port). <code>
        env push
      </code>
      
       forwards it to dev deployments only; never set it in production
    </td>
  </tr>
</tbody>
</table>

`NUXT_BACKEND_LOG_OTP` is the one deployment variable you may set that `backendEnv` does not declare (the platform itself provides `CONVEX_SITE_URL`), and it is dev-only: `npm run dev` (or `npx nuxt-backend env push`) sets it to `1` on a dev deployment that has no `EMAIL_API_KEY`, and while it is `1` the OTP sender prints each code to the `convex dev` console instead of throwing. Any other value, `false` included, leaves codes out of the logs. It is inert once `EMAIL_API_KEY` is set, and `env push` never sets it on a non-dev deployment.

### Setting them

On a dev deployment `npm run dev` (or `npx nuxt-backend env push`) provisions the required pair and forwards whatever `.env.local` holds. Explicitly, with each secret asked for at a hidden prompt (or piped in), so it never lands in your shell history:

```bash
# Required
openssl rand -base64 32 | npx convex env set AUTH_SECRET
npx convex env set SITE_URL https://nuxt-backend.localhost
# Optional — as you connect services
npx convex env set EMAIL_API_KEY           # asks for the key
npx convex env set EMAIL_FROM "Acme <hello@yourdomain.com>"
npx convex env set EMAIL_TEST_MODE true
npx convex env set EMAIL_WEBHOOK_SECRET    # asks for the secret
npx convex env set BILLING_ACCESS_TOKEN    # asks for the token
npx convex env set BILLING_WEBHOOK_SECRET  # asks for the secret
npx convex env set BILLING_ENVIRONMENT sandbox
```

<note>

The `EMAIL_*` vars are forwarded to the `backend` component by reference, since [components can't read the app's env directly](https://docs.convex.dev/components). The scaffolded `convex.config.ts` handles this for you — see [Backend components overview](https://nuxt-backend.dev/docs/start/concepts/how-it-works).

</note>


## Sitemap

See the full [sitemap](https://nuxt-backend.dev/sitemap.md) for all pages.
