SSM Parameter Conventions

Autoload Convention Path

Jets will autoload SSM parameters under the path of /PROJECT/ENV/. This means SSM parameters like

/demo/dev/DATABASE_URL
/demo/dev/SECRET_KEY_BASE

All you have to do is create them in AWS SSM parameter store, and they are automatically loaded. So the config/jets/env/.env is entirely optional. This behavior can be configured with:

config/jets/project.rb

Jets.project.configure do
  config.dotenv.ssm.autoload = true # default: true
end

This spares you from updating your config/jets/env files with newly added SSM parameters. Here’s a useful CLI command to see what values are in SSM.

❯ aws ssm get-parameters-by-path --path "/demo/dev/" | jq -r '.Parameters[].Name' | sort
/demo/dev/DATABASE_URL
/demo/dev/SECRET_KEY_BASE

For those who prefer more control over the SSM env variables, you can turn off the behavior and use explicit jets/config/env files. If you using both, the explicit values always win.

Note: Jets uses the optimized get_parameters_by_path API call. It efficiently retrieves multiple parameters that share a path hierarchy. This minimizes API calls compared to fetching parameters individually and avoids rate limit issues. The implementation does not use the recursive option by design, so the parameters should be within the same hierarchy level.

Conventional SSM Names

Additionally, there is some conventional SSM name logic to help DRY up your dotenv files. Some examples probably best help explain:

DATABASE_URL=SSM        # => DATABASE_URL=/demo/dev/DATABASE_URL
DATABASE_URL=SSM:DB_URL # => DATABASE_URL=/demo/dev/DB_URL

If the value starts with a / right after SSM:, IE: SSM:/abs/path/DB_URL, then the conventional behavior is not performed.

DATABASE_URL=SSM:/shared/dev/DB_URL # => DATABASE_URL=/shared/dev/DB_URL

Custom Convention Resolver

The conventional SSM name works like this:

DATABASE_URL=SSM        # => DATABASE_URL=/demo/dev/DATABASE_URL
DATABASE_URL=SSM:DB_URL # => DATABASE_URL=/demo/dev/DB_URL

For advanced use cases where the that logic does not work for your needs, you can configure a custom convention_resolver.

config/jets/project.rb

Jets.project.configure do
  config.dotenv.ssm.convention_resolver = ->(ssm_leaf_name) do
    "/#{Jets.project.name}/#{ssm_env}/#{ssm_leaf_name}"
  end
end

It can be any object that responds to .call and is passed the ssm_leaf_name as an argument.

Reference

The table below covers each setting. Each option is configured with config.OPTION. The config. portion is not shown for conciseness. IE: logger.level vs config.logger.level.

Name Default Description
dotenv.ssm.autoload.default_skip see desc Default skip values for SSM autoloading. Default: ["BASIC_AUTH_USERNAME", "BASIC_AUTH_PASSWORD", "BASIC_AUTH_CREDENTIALS"]
dotenv.ssm.autoload.enable true Autoload SSM values from conventional path. IE: /demo/dev/
dotenv.ssm.autoload.skip [] Skip these values for SSM autoloading.
dotenv.ssm.convention_resolver nil A proc that receives ssm_leaf_value as the argument. You can use this to customize the SSM name conventional resolver.
dotenv.ssm.long_env false Useful for legacy Jets 5 behavior, where JETS_ENV was encouraged to be development or production. Jets 6 uses dev and prod.
dotenv.ssm.envs.unique [“dev”,”prod”] The unique env values that should resolve to the SSM env name. So the cases when JETS_ENV is the same as SSM env name.
dotenv.ssm.envs.fallback [“dev”] When JETS_ENV is not one of the ssm.envs.unique envs, then fall back and use this env. IE: JETS_ENV=sandbox resolves to dev for the SSM env name.
dotenv.ssm.project_name nil Override the ssm project name. When not set, defaults to project name set by config.name in config/jets/project.rb.

See Full Config Reference