Steve Kinney

Parameter Store: Hierarchical Configuration

Parameter Store is part of AWS Systems Manager (SSM). It’s a key-value store for configuration data—the same kind of data you’ve been putting in Lambda environment variables, but with encryption, access control, versioning, and a hierarchical namespace built in.

If you want AWS’s version of the same feature while you read, the Parameter Store documentation is the official reference.

If Lambda environment variables are like a flat .env file, Parameter Store is like a structured configuration tree. I find that distinction helpful because it changes how you think about organizing your config. You organize parameters by application, environment, and purpose using paths that look like file system directories: /my-frontend-app/production/api-key. And unlike environment variables, you can share parameters across multiple Lambda functions without duplicating values.

Diagram showing Parameter Store paths grouped by application and environment, with an IAM policy scoped to only the production subtree.

Creating Parameters with the CLI

The put-parameter command creates or updates a parameter. Here’s a plain text parameter:

aws ssm put-parameter \
  --name "/my-frontend-app/production/table-name" \
  --value "my-frontend-app-data" \
  --type "String" \
  --region us-east-1 \
  --output json

The response includes the version number and the tier:

{
  "Version": 1,
  "Tier": "Standard"
}

Now create a SecureString parameter for something sensitive—an API key:

aws ssm put-parameter \
  --name "/my-frontend-app/production/api-key" \
  --value "sk_live_abc123xyz" \
  --type "SecureString" \
  --region us-east-1 \
  --output json

In the console, the Create parameter form shows the SecureString type option with the KMS key selector.

The AWS Systems Manager Parameter Store Create parameter form showing the name /my-frontend-app/api-key filled in and SecureString selected as the type with the default KMS key.

The value is encrypted at rest using an AWS-managed KMS key. You can also specify your own KMS key with the --key-id flag, but the default key works fine for most use cases.

To update an existing parameter, add the --overwrite flag. Without it, put-parameter fails if the parameter already exists. This is a safety feature—you don’t accidentally overwrite production values.

Hierarchical Paths

The forward slashes in parameter names aren’t just cosmetic. They define a hierarchy that you can query, and more importantly, they let you scope IAM permissions to entire subtrees.

Here’s a typical structure for a frontend application with two environments:

/my-frontend-app/
├── production/
│   ├── table-name          (String)
│   ├── api-key             (SecureString)
│   ├── api-endpoint        (String)
│   └── feature-flags       (String)
├── staging/
│   ├── table-name          (String)
│   ├── api-key             (SecureString)
│   ├── api-endpoint        (String)
│   └── feature-flags       (String)

