Skip to content

v4.0.1

Choose a tag to compare

@github-actions github-actions released this 10 Dec 08:41
· 33 commits to main since this release

next-dynenv v4.0.1 ✨

Build once, deploy anywhere. This major release brings full Next.js 15/16 support, a complete rebrand, and powerful new features for type-safe runtime environment variables.


🎯 Highlights

  • Next.js 15 & 16 Ready — Full compatibility with the latest Next.js and React 19
  • New Identity — Rebranded from next-runtime-env to next-dynenv
  • Type-Safe Parsers — Boolean, number, array, JSON, URL, and enum parsers with full TypeScript inference
  • Enhanced Security — XSS protection and frozen window.__ENV object
  • Modern Tooling — ESM-first, Biome + Prettier, Vitest test framework
  • Trusted Publishing — OIDC-based npm publishing with provenance

⬆️ Next.js 15/16 Migration

New Dynamic Rendering APIs

Replaced deprecated unstable_noStore with modern Next.js APIs:

// PublicEnvScript & PublicEnvProvider now use:
import { connection } from 'next/server'
await connection()

// env() uses headers() as a side-effect for dynamic rendering
import { headers } from 'next/headers'

Async Server Components

All server components are now properly async for React 19:

// Before (Next.js 14)
export function MyComponent() {
  const apiUrl = env('API_URL')
  return <div>{apiUrl}</div>
}

// After (Next.js 15+)
export async function MyComponent() {
  const apiUrl = env('API_URL')
  return <div>{apiUrl}</div>
}

ESM Package

The package is now native ESM with "type": "module":

{
  "type": "module",
  "exports": {
    ".": {
      "types": "./build/index.d.ts",
      "import": "./build/index.js"
    }
  }
}

🔒 Type-Safe Environment Parsers

New envParsers module for validated, type-safe environment variables:

import { env, envParsers } from 'next-dynenv'

// Boolean parsing
const debug = envParsers.boolean(env('DEBUG'))  // true/false

// Number parsing
const port = envParsers.number(env('PORT'))  // number

// Array parsing
const hosts = envParsers.array(env('ALLOWED_HOSTS'))  // string[]

// JSON parsing with type inference
const config = envParsers.json<AppConfig>(env('CONFIG'))

// URL validation
const apiUrl = envParsers.url(env('API_URL'))  // URL object

// ✨ NEW: Enum validation
type Env = 'development' | 'staging' | 'production'
const nodeEnv = envParsers.enum<Env>(env('NODE_ENV'), [
  'development', 'staging', 'production'
])

Required Variables with requireEnv()

import { requireEnv } from 'next-dynenv'

// Throws if undefined
const apiKey = requireEnv('API_KEY')

Default Values

import { env } from 'next-dynenv'

// Returns default if undefined
const timeout = env('TIMEOUT', '5000')

🛡️ Security Enhancements

XSS Protection

Script injection is now protected against </script> attacks:

// Malicious input: "</script><script>alert('xss')</script>"
// Safely escaped in the injected script tag

Frozen Environment Object

window.__ENV is now frozen to prevent tampering:

// Attempting to modify throws in strict mode
window.__ENV.API_KEY = 'hacked'  // ❌ TypeError

📦 Package Rebrand

The package has been renamed for clarity and discoverability:

- npm install next-runtime-env
+ npm install next-dynenv
- import { env } from 'next-runtime-env'
+ import { env } from 'next-dynenv'

🧪 Testing Infrastructure

Vitest Migration

Replaced Jest with Vitest for faster, ESM-native testing:

pnpm test          # Run tests
pnpm test:watch    # Watch mode
pnpm test:coverage # Coverage report

Integration Tests

New end-to-end integration test validates the core promise:

pnpm test:integration

Verifies:

  • ✓ Runtime values override build-time values
  • ✓ window.__ENV injection works correctly
  • ✓ Standalone mode fully functional
  • ✓ Both script and context provider approaches work

🔧 Modern Tooling

Biome + Prettier

  • Biome — Fast Rust-based linting and formatting for TypeScript/JavaScript
  • Prettier — Markdown, YAML, and JSON formatting only
  • 10x faster linting, unified tooling, 12 fewer dependencies
pnpm lint      # Check
pnpm lint:fix  # Auto-fix

CI/CD Overhaul

  • Parallel job execution for faster builds
  • Matrix testing across Node 18, 20, 22
  • Codecov integration
  • GitHub Actions summaries
  • Trusted npm publishing with OIDC provenance

📚 Documentation

New VitePress Site

Beautiful documentation with:

  • Getting Started guide
  • API reference
  • Deployment examples (Docker, Kubernetes, Vercel, Netlify)
  • Troubleshooting guide

AI-Ready

Added llms.txt generation for AI/LLM contextual understanding.


💔 Breaking Changes

Node.js Requirement

{
  "engines": {
    "node": ">=20.9.0"
  }
}

Peer Dependencies

{
  "peerDependencies": {
    "next": "^15 || ^16",
    "react": "^19"
  }
}

Package Name

Update your imports:

- import { env, PublicEnvScript } from 'next-runtime-env'
+ import { env, PublicEnvScript } from 'next-dynenv'

🙏 Attribution

This project is a fork of next-runtime-env by Expatfile.tax LLC. All credit for the original implementation goes to them. This fork exists to provide continued maintenance and Next.js 15+ support.


📋 Full Changelog

Features

  • ✨ Migrate to Next.js 15 dynamic rendering APIs
  • ✨ Add type-safe env parsers (boolean, number, array, json, url)
  • ✨ Add enum parser for validated environment variables
  • ✨ Add requireEnv() for required variables
  • ✨ Add default value support to env()
  • 🔒 Add XSS protection for script injection
  • 🔒 Freeze window.__ENV with Object.freeze()

Infrastructure

  • ⬆️ Upgrade to Next.js 16 with ESM module system
  • 📦 Rename package to next-dynenv
  • ✅ Migrate from Jest to Vitest
  • ⚡ Modernize tooling with Biome + Prettier
  • ♻️ Refactor CI workflows for parallel execution
  • 🔧 Add pnpm workspace configuration
  • 🧪 Add integration test with real Next.js app

Documentation

  • 📚 Add VitePress documentation site
  • 📝 Comprehensive documentation overhaul
  • 📝 Add llms.txt plugin for AI context
  • 📝 Improve SEO metadata

Fixes

  • 🐛 Fix client-side bundling issue in env-script component
  • 🐛 Improve error handling for headers() outside request scope
  • 🐛 Fix makeEnvPublic() to prevent double-prefixing

Full Commit History: de82ca4...HEAD