How to Load Config From AWS SSM Parameter Store

Fetching config from AWS SSM Parameter Store at boot - instead of reading raw environment variables - means you can rotate a database URL or API key with a parameter update and a process restart, no redeploy needed.

DevOps Engineerawsssmparameter-store

Why SSM Parameter Store instead of environment variables

The 12-factor app rule "store config in the environment" made sense when the alternative was hardcoding values. AWS SSM Parameter Store goes a step further: config lives in a managed store with versioning, IAM-gated access, and optional encryption (SecureString). Rotation becomes a parameter update + a process restart. No image rebuild, no Kubernetes rollout, no redeploy.

Reading a parameter with boto3

import os
import boto3

def load_database_url() -> str:
    ssm = boto3.client(
        "ssm",
        endpoint_url=os.environ.get("AWS_ENDPOINT_URL"),   # override for local/moto testing
        region_name=os.environ.get("AWS_DEFAULT_REGION", "us-east-1"),
    )
    try:
        return ssm.get_parameter(Name="/app/database/url")["Parameter"]["Value"]
    except Exception:
        # fall back to env if SSM is unreachable or the parameter is missing
        return os.environ["DATABASE_URL"]

The ["Parameter"]["Value"] path is the standard shape for a plain String parameter. For SecureString parameters add WithDecryption=True:

ssm.get_parameter(Name="/app/db/password", WithDecryption=True)["Parameter"]["Value"]

Verify the parameter exists before you deploy

aws ssm get-parameter --name /app/database/url
# {
#   "Parameter": {
#     "Name": "/app/database/url",
#     "Type": "String",
#     "Value": "postgresql://user:pass@db:5432/myapp",
#     ...
#   }
# }

Cache it - do not call SSM on every request

SSM GetParameter has a 40 req/s per-account rate limit and adds ~5-20 ms of latency. Read once at boot and store in a module-level variable:

_db_url: str | None = None

def get_database_url() -> str:
    global _db_url
    if _db_url is None:
        _db_url = load_database_url()
    return _db_url

For applications that need to pick up rotations without restarting, refresh the cached value on a background timer (e.g. every 5 minutes) rather than on every call.

Naming convention

Use a hierarchical path like /app/<env>/<service>/<param> - it maps cleanly to IAM resource ARNs, lets you lock down access by prefix, and makes it obvious which parameters belong to which service:

/app/prod/api/database_url
/app/prod/api/stripe_secret_key
/app/staging/api/database_url

IAM can then grant a role access to /app/prod/api/* without exposing staging or other services.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

How do I read a parameter from AWS SSM Parameter Store in Python?

Use boto3: ssm = boto3.client('ssm'); val = ssm.get_parameter(Name='/your/param')['Parameter']['Value']. For SecureString (encrypted) parameters, add WithDecryption=True. Read once at startup and cache the result.

How is SSM Parameter Store different from environment variables?

SSM stores config centrally with versioning and IAM-gated access. You can rotate a value - update the parameter, restart the process - without rebuilding the Docker image or redeploying. Environment variables are baked in at container start and can't change without a restart + redeploy.

Should I call SSM Parameter Store on every request?

No. GetParameter has a 40 req/s rate limit and adds latency. Read at startup, cache the value in memory, and optionally refresh it on a background timer if you need to pick up rotations without restarting.

What is the difference between SSM Parameter Store and Secrets Manager?

Both store config and secrets, but Secrets Manager adds built-in automatic rotation and costs per secret; Parameter Store is free for standard parameters and simpler. Use Parameter Store for general config, Secrets Manager when you need managed rotation.

Keep learning

Fix the Nginx 502 Bad GatewayDevOps projectRecover a Crashed Linux ServiceDevOps projectCorrect a Postgres Port MismatchDevOps projectDevOps roadmapStep by step to hiredDevOps interview questionsSTAR answersAll DevOps projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →