<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aparna Krishnamoorthy</title>
    <description>The latest articles on DEV Community by Aparna Krishnamoorthy (@aparkris).</description>
    <link>https://dev.to/aparkris</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3927622%2F9eb7d712-e035-4ef1-812f-a1f71401f76b.png</url>
      <title>DEV Community: Aparna Krishnamoorthy</title>
      <link>https://dev.to/aparkris</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aparkris"/>
    <language>en</language>
    <item>
      <title>Stop hardcoding AWS Lambda layer ARNs: use public parameters for the AWS Parameters and Secrets Lambda Extension</title>
      <dc:creator>Aparna Krishnamoorthy</dc:creator>
      <pubDate>Tue, 15 Sep 2026 13:09:51 +0000</pubDate>
      <link>https://dev.to/aparkris/stop-hardcoding-aws-lambda-layer-arns-use-public-parameters-for-the-aws-parameters-and-secrets-56m5</link>
      <guid>https://dev.to/aparkris/stop-hardcoding-aws-lambda-layer-arns-use-public-parameters-for-the-aws-parameters-and-secrets-56m5</guid>
      <description>&lt;p&gt;To add the AWS Parameters and Secrets Lambda Extension to an AWS Lambda function, you can open the documentation, find the ARN table, locate your AWS Region and architecture, copy the ARN, and paste it into your template. This approach works, but the version number at the end of that ARN changes every time AWS releases an update. If you hardcode that number, your deployment stays pinned to an older version, which you might not notice for months.&lt;/p&gt;

&lt;p&gt;There's a better approach that uses public parameters in AWS Systems Manager Parameter Store (Parameter Store).&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the AWS Parameters and Secrets Lambda Extension?
&lt;/h2&gt;

&lt;p&gt;The AWS Parameters and Secrets Lambda Extension is a Lambda layer that retrieves and caches values from Parameter Store and AWS Secrets Manager. It runs as a companion process alongside your function, and serves cached parameter values over a local HTTP endpoint. The use of this extension reduces latency, reduces API call costs, and simplifies your function code: you make a local HTTP call instead of configuring an SDK client and managing your own caching logic.&lt;/p&gt;

&lt;p&gt;If you're new to the extension, the &lt;a href="https://aws.amazon.com/blogs/compute/using-the-aws-parameter-and-secrets-lambda-extension-to-cache-parameters-and-secrets/" rel="noopener noreferrer"&gt;AWS Compute Blog post&lt;/a&gt; covers the full setup, and provides a walkthrough with load test results showing ~98% fewer API calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with hardcoded layer ARNs
&lt;/h2&gt;

&lt;p&gt;The extension is distributed as a Lambda layer. To attach it, you need its ARN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:122
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The version number at the end (&lt;code&gt;122&lt;/code&gt; at the time of writing) changes with each release. If you hardcode it, it'll keep working, but you won't get bug fixes, performance improvements, or new features until someone manually checks the docs and updates it.&lt;/p&gt;

&lt;p&gt;The Lambda console makes this easy for a single function. You pick "AWS-Parameters-and-Secrets-Lambda-Extension" from a dropdown and choose the latest version. But that doesn't help your CloudFormation templates, CDK stacks, or Terraform configurations, where the ARN is a static string that someone has to maintain.&lt;/p&gt;

&lt;p&gt;For a team managing many functions across multiple AWS Regions, it becomes a maintenance chore that's easy to forget.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better approach: resolve at deploy time
&lt;/h2&gt;

&lt;p&gt;AWS publishes the latest extension layer ARN as a public parameter in every commercial AWS Region. The paths are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;th&gt;Parameter path&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;x86_64&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/aws/service/aws-parameters-and-secrets-lambda-extension/x86/latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARM64&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/aws/service/aws-parameters-and-secrets-lambda-extension/arm64/latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When you reference these parameters in infrastructure code, the ARN resolves at deploy time. Each deployment picks up the latest version automatically.&lt;/p&gt;

&lt;p&gt;The only IAM permission you need is &lt;code&gt;ssm:GetParameter&lt;/code&gt;. The parameters are public and readable from any AWS account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving the ARN from the CLI
&lt;/h2&gt;

&lt;p&gt;To see the latest layer ARN for your AWS Region, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/aws/service/aws-parameters-and-secrets-lambda-extension/x86/latest"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Parameter.Value"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For ARM64:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/aws/service/aws-parameters-and-secrets-lambda-extension/arm64/latest"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Parameter.Value"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use these commands in a script, a CI pipeline, or to check what version is the latest before deploying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the parameter in CloudFormation
&lt;/h2&gt;

