A lightweight solution to load environment variables from AWS SSM Parameter Store—with support for .env files and process.env—and seamlessly integrate with a type coercion API for safe, validated configuration.
This package has peer dependencies @aws-sdk/client-ssm. To install the core functionality, run:
npm install @byu-oit/env-ssm @aws-sdk/client-ssmIf you want to support loading variables from a .env file, install dotenv:
npm install dotenvThe package loads environment variables from three sources, in the following order (later sources overwrite earlier ones):
- SSM Parameter Store
- .envfile
- process.env
SSM Path: /my/app
SSM Parameters:
- /my/app/db/user => admin
- /my/app/db/pass => ch@ng3m3
- /my/app/host => https://example.com
import EnvSsm from 'env-ssm'
/**
 * Retrieves environment variables.
 * @returns { db: { user: 'admin', pass: 'ch@ng3m3' }, host: 'https://example.com' }
 */
async function getParams () {
  const env = await EnvSsm('/my/app')
  const db = env.get('db').required().asJsonObject()
  const host = env.get('api').required().asUrlString()
  return { db, host }
}If your SSM parameters are spread across multiple paths or use custom delimiters, you can specify these as follows:
SSM Paths:
- /my/app
- my.app (using .as a delimiter)
Parameters:
- /my/app/db/user → admin
- /my/app/db/pass → ch@ng3m3
- my.app.host → example.com
import EnvSsm from 'env-ssm'
/**
 * Retrieves environment variables from multiple SSM paths.
 * @returns { db: { user: 'admin', pass: 'ch@ng3m3' }, host: 'example.com' }
 */
async function getParams () {
  const env = await EnvSsm([
    '/my/app',
    { path: 'my.app', delimiter: '.' }
  ])
  const db = env.get('db').required().asJsonObject()
  const host = env.get('api').required().asString()
  return { db, host }
}Once your environment variables are loaded, you can use the built-in coercion library for type-safe access. For example:
import { CoercionContainer } from '@byu-oit/env-ssm'
// Define a sample environment source
const envSource = {
PORT: '8080',
DEBUG: 'true',
CONFIG: '{"key": "value"}',
MODE: 'production'
}
// Create a container instance with the source
const env = new CoercionContainer(envSource)
// Retrieve and coerce variables with defaults and validations
const port = env.get('PORT')
  .default(3000)
  .asPortNumber()
const debug = env.get('DEBUG')
  .required()
  .asBool()
const config = env.get('CONFIG')
  .default('{}')
  .asJsonObject()
const mode = env.get('MODE')
  .asEnum(['development', 'production', 'test'])
console.log(`Server will run on port: ${port}`)
console.log(`Debug mode: ${debug}`)
console.log(`Configuration:`, config)
console.log(`Running mode: ${mode}`)In this example:
- PORT is converted into a valid port number with a default.
- DEBUG is required and coerced to a boolean.
- CONFIG is parsed as a JSON object.
- MODE is validated against allowed values.
| Option | Type | Description | Default | 
|---|---|---|---|
| ssm | SSMClient | An AWS SSM client instance. The default SSM client can be configured with environment variables or a custom instance may be provided. | SSMClient | 
| paths | PathSsmLike OR PathSsmLike[] | The SSM parameter store path to use. All parameters that fall under this path will be returned as properties in the environment variables object. Parameters with multiple nested children will be returned as stringified JSON. | [] | 
| pathDelimiter | string | Specify a path delimiter. | / | 
| processEnv | boolean | If true, it will add process.env variables to the container. | true | 
| dotenv | boolean OR string | Adds local .env variables to the environment. Can be false, which disables .envsupport. May also be the exact path to the .env file relative to the project or package root. | process.cwd() + '/.env' | 
[TIP!] You can also configure options using environment variables:
- ENV_SSM_PATHS
- ENV_SSM_PATH_DELIMITER
- ENV_SSM_PROCESS_ENV
- ENV_SSM_DOTENV
[NOTE!] All options provided as environment variables are cast from strings to their respective types. For ENV_SSM_PATHS, you can supply a comma-delimited list (e.g. /app/dev,/app/prd) or a JSON object/array.
Wraps an object of environment variables and provides a method for type-safe variable access.
constructor(source: T)- source: An object conforming to the Source interface.
get(key: keyof T | string): Coercion- key: The name of the environment variable.
- Returns: A Coercion instance for chaining validation and conversion methods.
A builder class for handling an individual environment variable. It allows marking a variable as required, setting default values, and converting the variable into various types.
Methods
required(condition?: boolean): thisMarks the variable as required (default is true). Throws an error if the variable is missing when required.
default(defaultValue: unknown): thisSets a fallback value if the variable is absent.
asString(): stringConverts the variable to a string.
asBool(): booleanConverts the variable to a boolean. Accepts native boolean values or the strings "true"/"false" (case-insensitive). Throws an error if the conversion fails.
asNumber(): numberConverts the variable to a number. Throws an error if the result is NaN.
asPortNumber(): numberConverts the variable to a number and validates that it falls within the range 1–65535. Throws an error if the port number is out of range.
asJsonObject<T = any>(): TConverts the variable to a JSON object. If the value is a string, it is parsed as JSON. Throws an error if parsing fails or if the value is not a valid JSON object.
asEnum<T extends string>(allowed: T[]): TValidates that the variable’s string value is one of the allowed values. Throws an error if the value is not in the allowed list.
asUrlString(): stringConverts the variable to a string and validates that it is a well-formed URL. Throws an error if the URL is invalid.
asUrlObject(): URLConverts the variable to a URL object using the URL constructor. Throws an error if the value is not a valid URL.
Each coercion method checks for the presence and validity of its target variable:
- If a variable is missing and marked as required, an error is thrown.
- If conversion fails (e.g., an invalid number, malformed JSON, or a bad URL), a descriptive error is provided.
This helps catch configuration issues early during application startup.