Skip to content

envParsers ​

Turn environment strings into booleans, numbers, lists, JSON, URLs, and enums, with error messages that name the variable.

Import ​

ts
import { envParsers } from 'next-dynenv'

At a glance ​

ParserReturnsNot setInvalid
boolean(key, default = false)booleandefaultdefault
number(key, default = 0)numberdefaultThrows
array(key, default = [])string[]defaultNever invalid
json<T>(key, default?)Tdefault, or throwsThrows
url(key, default?)stringdefault, or throwsThrows
enum<T>(key, allowed, default?)Tdefault, or throwsThrows

"Not set" means undefined. Empty strings differ per parser: boolean and number treat blank values as not set, array returns [], and json, url, and enum throw.

Parsers read through env()

Every parser calls env(), so the same rules apply. In client components, use NEXT_PUBLIC_ keys and render PublicEnvScript or EnvScript. With the context approach, parse the strings from useEnvContext() yourself.

boolean() ​

ts
envParsers.boolean(key: string, defaultValue?: boolean): boolean

Trims and lowercases the value, then checks it against the truthy list.

ValueResult
true, 1, yes, on (any case)true
Any other value, including ''false
Not setdefaultValue (false unless passed)

Never throws. The default only applies when the variable is missing, so FLAG= turns a default-on flag off.

ts
const debug = envParsers.boolean('NEXT_PUBLIC_DEBUG')
// Opt-out flag: on unless the variable is set to something other than a truthy value
const analytics = envParsers.boolean('NEXT_PUBLIC_ANALYTICS', true)

number() ​

ts
envParsers.number(key: string, defaultValue?: number): number

Converts with Number() and rejects anything that is not finite.

ValueResult
3000, 423000, 42
3.14, -42, 1e3, 0x103.14, -42, 1000, 16
'' or whitespace onlydefaultValue (0 unless passed)
Not setdefaultValue
abc, 3000px, InfinityThrows
text
Environment variable 'NEXT_PUBLIC_PAGE_SIZE' is not a valid number: 'abc'.
Expected a numeric value like '3000' or '3.14'.
ts
const pageSize = envParsers.number('NEXT_PUBLIC_PAGE_SIZE', 20)
const timeoutMs = envParsers.number('NEXT_PUBLIC_TIMEOUT_MS', 5000)

Range checks stay yours: number() accepts -1 and 2.5 for a page size.

array() ​

ts
envParsers.array(key: string, defaultValue?: string[]): string[]

Splits on commas, trims each item, and drops empty items. Never throws for its content.

ValueResult
auth,payments,search['auth', 'payments', 'search']
auth , payments ,['auth', 'payments']
''[]
Not setdefaultValue ([] unless passed)
ts
const features = envParsers.array('NEXT_PUBLIC_FEATURES')

if (features.includes('payments')) {
    // render checkout
}

Items cannot contain commas. Use json() for anything richer.

json() ​

ts
envParsers.json<T = unknown>(key: string, defaultValue?: T): T

Parses with JSON.parse. The generic is a cast, not a check, so validate the shape when it matters.

ts
import { envParsers } from 'next-dynenv'
import { z } from 'zod'

const Flags = z.object({ checkout: z.boolean(), search: z.boolean() })

// NEXT_PUBLIC_FLAGS={"checkout":true,"search":false}
const flags = Flags.parse(envParsers.json('NEXT_PUBLIC_FLAGS', { checkout: false, search: false }))

Throws when the value is not set and there is no default:

text
Required environment variable 'NEXT_PUBLIC_FLAGS' is not defined.
Expected a JSON string value.

And when the value is not valid JSON (including ''):

text
Environment variable 'NEXT_PUBLIC_FLAGS' is not valid JSON: '{checkout:true}'.
Expected a valid JSON string like '{"key":"value"}'.

url() ​

ts
envParsers.url(key: string, defaultValue?: string): string

Checks the value with new URL() and returns the original string unchanged, so https://api.example.com stays without the trailing slash new URL() would add. Any absolute URL passes, including postgres:// and mailto: schemes. Relative paths such as /api throw. The default is returned as is, without validation.

ts
const apiUrl = envParsers.url('NEXT_PUBLIC_API_URL')
const cdnUrl = envParsers.url('NEXT_PUBLIC_CDN_URL', 'https://cdn.example.com')
text
Required environment variable 'NEXT_PUBLIC_API_URL' is not defined.
Expected a valid URL.
text
Environment variable 'NEXT_PUBLIC_API_URL' is not a valid URL: 'api.example.com'.
Expected a valid URL like 'https://example.com'.

enum() ​

ts
envParsers.enum<T extends string>(key: string, allowedValues: readonly T[], defaultValue?: T): T

Returns the value when it exactly matches one of allowedValues. Matching is case-sensitive, so Production fails against 'production'. TypeScript infers T from the list; the default is typed against it but not checked at runtime.

ts
const stage = envParsers.enum('NEXT_PUBLIC_STAGE', ['development', 'staging', 'production'] as const, 'development')
// stage: 'development' | 'staging' | 'production'
text
Required environment variable 'NEXT_PUBLIC_STAGE' is not defined.
Expected one of: 'development', 'staging', 'production'.
text
Environment variable 'NEXT_PUBLIC_STAGE' has invalid value: 'prod'.
Expected one of: 'development', 'staging', 'production'.

Putting it together ​

Read config inside a function so values come from the request-time environment, not from whenever the module first loaded.

ts
// lib/public-config.ts
import { envParsers } from 'next-dynenv'

export function getPublicConfig() {
    return {
        apiUrl: envParsers.url('NEXT_PUBLIC_API_URL'),
        debug: envParsers.boolean('NEXT_PUBLIC_DEBUG'),
        features: envParsers.array('NEXT_PUBLIC_FEATURES'),
        pageSize: envParsers.number('NEXT_PUBLIC_PAGE_SIZE', 20),
        stage: envParsers.enum('NEXT_PUBLIC_STAGE', ['development', 'staging', 'production'] as const, 'development'),
    }
}

Catch errors with a narrowed type to report them your way:

ts
try {
    getPublicConfig()
} catch (error) {
    if (error instanceof Error) {
        console.error(`Config error: ${error.message}`)
    }
    throw error
}

Released under the MIT License. Forked from next-runtime-env by Expatfile.tax LLC.