&lt;p&gt;CloudFormation supports dynamic references that resolve SSM parameters during stack operations. If you reference the public parameter directly, your template won't need a version-specific ARN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;MyFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Lambda::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-function&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.12&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
      &lt;span class="na"&gt;Architectures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;x86_64&lt;/span&gt;
      &lt;span class="na"&gt;Code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ZipFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;import json&lt;/span&gt;
          &lt;span class="s"&gt;import os&lt;/span&gt;
          &lt;span class="s"&gt;import urllib.request&lt;/span&gt;

          &lt;span class="s"&gt;def handler(event, context):&lt;/span&gt;
              &lt;span class="s"&gt;token = os.environ['AWS_SESSION_TOKEN']&lt;/span&gt;

              &lt;span class="s"&gt;req = urllib.request.Request(&lt;/span&gt;
                  &lt;span class="s"&gt;'http://localhost:2773/systemsmanager/parameters/get?name=%2Fmy%2Fparameter'&lt;/span&gt;
              &lt;span class="s"&gt;)&lt;/span&gt;
              &lt;span class="s"&gt;req.add_header('X-Aws-Parameters-Secrets-Token', token)&lt;/span&gt;
              &lt;span class="s"&gt;config = urllib.request.urlopen(req).read()&lt;/span&gt;
              &lt;span class="s"&gt;return json.loads(config)&lt;/span&gt;
      &lt;span class="na"&gt;Layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{resolve:ssm:/aws/service/aws-parameters-and-secrets-lambda-extension/x86/latest}}'&lt;/span&gt;
      &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;MyFunctionRole.Arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{{resolve:ssm:...}}&lt;/code&gt; syntax tells CloudFormation to fetch the parameter value during stack creation or update. The resolved value is fixed until the next stack operation. To pick up a new extension version, update the stack. (The template itself doesn't change.)&lt;/p&gt;

&lt;p&gt;For ARM64 functions, swap the path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{resolve:ssm:/aws/service/aws-parameters-and-secrets-lambda-extension/arm64/latest}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the parameter in CDK
&lt;/h2&gt;

&lt;p&gt;CDK resolves the parameter at deploy time using the same underlying SSM resolution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-ssm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParameterCacheStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;extensionArn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringParameter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueForStringParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/aws/service/aws-parameters-and-secrets-lambda-extension/x86/latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyFunction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PYTHON_3_12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LayerVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromLayerVersionArn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ParamsSecretsExt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;extensionArn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, CDK synthesizes this into a CloudFormation template parameter of type &lt;code&gt;AWS::SSM::Parameter::Value&amp;lt;String&amp;gt;&lt;/code&gt;, so the layer ARN is resolved from the public parameter at deploy time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the parameter in Terraform
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_ssm_parameter"&lt;/span&gt; &lt;span class="s2"&gt;"params_secrets_extension"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/aws/service/aws-parameters-and-secrets-lambda-extension/x86/latest"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"my_function"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-function"&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.12"&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;
  &lt;span class="nx"&gt;filename&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda.zip"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_exec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;

  &lt;span class="nx"&gt;architectures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"x86_64"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;layers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ssm_parameter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params_secrets_extension&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;terraform apply&lt;/code&gt; resolves the parameter. If a new version was published since your last deploy, you'd see it in the plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  A common mistake: parameter ARN vs. parameter value
&lt;/h2&gt;

&lt;p&gt;Because it's an AWS resource, the SSM public parameter has its own ARN, and it contains a value that is the Lambda layer ARN. These are not the same thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parameter ARN&lt;/strong&gt; (the address): &lt;code&gt;arn:aws:ssm:us-east-1::parameter/aws/service/aws-parameters-and-secrets-lambda-extension/x86/latest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameter value&lt;/strong&gt; (the content): &lt;code&gt;arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:122&lt;/code&gt; (version number at the time of writing)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you paste the parameter ARN into the Lambda layer field in the console, you'll get a validation error. Lambda expects a layer ARN, not a parameter ARN. The dynamic references in CloudFormation and Terraform handle this resolution automatically. However, if you copy manually from the console, make sure you're copying the &lt;strong&gt;value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One more detail the parameters save you from: the x86_64 and ARM64 layers have different names, not just different version numbers. The x86_64 value resolves to a layer named &lt;code&gt;AWS-Parameters-and-Secrets-Lambda-Extension&lt;/code&gt;, while the ARM64 value resolves to &lt;code&gt;AWS-Parameters-and-Secrets-Lambda-Extension-Arm64&lt;/code&gt;. Reference the right architecture's parameter and you never have to track that distinction yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters for teams
&lt;/h2&gt;

&lt;p&gt;Public parameters reduce maintenance work. Every team's deployment pipeline resolves the latest version independently. You don't need shared spreadsheets of ARNs, Slack messages asking what the latest version is, or pull requests that just bump a version number.&lt;/p&gt;

&lt;p&gt;When AWS publishes an update with a bug fix or performance improvement, your next deployment picks it up automatically without the need for coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/ps-integration-lambda-extensions.html" rel="noopener noreferrer"&gt;Using Parameter Store parameters in AWS Lambda functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/compute/using-the-aws-parameter-and-secrets-lambda-extension-to-cache-parameters-and-secrets/" rel="noopener noreferrer"&gt;Using the AWS Parameter and Secrets Lambda extension to cache parameters and secrets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html" rel="noopener noreferrer"&gt;Discovering public parameters in Parameter Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>parameterstore</category>
      <category>lambda</category>
      <category>devops</category>
    </item>
    <item>
      <title>Stop hardcoding AWS Lambda layer ARNs, and use AWS Systems Manager Parameter Store public parameters instead</title>
      <dc:creator>Aparna Krishnamoorthy</dc:creator>
      <pubDate>Tue, 01 Sep 2026 03:43:00 +0000</pubDate>
      <link>https://dev.to/aparkris/-stop-hardcoding-aws-lambda-layer-arns-and-use-aws-systems-manager-parameter-store-public-p70</link>
      <guid>https://dev.to/aparkris/-stop-hardcoding-aws-lambda-layer-arns-and-use-aws-systems-manager-parameter-store-public-p70</guid>
      <description>&lt;p&gt;To add the AWS AppConfig Agent Lambda extension to an AWS Lambda function, you can open the documentation, scroll through a table of ARNs, find the one that matches your AWS Region and architecture, copy it, and paste it into your template. However, a few months later, AWS publishes a new version and now your deployment is silently using an older one. There’s a better approach that uses public parameters in AWS Systems Manager Parameter Store (Parameter Store).&lt;/p&gt;

&lt;h2&gt;
  
  
  What are public parameters in Parameter Store?
&lt;/h2&gt;

&lt;p&gt;Many AWS services use Parameter Store to publish read-only public parameters with names that start with &lt;code&gt;/aws/service/{service-name}&lt;/code&gt;. These public parameters contain up-to-date metadata about AWS services.&lt;/p&gt;

&lt;p&gt;You've probably seen them used for AMI lookups for fetching the latest Amazon Linux AMI ID without hardcoding it. The same mechanism is available for Lambda layer ARNs, ECS-optimized AMIs, and other resources that AWS updates regularly.&lt;/p&gt;

&lt;p&gt;The key idea is that instead of looking up a value in documentation and pasting it into your code, you query Parameter Store at deploy time and get the current value. The only IAM permission that's required is &lt;code&gt;ssm:GetParameter&lt;/code&gt;. The parameters are public and readable from any AWS account.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with hardcoded layer ARNs
&lt;/h2&gt;

&lt;p&gt;The AWS AppConfig Agent Lambda extension is distributed as a Lambda layer. To attach it, you need the layer's ARN, which includes a version number at the end like in this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arn:aws:lambda:us-east-1:027255383542:layer:AWS-AppConfig-Extension:128
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That version number changes every time AWS releases an update. If you hardcode it, you get a working deployment, but you also get silent drift. A few months from now, you'll be running an older version without realizing it.&lt;/p&gt;

&lt;p&gt;Imagine a team that's managing dozens of functions in multiple AWS Regions, and you can see how this can become a maintenance problem. Someone has to regularly check the documentation, update the ARN, and redeploy. It's not difficult work, but it's the kind of thing that's a hassle and that gets forgotten.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better approach: resolve at deploy time
&lt;/h2&gt;

&lt;p&gt;AWS publishes the latest AppConfig extension layer ARN as a public parameter in every commercial AWS Region. Here are the two paths:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;th&gt;Parameter path&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;x86_64&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/aws/service/aws-appconfig/lambda-extension/x86/latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARM64&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/aws/service/aws-appconfig/lambda-extension/arm64/latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The x86 path uses &lt;code&gt;x86&lt;/code&gt;, not &lt;code&gt;x86_64&lt;/code&gt;, even though the Lambda architecture name is &lt;code&gt;x86_64&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you reference these parameters in your infrastructure code, each deployment resolves the current value from Parameter Store. How and when that resolution happens depends on your tooling. The AWS CLI resolves the parameter on each invocation. CloudFormation dynamic references (&lt;code&gt;{{resolve:ssm:...}}&lt;/code&gt;) and parameter types (&lt;code&gt;AWS::SSM::Parameter::Value&lt;/code&gt;) resolve during stack create or update operations. The resolved value is then fixed until the next stack operation. Either way, you avoid hardcoding and pick up new versions through your normal deployment workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving the ARN from the CLI
&lt;/h2&gt;

&lt;p&gt;As an example, run the following AWS CLI command. It returns the full layer ARN for your current AWS Region.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/aws/service/aws-appconfig/lambda-extension/x86/latest"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Parameter.Value"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For ARM64:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/aws/service/aws-appconfig/lambda-extension/arm64/latest"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Parameter.Value"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the parameter in CloudFormation
&lt;/h2&gt;

&lt;p&gt;You can reference the public parameter directly in a CloudFormation template using a dynamic reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;MyFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Lambda::Function&lt;/span&gt;
  &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-function&lt;/span&gt;
    &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.12&lt;/span&gt;
    &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
    &lt;span class="na"&gt;Architectures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;x86_64&lt;/span&gt;
    &lt;span class="na"&gt;Layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{resolve:ssm:/aws/service/aws-appconfig/lambda-extension/x86/latest}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this approach matters for teams
&lt;/h2&gt;

&lt;p&gt;For one developer working on one function, looking up an ARN in the documentation is fine. But when you have multiple teams deploying functions across AWS Regions, keeping layer versions current becomes a coordination problem.&lt;/p&gt;

&lt;p&gt;Public parameters remove that concern. Every team's deployment pipeline resolves the latest version independently. You don't need shared spreadsheets of ARNs or Slack messages asking if anyone has checked the latest version. It's a small thing, but small operational improvements add up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html" rel="noopener noreferrer"&gt;Discovering public parameters in Parameter Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions-versions.html" rel="noopener noreferrer"&gt;Available versions of the AWS AppConfig Agent Lambda extension&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Finding public SSM parameters for AMIs with the EC2 DescribeImages API</title>
      <dc:creator>Aparna Krishnamoorthy</dc:creator>
      <pubDate>Wed, 19 Aug 2026 13:49:48 +0000</pubDate>
      <link>https://dev.to/aparkris/finding-public-ssm-parameters-for-amis-with-the-ec2-describeimages-api-6e5</link>
      <guid>https://dev.to/aparkris/finding-public-ssm-parameters-for-amis-with-the-ec2-describeimages-api-6e5</guid>
      <description>&lt;p&gt;Services like EC2 and ECS require an AMI ID at launch time, which pins the instance to a specific OS image. AMIs from AWS and its partners get patched often, and each patch ships as a new ID. If you hardcode that ID, it goes stale quickly and your infrastructure drifts behind the latest patches.&lt;/p&gt;

&lt;p&gt;The standard fix is to use a public SSM parameter — a well-known path that always resolves to the current AMI in a given family. That works great for new deployments, but what about existing code where the AMI ID is already baked in? Finding the right parameter used to mean navigating cryptic /aws/service/ hierarchies, guessing naming conventions, and making dozens of &lt;code&gt;GetParametersByPath&lt;/code&gt;calls. This tedious process not only slowed down workflows but also introduced the risk of selecting the wrong parameter, potentially leading to deployment issues.&lt;/p&gt;

&lt;p&gt;A new EC2 feature eliminates that friction: the &lt;code&gt;DescribeImages&lt;/code&gt; API now includes a &lt;code&gt;PublicSsmParameterName&lt;/code&gt; field that tells you exactly which parameter maps to a given AMI. &lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the SSM parameter for a public AMI in DescribeImages
&lt;/h2&gt;

&lt;p&gt;You can avoid the manual search by retrieving the parameter name from &lt;code&gt;DescribeImages&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ec2 describe-images &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--image-ids&lt;/span&gt; ami-1234567890abcdef0 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Images[*].{ImageId:ImageId,PublicSsmParameterName:PublicSsmParameterName}'&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;
 &lt;span class="o"&gt;{&lt;/span&gt;
 &lt;span class="s2"&gt;"ImageId"&lt;/span&gt;: &lt;span class="s2"&gt;"ami-1234567890abcdef0"&lt;/span&gt;,
 &lt;span class="s2"&gt;"PublicSsmParameterName"&lt;/span&gt;: &lt;span class="s2"&gt;"aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parameter will now resolve to the updated AMI than the one you described if the publisher has released a newer version. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the leading slash before using the parameter
&lt;/h2&gt;

&lt;p&gt;When you copy the parameter name from the EC2 &lt;code&gt;DescribeImages&lt;/code&gt; API, note that it doesn't have the leading slash required by Parameter Store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
ValidationException: Parameter name: can't be prefixed with "ssm"...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a leading / to avoid the error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using a parameter instead of a hardcoded AMI ID
&lt;/h2&gt;

&lt;p&gt;Reference the parameter returned by &lt;code&gt;DescribeImages&lt;/code&gt; directly in your infrastructure code.&lt;/p&gt;

&lt;p&gt;In the following CloudFormation example, you define a parameter of type &lt;code&gt;AWS::SSM::Parameter::Value&amp;lt;AWS::EC2::Image::Id&amp;gt;&lt;/code&gt;, and use it for the &lt;code&gt;ImageId&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;LatestAmiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SSM::Parameter::Value&amp;lt;AWS::EC2::Image::Id&amp;gt;&lt;/span&gt;
 &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;Instance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::Instance&lt;/span&gt;
 &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;ImageId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;LatestAmiId&lt;/span&gt;
 &lt;span class="na"&gt;InstanceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t3.micro&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the following CDK example, you pass the same parameter name to &lt;code&gt;MachineImage.fromSsmParameter()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;machineImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MachineImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromSsmParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InstanceSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MICRO&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="nx"&gt;machineImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both approaches resolve the parameter when you create or update the stack, not on every new instance launch, so an update is still reviewable and tied to your normal deployment process.&lt;/p&gt;

&lt;p&gt;In the following example, you use the &lt;code&gt;resolve:ssm:&lt;/code&gt; prefix on the &lt;code&gt;ImageId&lt;/code&gt;. New instances resolve the parameter at launch time, so they can use the current AMI in that AMI family without a redeploy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ec2 create-launch-template &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--launch-template-name&lt;/span&gt; my-template &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--version-description&lt;/span&gt; version1 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--launch-template-data&lt;/span&gt; &lt;span class="s1"&gt;'{"ImageId":"resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64","InstanceType":"t3.micro"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;DescribeImages&lt;/code&gt; returns the public SSM parameter associated with a public AMI family. Reference that parameter in your launch and deployment code to avoid manually searching for it. Remember to add the leading slash to the parameter name when retrieving it from Parameter Store.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>parameterstore</category>
      <category>ec2</category>
    </item>
    <item>
      <title>Scaling Parameter Store reads for production workloads</title>
      <dc:creator>Aparna Krishnamoorthy</dc:creator>
      <pubDate>Thu, 23 Jul 2026 19:33:35 +0000</pubDate>
      <link>https://dev.to/aparkris/scaling-parameter-store-reads-for-production-workloads-46ie</link>
      <guid>https://dev.to/aparkris/scaling-parameter-store-reads-for-production-workloads-46ie</guid>
      <description>&lt;p&gt;Consider an order-processing service running on Amazon ECS Fargate during a weekend sale. Under normal conditions, 20 tasks read configuration values from Parameter Store at startup. As traffic increases, the service scales to 200 tasks, causing many tasks to request the same parameters at nearly the same time. If these requests exceed the available throughput, new tasks can start slowly or fail, potentially delaying or interrupting customer orders.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsyheu0gk10nqclytk0a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsyheu0gk10nqclytk0a6.png" alt="Parameter Store Throughput" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When an application exceeds the available quota, its logs can show a &lt;code&gt;ThrottlingException&lt;/code&gt;or &lt;code&gt;RateExceeded&lt;/code&gt; error from &lt;code&gt;GetParameter&lt;/code&gt;, &lt;code&gt;GetParameters&lt;/code&gt;, or &lt;code&gt;GetParametersByPath&lt;/code&gt;. To diagnose such issues, you can check the error source in application logs, or trace the relevant API calls in CloudTrail. Then compare the timing against a known scaling or deployment event. Throttling or latency issues that cluster around this event are a strong signal that concurrent parameter requests caused the bottleneck. &lt;/p&gt;

&lt;p&gt;You can address Parameter Store throughput issues in the following complementary ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable higher throughput.&lt;/strong&gt; Increase the quota so that production workloads handle concurrent reads during normal operation and scaling events. The cost is based on usage. For example, a workload generating approximately 456,000 parameter interactions for a 60-hour sale costs about $2.28.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize read patterns.&lt;/strong&gt; Reduce unnecessary API traffic by retrieving only the parameters the application needs and caching values that it reads repeatedly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enabling higher throughput raises the quota for each API action in a single account in a single Region. Throughput for &lt;code&gt;SecureString&lt;/code&gt; parameters might be further limited by AWS KMS. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API action&lt;/th&gt;
&lt;th&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-throughput.html" rel="noopener noreferrer"&gt;Default quota&lt;/a&gt;&lt;/th&gt;
&lt;th&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-throughput.html" rel="noopener noreferrer"&gt;Higher-throughput quota&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GetParameter&lt;/td&gt;
&lt;td&gt;Shared 40 TPS&lt;/td&gt;
&lt;td&gt;10,000 TPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GetParameters&lt;/td&gt;
&lt;td&gt;Shared 40 TPS&lt;/td&gt;
&lt;td&gt;1,000 TPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GetParametersByPath&lt;/td&gt;
&lt;td&gt;Shared 40 TPS&lt;/td&gt;
&lt;td&gt;100 TPS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Improving application resilience by enabling higher throughput
&lt;/h2&gt;

&lt;p&gt;Consider enabling higher throughput in the following scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parameter Store is part of a production request path, not a one-time deployment. A higher quota ensures configuration requests don’t become a bottleneck at runtime. &lt;/li&gt;
&lt;li&gt;Many instances, containers, or Lambda functions read parameters within the same window. Higher throughput lets your fleet scale without individual instances competing for a shared, undersized quota. &lt;/li&gt;
&lt;li&gt;Deployments, restarts, or autoscaling events produce bursts of reads. You can absorb these predictable spikes, so a routine deployment doesn't fail.&lt;/li&gt;
&lt;li&gt;Usage regularly approaches or exceeds the default 40 TPS quota. By proactively increasing your quota, you eliminate bottlenecks instead of waiting for them to recur under heavier load.&lt;/li&gt;
&lt;li&gt;You want more throughput but don’t want to redesign the system. Enabling the higher-throughput setting increases your quota immediately without touching your infrastructure or application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you enable higher throughput, you increase the request quota for your AWS account and Region. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3chxqgjmgn1vo6efo5br.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3chxqgjmgn1vo6efo5br.png" alt="Parameter Store Higher Throughput" width="799" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cost of higher throughput is &lt;a href="https://aws.amazon.com/systems-manager/pricing/" rel="noopener noreferrer"&gt;$0.05 per 10,000 parameter interactions&lt;/a&gt;. A request that retrieves multiple parameters counts as one interaction for each parameter returned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An order-processing example&lt;/strong&gt;&lt;br&gt;
Assume that our order-processing service runs 20 tasks under normal conditions. During a promotional event lasting 60 hours (6 p.m. Friday to 6 a.m. Monday), it scales to 200 tasks for the duration of the sale. To limit stale values, each task refreshes the database endpoint, inventory service, and order dead-letter queue parameters every 5 minutes as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;200 tasks × (60 hours × 12 refreshes per hour) = 144,000 refresh calls.&lt;/li&gt;
&lt;li&gt;144,000 calls × 3 parameters each = 432,000 parameter interactions.&lt;/li&gt;
&lt;li&gt;A Lambda function handling checkout cold starts approximately 8,000 times during traffic bursts, creating 24,000 additional interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is approximately 456,000 parameter interactions for the 60-hour sale. With higher throughput enabled, the application avoids throttling errors caused by hitting quota limits. At $0.05 per 10,000 interactions, the total additional cost is $2.28.&lt;/p&gt;

&lt;p&gt;Because the higher-throughput setting is billed on usage, you can enable it before an anticipated traffic spike and disable it afterward. If your application is throttled during normal production workloads, however, consider enabling higher throughput as a permanent setting.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enabling higher throughput in the AWS console and CLI
&lt;/h2&gt;

&lt;p&gt;A throughput setting applies at the account and Region level. It takes effect for all applications reading from Parameter Store in the specified scope.&lt;/p&gt;

&lt;p&gt;In the console, increase throughput by choosing &lt;strong&gt;Systems Manager &amp;gt; Parameter Store &amp;gt; Settings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the AWS CLI, run the following command to enable higher throughput, replacing the AWS Region and account ID with your own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shell
aws ssm update-service-setting &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--setting-id&lt;/span&gt; arn:aws:ssm:us-east-1:123456789012:servicesetting/ssm/parameter-store/high-throughput-enabled &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--setting-value&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Optimizing read patterns
&lt;/h2&gt;

&lt;p&gt;Optimizing how your application retrieves parameters is an operational best practice. If your application retrieves only necessary parameters and caches values that it reads repeatedly, it reduces latency and uses throughput more efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoid retrieving more than your application needs.&lt;/strong&gt; Parameter hierarchies are a useful way to organize configuration values. For example, you can group parameters for a checkout application as follows: &lt;code&gt;/prod/checkout/db-host&lt;/code&gt;, &lt;code&gt;/prod/checkout/inventory-service-endpoint&lt;/code&gt;, and &lt;code&gt;/prod/checkout/order-dlq-arn&lt;/code&gt;. It’s tempting to use &lt;code&gt;GetParametersByPath&lt;/code&gt; to retrieve an entire subtree when your application knows the specific parameters it needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="c"&gt;# Gets the subtree, including parameters your app might not need`&lt;/span&gt;
&lt;span class="sb"&gt;`&lt;/span&gt;aws ssm get-parameters-by-path &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="s2"&gt;"/prod/checkout/"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--recursive&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--with-decryption&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With higher throughput enabled, &lt;code&gt;GetParametersByPath&lt;/code&gt; is limited to 100 TPS, compared to 1,000 for &lt;code&gt;GetParameters&lt;/code&gt; and 10,000 for single-parameter &lt;code&gt;GetParameter&lt;/code&gt; calls. With default throughput, all three share the same 40 TPS pool. If your application knows its parameter names, requesting them directly means that your application is less likely to hit the quota.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="c"&gt;# Retrieves only the parameters your app actually needs&lt;/span&gt;
aws ssm get-parameters &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--names&lt;/span&gt; &lt;span class="s2"&gt;"/prod/checkout/db-host"&lt;/span&gt; &lt;span class="s2"&gt;"/prod/checkout/inventory-service-endpoint"&lt;/span&gt; &lt;span class="s2"&gt;"/prod/checkout/order-dlq-arn"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--with-decryption&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a best practice, remove unused parameters from a hierarchy. You prevent &lt;code&gt;GetParametersByPath&lt;/code&gt; calls from returning parameters that the application doesn’t need and can reduce the paginated requests for larger hierarchies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache parameter values in the application.&lt;/strong&gt; Many configuration values don’t change often enough to justify reading them on every request. If your application reads the same parameter many times per minute, read it once and reuse the value for an appropriate period. For example, use a short reuse window for values that change often and a longer one for values that don’t. &lt;/p&gt;

&lt;p&gt;The following sample code defines a &lt;code&gt;get_parameter()&lt;/code&gt; function. You can call this function every 10 seconds for a specific parameter. The first call after the five-minute TTL expires retrieves the latest value from Parameter Store and updates the cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;ssm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ssm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;TTL_SECONDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;  &lt;span class="c1"&gt;# how long to trust a cached value
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pname&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cached_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pname&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;cached_at&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;TTL_SECONDS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Parameter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pname&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spread out reads when many resources start at the same time.&lt;/strong&gt; A common source of throttling is simultaneous startup. This occurs when many EC2 instances or ECS tasks read the same parameters within the same second during deployment or scaling. You can avoid concentrating the read burst by reading parameters once and passing the values to the application, or by staggering reads with a slight delay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Lambda functions, consider the AWS Parameters and Secrets Lambda Extension.&lt;/strong&gt; The extension caches parameter values locally for reuse across invocations. This reduces both the number of calls to Parameter Store and the latency of retrieving values. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Your application logs might show &lt;code&gt;ThrottlingException&lt;/code&gt; or &lt;code&gt;RateExceeded&lt;/code&gt;errors from &lt;code&gt;GetParameter&lt;/code&gt;, &lt;code&gt;GetParameters&lt;/code&gt;, or &lt;code&gt;GetParametersByPath&lt;/code&gt;. The results of throttling can be outages and degraded customer experience.&lt;/p&gt;

&lt;p&gt;Enabling the higher-throughput setting removes the risk of hitting an API quota during production. You can enable it before an anticipated event and disable it afterward, or leave it on permanently. For most production workloads, the operational benefit of resilience outweighs the modest cost.&lt;/p&gt;

&lt;p&gt;You can also address latency by optimizing read patterns. For example, you can replace a &lt;code&gt;GetParametersByPath&lt;/code&gt; call with &lt;code&gt;GetParameters&lt;/code&gt;, or cache values in your application. The combination of higher throughput and optimized reads helps make your application more resilient when multiple tasks run concurrently. &lt;/p&gt;

&lt;p&gt;Questions? Comments? Leave them below!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>parameterstore</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>Improving operational resilience by decoupling code deployments from feature activation using AWS AppConfig feature flags</title>
      <dc:creator>Aparna Krishnamoorthy</dc:creator>
      <pubDate>Wed, 13 May 2026 14:31:22 +0000</pubDate>
      <link>https://dev.to/aparkris/improving-operational-resilience-by-decoupling-code-deployments-from-feature-activation-using-aws-i3</link>
      <guid>https://dev.to/aparkris/improving-operational-resilience-by-decoupling-code-deployments-from-feature-activation-using-aws-i3</guid>
      <description>&lt;p&gt;Shipping quickly isn’t the hard part anymore. The hard part is recovering when something goes wrong.&lt;br&gt;
A lot of teams still release features the same way: deploy code and whatever’s in that deployment goes live immediately. It’s simple, and it works — until it doesn’t. Because when a feature causes problems, you don’t just turn off the feature. You end up rolling back the entire deployment. That means waiting, coordinating, and sometimes introducing new risk just to undo the last change.&lt;br&gt;
That’s a heavy price to pay for something that should be lightweight.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Where the risk actually comes from *&lt;/em&gt;&lt;br&gt;
The issue isn’t deployments themselves. It’s the fact that feature activation is tightly coupled to them. When those two things are tied together, every release becomes an all-or-nothing event. A small issue can impact your entire user base, and recovery depends on how quickly you can redeploy or roll back. That’s where Mean Time to Resolution starts to creep up—not because the fix is complicated, but because the mechanism to apply it is. It also makes it difficult to test safely in production. You either release to everyone or no one, which isn’t much of a choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separating deployment from release&lt;/strong&gt;&lt;br&gt;
A more resilient approach is to treat deployment and feature release as two different concerns. You can deploy code whenever you want, but keep new functionality inactive until you explicitly turn it on. That control layer is what feature flags provide.&lt;/p&gt;

&lt;p&gt;Using AWS AppConfig on Amazon Web Services, feature state becomes configuration rather than code. Your application checks that configuration at runtime and decides which path to execute.&lt;br&gt;
That one change removes the need to redeploy just to change behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What changes in practice&lt;/strong&gt;&lt;br&gt;
Instead of hardcoding whether a feature is on or off, your application asks AWS AppConfig for the current state and responds accordingly. The flow is straightforward: the application retrieves configuration, evaluates the relevant flag, and executes the appropriate logic.&lt;br&gt;
Here’s a simple example. Imagine you’re introducing a new checkout flow.&lt;br&gt;
Your configuration might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"flags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"enableNewCheckout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enable new checkout experience"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"constraints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"enableNewCheckout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That lives in AWS AppConfig, not in your codebase.&lt;/p&gt;

&lt;p&gt;To retrieve it at runtime, use AWS AppConfig Agent. The agent is an Amazon-managed process that retrieves configuration data from AWS AppConfig in the cloud. It caches configuration data locally and asynchronously polls the AWS AppConfig data plane for updates. This approach keeps configuration data readily available to your application while reducing latency and cost.&lt;br&gt;
&lt;em&gt;Although you can retrieve configuration data by calling the APIs directly, using the agent is the recommended approach. It improves application performance and simplifies configuration management.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With your configuration profile stored in AWS AppConfig and the agent running in your compute environment, using the configuration is just a conditional in your application logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;application_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MyDemoApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MyEnvironment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config_profile_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MyConfigProfile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// retrieve a single flag's data by providing the "flag" query string parameter&lt;/span&gt;
    &lt;span class="c1"&gt;// note: the configuration's type must be AWS.AppConfig.FeatureFlags&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`http://localhost:2772/applications/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;application_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/environments/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;environment_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/configurations/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config_profile_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?flag=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;flag_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleCheckout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enableNewCheckoutFlag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enableNewCheckout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// {"enabled":true,"version":"2.0"}&lt;/span&gt;


  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enableNewCheckoutFlag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;newCheckoutFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;legacyCheckoutFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That small shift—moving the decision out of your deployment and into runtime configuration—gives you a surprising amount of control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reducing mean time to resolution with gradual deployments&lt;/strong&gt;&lt;br&gt;
One of the less obvious benefits of feature flags is how they change how quickly you understand and resolve issues, not just how you prevent them.&lt;br&gt;
When you roll out a feature gradually using AWS AppConfig, you’re effectively turning a production release into a controlled experiment. Instead of exposing 100% of users at once, you start with a small segment and watch what happens. That alone shortens the feedback loop. If something is wrong, you’ll see it earlier—and in a much smaller slice of traffic. But the real impact on mean time to resolution comes from the combination of three things working together:&lt;br&gt;
First, reduced scope. If only 5% of users are impacted, you’re not dealing with a full-scale incident. That lowers urgency just enough to make debugging more methodical instead of reactive.&lt;br&gt;
Second, clearer signal. When a change is introduced gradually, it’s easier to correlate cause and effect. You’re not sifting through noise from a full deployment—you’re looking at a controlled change with a defined rollout window.&lt;br&gt;
Third, faster reversal. If metrics start trending in the wrong direction, you don’t need to redeploy or coordinate a rollback. You stop the rollout or revert the configuration.  Integration with Amazon CloudWatch or monitoring platforms like DataDog and New Relic (using custom extensions) allow you to define guardrails. If key metrics cross a threshold, AWS AppConfig can automatically roll back to a known good configuration without waiting for someone to step in.&lt;br&gt;
Put together, gradual deployments don’t just reduce blast radius—they reduce the time it takes to understand, isolate, and resolve issues in the first place.&lt;br&gt;
&lt;em&gt;AWS AppConfig also supports pre-deployment syntax and functional validation through integration with AWS Lambda. Pre-deployment validation reduces the chance of a bad configuration making it into production in the first place.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operational feature flags that make a difference&lt;/strong&gt;&lt;br&gt;
Once you start using feature flags, it’s tempting to think of them only in terms of user-facing features. In practice, some of the most valuable flags are operational—they exist purely to give you more control during incidents or high-risk changes.&lt;br&gt;
A simple but powerful example is an operational toggle or kill switch. Instead of rolling back an entire service, you can disable a specific capability that’s causing issues. This is especially useful for integrations or newly introduced dependencies where failure modes aren’t fully understood yet.&lt;br&gt;
Another common pattern is traffic shaping. You can route a percentage of requests to a new code path, a new backend, or even a different region. If something looks off, you dial it back immediately. This gives you a level of control that traditional deployments don’t offer.&lt;br&gt;
You can also use flags to control fallback behavior. For example, if a downstream dependency starts failing, a flag can switch your application into a degraded mode—serving cached data, skipping non-critical steps, or simplifying responses. That kind of switch can be the difference between a partial degradation and a full outage.&lt;br&gt;
There’s also value in flags that control operational safeguards. Rate limiting thresholds, retry behavior, or timeout values can all be externalized into configuration. Instead of pushing a code change during an incident, you adjust behavior in real time.&lt;br&gt;
Finally, some teams use feature flags to control observability itself. Increasing logging, enabling additional metrics, or turning on debug paths can all be done dynamically. When paired with validation via AWS Lambda, you can safely introduce these changes without risking malformed configurations.&lt;br&gt;
None of these flags are particularly complex on their own. What matters is that they give you options when things aren’t going smoothly.&lt;br&gt;
And that’s really the point: operational resilience isn’t just about preventing failures—it’s about having enough control to respond effectively when they happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When this starts to matter&lt;/strong&gt;&lt;br&gt;
This approach becomes especially valuable once you’re deploying frequently or operating systems where uptime really matters. If you’ve ever had to rush a rollback, or sit through a tense deployment wondering if something might break, you’ve already felt the limitations of tightly coupled releases.&lt;br&gt;
Decoupling feature activation from deployment doesn’t eliminate failures, but it makes them smaller and easier to recover from.&lt;/p&gt;

&lt;p&gt;Most teams focus on improving how they deploy code. Fewer spend time improving how they release features. Using AWS AppConfig shifts that focus. It gives you a way to control behavior independently of deployments, which in turn makes your system more resilient and your releases less stressful. It’s not a massive architectural overhaul. It’s a small change in where decisions are made.&lt;/p&gt;

&lt;p&gt;But it has a disproportionate impact on how safely you can move.&lt;/p&gt;

&lt;p&gt;For more information, see the &lt;a href="https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html" rel="noopener noreferrer"&gt;AWS AppConfig User Guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>aws</category>
      <category>cicd</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
