npm package: @julr/vite-plugin-validate-env
Description: ✅ Vite plugin for validating your environment variables
Author: Julien Ripouteau
Latest version: 2.2.2

<p align="center">
  <img src="https://user-images.githubusercontent.com/8337858/188329992-e74b3393-5bec-48b3-bba9-a8c45d279866.png">
</p>

# vite-plugin-validate-env

A Vite plugin that validates your environment variables at **build** or **dev time**. This helps you catch misconfigurations early by [failing fast](https://en.wikipedia.org/wiki/Fail-fast). No more broken builds or 10 minutes of debugging just to realize you forgot a variable 🥲

---

## ✅ Features

- Validate environment variables **at build time only**, zero runtime overhead
- Fully **type-safe**
- Supports [standard-schema](https://github.com/standard-schema/standard-schema) — works with Zod, Valibot, ArkType, and more
- Built-in parsing, validation, and transformation
- Custom rules and error messages

---

## Installation

```sh
pnpm add -D @julr/vite-plugin-validate-env
```

## Basic Usage

You can use the plugin with the [built-in validator](https://github.com/poppinss/validator-lite) for simple use cases, or with libraries like Zod for more advanced schemas.

> [!TIP]
> I would recommend using a dedicated `env.ts` file to keep your Vite config clean and separate from your environment variable definitions. See the [Using a Dedicated `env.ts` Config File](#using-a-dedicated-envts-config-file) section for more details.

### Built-in Validator

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { Schema, ValidateEnv } from '@julr/vite-plugin-validate-env'

export default defineConfig({
  plugins: [
    ValidateEnv({
      validator: 'builtin',
      schema: {
        VITE_MY_VAR: Schema.string(),
      },
    }),
  ],
})
```

### Standard Schema Validators

If you want to use Zod or another validator compatible with [standard-schema](https://github.com/standard-schema/standard-schema), pass the `validator` and `schema` manually:

```ts
import { defineConfig } from 'vite'
import { z } from 'zod'
import { ValidateEnv } from '@julr/vite-plugin-validate-env'

export default defineConfig({
  plugins: [
    ValidateEnv({
      validator: 'standard', // 👈
      schema: {
        VITE_MY_VAR: z.string(),
      },
    }),
  ],
})
```

## Built-in Validator Examples

```ts
ValidateEnv({
  VITE_STRING: Schema.string(),
  VITE_NUMBER: Schema.number(),
  VITE_BOOLEAN: Schema.boolean(),
  VITE_ENUM: Schema.enum(['foo', 'bar'] as const),

  // Optional
  VITE_OPTIONAL: Schema.boolean.optional(),

  // With format and protocol checks
  VITE_API_URL: Schema.string({ format: 'url', protocol: true }),

  // With custom error message
  VITE_PORT: Schema.number({ message: 'You must set a port!' }),

  // Custom validator + transform function
  VITE_URL_SUFFIXED_WITH_SLASH: (key, value) => {
    if (!value) throw new Error(`Missing ${key}`)

    return value.endsWith('/') ? value : `${value}/`
  },
})
```

## Using Standard Schema

`standard-schema` provides a common interface for multiple validation libraries.

Here’s how to use it with Zod, Valibot, or ArkType, or any other library that supports it.

```ts
import { defineConfig } from '@julr/vite-plugin-validate-env'
import { z } from 'zod'
import * as v from 'valibot'
import { type } from 'arktype'

export default defineConfig({
  validator: 'standard',
  schema: {
    VITE_ZOD_VAR: z.string(),
    VITE_VALIBOT_VAR: v.string(),
    VITE_ARKTYPE_VAR: type.string(),
  },
})
```

## Using a Dedicated `env.ts` Config File

You can move your env definitions to a separate file like this:

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { ValidateEnv } from '@julr/vite-plugin-validate-env'

export default defineConfig({
  plugins: [
    ValidateEnv({
      // Optional: you can specify a custom path for the config file
      configFile: 'config/env',
    }),
  ],
})
```

```ts
// env.ts
import { defineConfig, Schema } from '@julr/vite-plugin-validate-env'

export default defineConfig({
  validator: 'builtin',
  schema: {
    VITE_MY_VAR: Schema.enum(['foo', 'bar'] as const),
  },
})
```

## Typing `import.meta.env`

In order to have a type-safe `import.meta.env`, the ideal is to use the dedicated configuration file `env.ts`.
Once this is done, you would only need to add an `vite-env.d.ts` in `src/` folder to augment `ImportMetaEnv` (as [suggested here](https://vitejs.dev/guide/env-and-mode.html#env-files) ) with the following content:

```ts
/// <reference types="vite/client" />

type ImportMetaEnvAugmented = import('@julr/vite-plugin-validate-env').ImportMetaEnvAugmented<
  typeof import('../env').default
>

interface ViteTypeOptions {
  // Avoid adding an index type to `ImportMetaDev` so
  // there's an error when accessing unknown properties.
  // ⚠️ This option requires Vite 6.3.x or higher
  strictImportMetaEnv: unknown
}

interface ImportMetaEnv extends ImportMetaEnvAugmented {
  // Now import.meta.env is totally type-safe and based on your `env.ts` schema definition
  // You can also add custom variables that are not defined in your schema
}
```

## Validation without Vite

In some cases, you might want to validate environment variables outside of Vite and reuse the same schema. You can do so by using the `loadAndValidateEnv` function directly. This function will validate and also load the environment variables inside the `process.env` object.

> [!WARNING]
> `process.env` only accept string values, so don't be surprised if a `number` or `boolean` variable comes back as a string when accessing it after validation.

```ts
import { loadAndValidateEnv } from '@julr/vite-plugin-validate-env'

const env = await loadAndValidateEnv(
  {
    mode: 'development', // required
    root: import.meta.dirname, // optional
  },
  {
    // Plugin options. Also optional if you
    // are using a dedicated `env.ts` file
    validator: 'builtin',
    schema: { VITE_MY_VAR: Schema.string() },
  },
)

console.log(env.VITE_MY_VAR)
console.log(process.env.VITE_MY_VAR)
```

## 💖 Sponsors

If you find this useful, consider [sponsoring me](https://github.com/sponsors/Julien-R44)! It helps support and maintain the project 🙏

<p align="center">
  <img src="https://github.com/julien-r44/static/blob/main/sponsorkit/sponsors.png?raw=true">
</p>

---

## License

MIT © [Julien Ripouteau](https://github.com/Julien-R44)