From 8b71f165e5155a21e2677c915be9685bafc7df4d Mon Sep 17 00:00:00 2001 From: Alexey Orlenko Date: Thu, 16 Oct 2025 11:40:51 +0200 Subject: [PATCH] feat(config): add `env` helper Add a helper that safely checks if an environment variable is defined and is not empty, and returns its value if so, otherwise throws an error. This allows users to avoid having boilerplate code related to environment variables in their config files or using unsafe assertions like `process.env.DATABASE_URL!`. Usage: ```ts import { defineConfig, env } from '@prisma/config' export default defineConfig({ engine: 'classic', datasource: { url: env('DATABASE_URL'), }, }) ``` Closes: https://linear.app/prisma-company/issue/TML-1508/env-helper-in-prismaconfig --- packages/config/src/__tests__/env.test.ts | 40 +++++++++++++++++++++++ packages/config/src/env.ts | 14 ++++++++ packages/config/src/index.ts | 1 + 3 files changed, 55 insertions(+) create mode 100644 packages/config/src/__tests__/env.test.ts create mode 100644 packages/config/src/env.ts diff --git a/packages/config/src/__tests__/env.test.ts b/packages/config/src/__tests__/env.test.ts new file mode 100644 index 000000000000..f3fd21d5d6fd --- /dev/null +++ b/packages/config/src/__tests__/env.test.ts @@ -0,0 +1,40 @@ +import { afterAll, beforeEach, describe, expect, test } from 'vitest' + +import { env, PrismaConfigEnvError } from '../env' + +const VAR_NAME = 'PRISMA_CONFIG_ENV_TEST' +const originalValue = process.env[VAR_NAME] + +describe('env', () => { + beforeEach(() => { + delete process.env[VAR_NAME] + }) + + afterAll(() => { + if (originalValue === undefined) { + delete process.env[VAR_NAME] + } else { + process.env[VAR_NAME] = originalValue + } + }) + + test('returns the value when the environment variable is defined', () => { + process.env[VAR_NAME] = 'postgresql://example' + expect(env(VAR_NAME)).toBe('postgresql://example') + }) + + test('throws when the environment variable is missing', () => { + expect(() => env(VAR_NAME)).toThrowError(PrismaConfigEnvError) + expect(() => env(VAR_NAME)).toThrowErrorMatchingInlineSnapshot( + `[PrismaConfigEnvError: Missing required environment variable: PRISMA_CONFIG_ENV_TEST]`, + ) + }) + + test('throws when the environment variable is an empty string', () => { + process.env[VAR_NAME] = '' + expect(() => env(VAR_NAME)).toThrowError(PrismaConfigEnvError) + expect(() => env(VAR_NAME)).toThrowErrorMatchingInlineSnapshot( + `[PrismaConfigEnvError: Missing required environment variable: PRISMA_CONFIG_ENV_TEST]`, + ) + }) +}) diff --git a/packages/config/src/env.ts b/packages/config/src/env.ts new file mode 100644 index 000000000000..99524a4ed1d2 --- /dev/null +++ b/packages/config/src/env.ts @@ -0,0 +1,14 @@ +export class PrismaConfigEnvError extends Error { + constructor(name: string) { + super(`Missing required environment variable: ${name}`) + this.name = 'PrismaConfigEnvError' + } +} + +export function env(name: string): string { + const value = process.env[name] + if (!value) { + throw new PrismaConfigEnvError(name) + } + return value +} diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts index a6c8e7b68c12..a473541c9914 100644 --- a/packages/config/src/index.ts +++ b/packages/config/src/index.ts @@ -1,5 +1,6 @@ export { defaultTestConfig } from './defaultTestConfig' export { defineConfig } from './defineConfig' +export { env, PrismaConfigEnvError } from './env' export type { ConfigDiagnostic, ConfigFromFile, InjectFormatters, LoadConfigFromFileError } from './loadConfigFromFile' export { loadConfigFromFile } from './loadConfigFromFile' export { loadConfigFromPackageJson } from './loadConfigFromPackageJson'