Skip to main content

Overview

Prisma provides the env() helper function to safely access environment variables in your configuration files. This replaces the env() function previously used in schema.prisma datasource blocks.

The env() Function

Import

import { env } from '@prisma/config'

Basic Usage

import { defineConfig, env } from '@prisma/config'

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL')
  }
})

Function Signature

function env(name: string): string

Parameters

name
string
required
The name of the environment variable to read.

Return Value

Returns the string value of the environment variable.

Errors

Throws PrismaConfigEnvError if:
  • The environment variable is not defined
  • The environment variable is an empty string

Error Handling

The env() function throws a PrismaConfigEnvError when an environment variable cannot be resolved:
import { env, PrismaConfigEnvError } from '@prisma/config'

try {
  const url = env('DATABASE_URL')
} catch (error) {
  if (error instanceof PrismaConfigEnvError) {
    console.error(`Missing environment variable: ${error.message}`)
  }
}
Error message format:
Cannot resolve environment variable: <VARIABLE_NAME>.

Loading Environment Variables

Prisma 7 does not automatically load .env files. You must load environment variables explicitly.

Using dotenv

Load environment variables using dotenv at the top of your config file:
import { defineConfig, env } from '@prisma/config'
import 'dotenv/config'

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL')
  }
})

Using dotenv with Custom Path

import { defineConfig, env } from '@prisma/config'
import { config } from 'dotenv'

// Load from custom .env file
config({ path: '.env.local' })

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL')
  }
})

Multiple Environment Files

import { defineConfig, env } from '@prisma/config'
import { config } from 'dotenv'

// Load multiple env files
config({ path: '.env' })
config({ path: '.env.local', override: true })

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL'),
    shadowDatabaseUrl: env('SHADOW_DATABASE_URL')
  }
})

Common Patterns

Database Connection URL

import { defineConfig, env } from '@prisma/config'
import 'dotenv/config'

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL')
  }
})
.env file:
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

Multiple Database URLs

import { defineConfig, env } from '@prisma/config'
import 'dotenv/config'

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL'),
    shadowDatabaseUrl: env('SHADOW_DATABASE_URL')
  }
})
.env file:
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
SHADOW_DATABASE_URL="postgresql://user:password@localhost:5432/shadow"

Environment-Specific Configuration

import { defineConfig, env } from '@prisma/config'
import 'dotenv/config'

const isProduction = process.env.NODE_ENV === 'production'

export default defineConfig({
  datasource: {
    url: env(isProduction ? 'PRODUCTION_DATABASE_URL' : 'DATABASE_URL')
  },
  migrations: {
    path: isProduction ? './migrations' : './dev-migrations'
  }
})

Direct Access to process.env

You can also access process.env directly for more complex logic:
import { defineConfig } from '@prisma/config'
import 'dotenv/config'

export default defineConfig({
  datasource: {
    url: process.env.DATABASE_URL || 'file:./dev.db'
  }
})
Using env() is recommended over direct process.env access because it provides better error messages when variables are missing.

Type Safety

Basic Type Safety

The env() function is typed to return string:
const url: string = env('DATABASE_URL')

Custom Environment Type

You can define a custom environment type for better autocomplete:
import { defineConfig, env } from '@prisma/config'
import 'dotenv/config'

interface Env {
  DATABASE_URL: string
  SHADOW_DATABASE_URL: string
  NODE_ENV: 'development' | 'production' | 'test'
}

export default defineConfig({
  datasource: {
    url: env<Env>('DATABASE_URL'),
    shadowDatabaseUrl: env<Env>('SHADOW_DATABASE_URL')
  }
})

Best Practices

1. Always Load Environment Variables First

// ✅ Good: Load dotenv before using env()
import { defineConfig, env } from '@prisma/config'
import 'dotenv/config'

export default defineConfig({
  datasource: { url: env('DATABASE_URL') }
})

// ❌ Bad: env() called before loading .env
import { defineConfig, env } from '@prisma/config'

export default defineConfig({
  datasource: { url: env('DATABASE_URL') }
})
import 'dotenv/config' // Too late!

2. Use env() for Required Variables

// ✅ Good: Use env() to ensure variable exists
export default defineConfig({
  datasource: {
    url: env('DATABASE_URL') // Throws if missing
  }
})

// ❌ Bad: Silent failure with fallback
export default defineConfig({
  datasource: {
    url: process.env.DATABASE_URL || '' // Empty string causes issues
  }
})

3. Provide Clear Variable Names

// ✅ Good: Descriptive names
env('DATABASE_URL')
env('SHADOW_DATABASE_URL')
env('PRISMA_QUERY_ENGINE_BINARY')

// ❌ Bad: Unclear names
env('DB')
env('URL')
env('VAR1')

4. Document Required Variables

Create a .env.example file to document all required environment variables:
# .env.example

# Database connection URL
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

# Shadow database for migrations
SHADOW_DATABASE_URL="postgresql://user:password@localhost:5432/shadow"

SQLite Connection URLs

SQLite database URLs are resolved relative to the config file location, not the schema file.
import { defineConfig, env } from '@prisma/config'
import 'dotenv/config'

// Config at /project/prisma.config.ts
export default defineConfig({
  datasource: {
    url: 'file:./dev.db' // Resolves to /project/dev.db
  }
})
.env file:
DATABASE_URL="file:./data/dev.db"

Platform-Specific Considerations

Vercel

import { defineConfig, env } from '@prisma/config'

export default defineConfig({
  datasource: {
    url: env('POSTGRES_PRISMA_URL') // Vercel Postgres connection pooler
  }
})

Railway

import { defineConfig, env } from '@prisma/config'

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL')
  }
})

Docker

import { defineConfig, env } from '@prisma/config'

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL') // Set via docker-compose.yml
  }
})
docker-compose.yml:
services:
  app:
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb

Troubleshooting

Variable Not Found

Error:
PrismaConfigEnvError: Cannot resolve environment variable: DATABASE_URL.
Solutions:
  1. Ensure .env file exists
  2. Verify dotenv is loaded before using env()
  3. Check variable name spelling
  4. Confirm variable is not empty

Empty String Values

Error:
PrismaConfigEnvError: Cannot resolve environment variable: DATABASE_URL.
Cause: The environment variable exists but is set to an empty string. Solution: Provide a non-empty value:
# ❌ Bad
DATABASE_URL=""

# ✅ Good
DATABASE_URL="postgresql://localhost:5432/mydb"

Variable Not Loaded

Symptom: env() throws error even though .env file exists. Solution: Ensure dotenv/config is imported:
import 'dotenv/config' // Must be at the top
import { defineConfig, env } from '@prisma/config'