This hierarchy gives you two things. First, you can retrieve all parameters for a given environment in a single call. Second, you can write an IAM policy that grants a Lambda function access to /my-frontend-app/production/* without giving it access to staging parameters.

In the console, the Parameter Store list view shows all parameters in your account. You can filter by path to see only the /my-frontend-app/ hierarchy.

The AWS Systems Manager Parameter Store list view showing parameters with their names, types, and last modified dates.

Let’s populate a few more parameters:

aws ssm put-parameter \
  --name "/my-frontend-app/production/api-endpoint" \
  --value "https://api.example.com/v1" \
  --type "String" \
  --region us-east-1 \
  --output json

aws ssm put-parameter \
  --name "/my-frontend-app/production/feature-flags" \
  --value '{"darkMode":true,"newCheckout":false}' \
  --type "String" \
  --region us-east-1 \
  --output json

String vs. SecureString

Parameter Store supports three types:

TypeEncryptionUse Case
StringNoneTable names, endpoint URLs, feature flags
StringListNoneComma-separated values
SecureStringKMSAPI keys, tokens, passwords, connection strings

String parameters are stored in plain text. Use them for configuration that isn’t sensitive—the same kind of values you’d put in Lambda environment variables.

SecureString parameters are encrypted at rest with a KMS key. When you retrieve a SecureString, you must explicitly request decryption with the --with-decryption flag (CLI) or WithDecryption: true (SDK). Without it, you get the encrypted ciphertext, which is useless.

StringList stores comma-separated values as a single parameter. It’s occasionally useful, but most of the time you’re better off using a JSON string in a regular String parameter.

SecureString parameters require KMS permissions to decrypt. If your Lambda function’s execution role doesn’t have kms:Decrypt permission on the KMS key used to encrypt the parameter, the function can read the parameter name but can’t decrypt the value. You’ll get an access denied error at runtime, not at deploy time.

Retrieving Parameters

Get a Single Parameter

aws ssm get-parameter \
  --name "/my-frontend-app/production/table-name" \
  --region us-east-1 \
  --output json

Response:

{
  "Parameter": {
    "Name": "/my-frontend-app/production/table-name",
    "Type": "String",
    "Value": "my-frontend-app-data",
    "Version": 1,
    "LastModifiedDate": "2026-03-18T10:00:00.000Z",
    "ARN": "arn:aws:ssm:us-east-1:123456789012:parameter/my-frontend-app/production/table-name"
  }
}

For SecureString parameters, add --with-decryption:

aws ssm get-parameter \
  --name "/my-frontend-app/production/api-key" \
  --with-decryption \
  --region us-east-1 \
  --output json

Without --with-decryption, the Value field contains the encrypted ciphertext.

Get All Parameters by Path

This is where the hierarchy pays off. Retrieve every parameter under a given path:

aws ssm get-parameters-by-path \
  --path "/my-frontend-app/production" \
  --with-decryption \
  --recursive \
  --region us-east-1 \
  --output json

This returns all four parameters under /my-frontend-app/production/ in a single API call. The --recursive flag includes parameters in nested paths. Without it, only direct children of the specified path are returned.

Retrieving Parameters with the SDK

Here’s how you retrieve a parameter from a Lambda function using the AWS SDK v3:

import { SSMClient, GetParameterCommand } from '@aws-sdk/client-ssm';

const ssm = new SSMClient({});

const getParameter = async (name: string): Promise<string> => {
  const response = await ssm.send(
    new GetParameterCommand({
      Name: name,
      WithDecryption: true,
    }),
  );
Note WithDecryption: true is required for SecureString parameters. It has no effect on String parameters, so you can safely set it for all parameters.
  if (!response.Parameter?.Value) {
    throw new Error(`Parameter ${name} not found or has no value`);
  }

  return response.Parameter.Value;
};

To retrieve all parameters under a path:

import { SSMClient, GetParametersByPathCommand } from '@aws-sdk/client-ssm';

const ssm = new SSMClient({});

const getParametersByPath = async (path: string): Promise<Record<string, string>> => {
  const response = await ssm.send(
    new GetParametersByPathCommand({
      Path: path,
      WithDecryption: true,
      Recursive: true,
    }),
  );

  const parameters: Record<string, string> = {};
  for (const param of response.Parameters ?? []) {
    if (param.Name && param.Value) {
      const key = param.Name.replace(path, '').replace(/^\//, '');
Note Strip the path prefix to get a clean key like api-key instead of the full path.      parameters[key] = param.Value;
    }
  }

  return parameters;
};

Standard vs. Advanced Tier

Parameter Store has two tiers:

FeatureStandardAdvanced
CostFree$0.05 per parameter per month
Max value size4 KB8 KB
Max parameters per region10,000100,000
Parameter policiesNoYes (expiration, notification)
Throughput40 TPS (default)Up to 1,000 TPS (higher throughput)

For almost every frontend application, the standard tier is more than enough. You’re storing a handful of configuration values, not tens of thousands. The 4 KB value limit is the same as Lambda’s environment variable limit, and it’s plenty for API keys and configuration strings.

You don’t need to choose a tier upfront. Parameters default to Standard. If you later need Advanced features, you can change a parameter’s tier with put-parameter --tier Advanced --overwrite. You can also set the tier to Intelligent-Tiering and let AWS promote parameters to Advanced only when they exceed Standard limits.

Versioning

Every time you update a parameter, Parameter Store increments its version number. You can retrieve a specific version by appending :version to the name:

aws ssm get-parameter \
  --name "/my-frontend-app/production/api-key:1" \
  --with-decryption \
  --region us-east-1 \
  --output json

This gives you a lightweight audit trail and the ability to roll back a configuration change without redeploying anything.

Parameter Store handles most configuration needs, but it doesn’t rotate credentials for you. When you need automatic rotation—for database passwords, OAuth tokens, or any credential with a lifecycle—that’s where Secrets Manager comes in. The next lesson covers Secrets Manager and when it’s worth the cost.

Last modified on .