β Invalid environment variables: { DATABASE_URL: [ 'Required' ] }
This error means T3 Env (the @t3-oss/env-nextjs or @t3-oss/env-core package) validated your environment variables at build time and found missing or invalid values. The validation uses Zod schemas, so the error message tells you exactly which variable failed and why.
What causes this
T3 Env runs validation when your app starts or builds. If a variable defined in your schema is missing from .env, has the wrong format (e.g., not a valid URL), or isnβt mapped in runtimeEnv, the validation throws.
Common triggers:
- You added a new variable to the schema but forgot to add it to
.env - Your
.envfile isnβt being loaded (wrong location or wrong filename) - A
NEXT_PUBLIC_variable isnβt mapped in theruntimeEnvobject - Youβre deploying to CI/CD and the env vars arenβt set there
Fix 1: Add the missing variable to .env
Check the error message β it tells you which variable is missing. Add it:
# .env
DATABASE_URL="[postgresql](/blog/what-is-postgresql/)://user:password@localhost:5432/mydb"
NEXT_PUBLIC_APP_URL="http://localhost:3000"
Make sure the .env file is in the project root (next to package.json), not inside src/.
Fix 2: Check your env schema matches reality
Your schema must match what you actually provide. If a variable is optional in practice, mark it as optional in the schema:
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url().optional(), // Not always needed
},
client: {
NEXT_PUBLIC_APP_URL: z.string().url(),
},
runtimeEnv: {
DATABASE_URL: process.env.DATABASE_URL,
REDIS_URL: process.env.REDIS_URL,
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
},
});
Every variable in server and client must also appear in runtimeEnv. Missing a mapping there is a common mistake.
Fix 3: Skip validation in CI/Docker builds
During CI builds or Docker image creation, you often donβt have runtime env vars available. Skip validation for those environments:
export const env = createEnv({
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
// ... rest of config
});
Then in your CI pipeline:
SKIP_ENV_VALIDATION=1 npm run build
Fix 4: Check for .env.local overrides
Next.js loads .env.local after .env, and it takes precedence. If you have conflicting values:
# Check which files exist
ls -la .env*
The load order is: .env β .env.local β .env.development β .env.development.local. A variable set to an empty string in a later file will override a valid value from an earlier one.
How to prevent it
- Keep a
.env.examplefile in version control with all required variables (without real values). New team members copy it to.envand fill in the values. - Add
SKIP_ENV_VALIDATION=1to your CI environment so builds donβt fail on missing runtime secrets. - Use
.optional()or.default()in your Zod schema for variables that arenβt always required.