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-ssm
If you want to support loading variables from a .env file, install dotenv:
npm install dotenv
The package loads environment variables from three sources, in the following order (later sources overwrite earlier ones):
- SSM Parameter Store
.env
fileprocess.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 .env support. 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): this
Marks the variable as required (default is true). Throws an error if the variable is missing when required.
default(defaultValue: unknown): this
Sets a fallback value if the variable is absent.
asString(): string
Converts the variable to a string.
asBool(): boolean
Converts the variable to a boolean. Accepts native boolean values or the strings "true"/"false" (case-insensitive). Throws an error if the conversion fails.
asNumber(): number
Converts the variable to a number. Throws an error if the result is NaN.
asPortNumber(): number
Converts 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>(): T
Converts 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[]): T
Validates 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(): string
Converts the variable to a string and validates that it is a well-formed URL. Throws an error if the URL is invalid.
asUrlObject(): URL
Converts 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.