envsafe

repository·main·Indexed 21 days ago

https://github.com/katt/envsafe

A TypeScript-first library for validating and parsing environment variables in Node.js and browser environments. It ensures applications do not run with missing or invalid configuration by providing type-safe access via a schema-based approach. Features include built-in validators for strings, booleans, numbers, ports, URLs, emails, and JSON, as well as support for custom validators, default values (including development-specific defaults), and strict mode for JavaScript projects.

Tokens
4.6K
Snippets
19
Records
25
Agent score
72%

What's inside envsafe

  1. Enable strict mode for JavaScript projects

    main

    In TypeScript, envsafe returns a Readonly<T> which prevents accessing undefined properties. In vanilla JavaScript, you can still access undefined environment variables. To prevent this, enable strict: true in the options object. This wraps the result in Object.freeze and a Proxy that throws an error if you attempt to access a property that was not defined in your schema.

    import { envsafe, str } from 'envsafe';
    
    export const browserEnv = envsafe(
      {
        MY_ENV: str(),
      },
      {
        strict: true,
      },
    );
  2. Basic usage of envsafe

    main

    Use envsafe to define a schema for your environment variables. It validates the presence and type of variables, providing defaults where specified. By default, it uses process.env as the source, but you can provide a custom environment object (e.g., for browser environments).

    import { str, envsafe, port, url } from 'envsafe';
    
    export const env = envsafe({
      NODE_ENV: str({
        devDefault: 'development',
        choices: ['development', 'test', 'production'],
      }),
      PORT: port({
        devDefault: 3000,
        desc: 'The port the app is running on',
        example: 80,
      }),
      API_URL: url({
        devDefault: 'https://example.com/graphql',
      }),
      AUTH0_CLIENT_ID: str({
        devDefault: 'xxxxx',
      }),
      AUTH0_DOMAIN: str({
        devDefault: 'xxxxx.auth0.com',
      }),
    });
  3. Override the environment source

    main

    If you are not in a Node.js environment or need to use a specific object instead of process.env (like a global variable in the browser), pass a second argument to envsafe containing the env key.

    export const env = envsafe(
      {
        ENV_VAR: str({
          devDefault: 'myvar',
        }),
      },
      {
        env: window.__ENVIRONMENT__,
      },
    );
  4. Test environment variable scenarios in the playground

    main

    The playground demonstrates various environment variable states. You can use the following commands to observe how envsafe reacts to different configurations:

    • Valid configuration: Set a valid PORT.
    • Invalid configuration: Set an invalid PORT (e.g., a negative number) to trigger validation errors.
    • Missing variables: Set NODE_ENV=production to trigger errors for missing required variables.
    • Successful run: Provide all required variables (e.g., NODE_ENV, PORT, and MY_VAR) to see a successful execution.
    # Change PORT
    PORT=80 yarn dev
    
    # Invalid port:
    PORT=-1 yarn dev
    
    # Set production and see it fail
    NODE_ENV=production yarn dev
    
    # Fix errors
    NODE_ENV=production PORT=80 MY_VAR="🚀" yarn dev
  5. Customize error reporting

    main

    By default, envsafe logs a summary to console.error, calls window.alert() in browsers, and throws an error (exiting with code 1 in Node). You can override this behavior by providing a reporter function in the second argument of envsafe.

    const env = envsafe(
      {
        MY_VAR: str(),
      },
      {
        reporter({ errors, output, env }) {
          // do stuff
        },
      },
    );
  6. Built-in validators in envsafe

    main

    The following validator functions are available to define the expected type and format of your environment variables:

    FunctionReturn ValueDescription
    str()stringEnsures a value is present (unless a default is provided).
    bool()booleanParses "0", "1", "true", "false", "t", "f" into booleans.
    num()numberParses strings like "42", "0.23", or "1e5" into a Number.
    port()numberEnsures the value is a valid TCP port (1-65535).
    url()stringEnsures the value is a URL with a protocol and hostname.
    email()stringEnsures the value is a valid email address.
    json()unknownParses the string using JSON.parse.
  7. Create custom validators/parsers

    main

    You can create custom validation logic using makeValidator. A validator receives the input string and must either return the parsed value or throw an InvalidEnvError if validation fails.

    import { makeValidator, envsafe } from 'envsafe';
    
    const barParser = makeValidator<'bar'>(input => {
      if (input !== 'bar') {
        throw new InvalidEnvError(`Expected '${input}' to be 'bar'`);
      }
      return 'bar';
    });
    
    const env = envsafe({
      FOO: barParser(),
    });
  8. Configure validator options

    main

    When using validators, you can pass an options object to control behavior. Note that desc, example, and docs are purely for documentation and are not used by the library logic.

    Functional Options:

    NameTypeDescription
    choicesTValue[]An allow-list of permitted values.
    defaultTValue / stringA fallback value used if the env var is missing. Providing this makes the variable optional.
    devDefaultTValue / stringA fallback value used only when NODE_ENV is not production.
    inputstringManually provide the input value (useful for environments where dynamic reading is restricted).
    allowEmptybooleanIf true, empty strings are treated as valid values. Defaults to false (empty strings are treated as missing).