Environment Variables
How to handle environment variables in next-forge
next-forge uses @t3-oss/env-nextjs to handle environment variables in a type-safe way. This provides runtime validation and autocompletion for all environment variables.
Overview
Environment variables are defined and validated in packages/env/index.ts
. The file exports an env
object that contains all validated environment variables, separated into server
and client
variables.
Initial setup
App Environment Variables
As part of the initial setup, you will need to fill in the environment variables in each .env.local
file in each Next.js application, specifically app
, web
and api
.
The initial setup script will copy these .env.example
files to .env.local
files, so all you need to do is fill in the variables.
Check out the packages/env/index.ts
file to see the validation rules for each variable.
For FLAGS_SECRET
, you can run node -e "console.log(crypto.randomBytes(32).toString('base64url'))"
or openssl rand -base64 32
in your terminal to generate a random value.
Some environment variables will be added by integrations and other tooling. For example, environment variables prefixed with SENTRY_
are automatically added to a Vercel project when you add the Sentry integration from the Vercel Marketplace. Additionally, NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL
is a very handy environment variable that refers to the “production” URL to which this project is deployed on Vercel.
Database Environment Variable
You also need to configure a .env
file in the packages/database
directory. This file should be created by the setup script, so just add your DATABASE_URL
and you should be good to go.
Adding a variable
To add a new environment variable, you need to do two things:
- Add the variable to each of the
.env.local
files across the repo - Add the variable to the
server
orclient
object inpackages/env/index.ts
. The variable will be validated using Zod, so you can use any of the Zod validation primitives.
I recommend being as specific as possible with your validation. For example, if you know that a vendor secret starts with sec_
, you should validate it as z.string().min(1).startsWith('sec_')
. This will not only make your intent clearer to anyone reading your code, but will also help prevent errors at runtime.