Configuration

Environment Variables

Indie Starter uses @t3-oss/env-nextjs↗ along with zod↗ under the hood for validating environment variables at runtime and buildtime by providing a simple logic in src/env.js.

env.js

If you want to add a new environment variable, you must add a validator for it in src/env.js, and then add the KV-pair in .env.local

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  server: {
    NODE_ENV: z.enum(["development", "test", "production"]),
  },
  client: {
    // NEXT_PUBLIC_CLIENTVAR: z.string(),
  },
  runtimeEnv: {
    NODE_ENV: process.env.NODE_ENV,
  },
});

The boilerplate is generated by T3 and uses the createEnv function to create the schema validate both client and server-side environment variables.

Using Environment Variables

When you want to use your environment variables, you can import them from the created env.js and use them as you would normally do. If you import this on the client and try accessing a server-side environment variable, you will get a runtime error.

// app/api/hello.ts
import { env } from "@/env.js";

// `env` is fully typesafe and provides autocompletion
const dbUrl = env.DATABASE_URL;
// app/page.tsx
import { env } from "../env.js";

// ❌ This will throw a runtime error
const dbUrl = env.DATABASE_URL;

// ✅ This is fine
const wsKey = env.NEXT_PUBLIC_WS_KEY;

Adding Environment Variables

To ensure your build never completes without the environment variables the project needs, you will need to add new environment variables in two locations:

📄 .env.local: Enter your environment variable like you would normally do in a .env.local file, i.e. KEY=VALUE

📄 env.js: Add the appropriate validation logic for the environment variables by defining a Zod schema inside createEnv for each one, e.g. KEY: z.string(). Besides that, make sure to destruct them in the runtimeEnv option, e.g.: KEY: process.env.KEY

Why do I need to destructure the env variable in the `runtimeEnv`?

This is due to how Next.js bundles environment variables in certain runtimes. By destructuring it manually, you ensure that the variable will never be stripped out from the bundle.

Type Coercion

All variables you add to .env will be imported as strings, even if their value is intended to represent a different type. If you want to use your environment variables as a different type at runtime, you can use Zod’s coerce to convert the string to the type you want. It will throw if the coercion fails.

Add the variables to your .env.local:

SOME_NUMBER=123
SOME_BOOLEAN=true

Then, validate them in env.js:

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  server: {
    SOME_NUMBER: z.coerce.number(),
    SOME_BOOLEAN: z.coerce.boolean(),
  },
  // ...
  runtimeEnv: {
    SOME_NUMBER: process.env.SOME_NUMBER,
    SOME_BOOLEAN: process.env.SOME_BOOLEAN,
  },
});
Next
SEO