Runtime Configuration
Runtime configuration is the mechanism used by Nx Plugin for AWS to pass deploy-time values between generated projects and components so they can connect to one another. For example, when you generate an API, its URL is automatically registered in the runtime configuration so that a connected website can discover it.
How It Works
Section titled “How It Works”Runtime configuration is organised into namespaces. Each namespace is a logical grouping of related configuration values. At deploy time, all namespaces are stored in AWS AppConfig as Configuration Profiles.
The built-in connection namespace is used for configuration that enables generated projects to connect to each other, for example:
- API URLs — registered automatically by API constructs
- Cognito settings — registered automatically by the UserIdentity construct
- Agent runtime ARNs — registered automatically by agent constructs
The connection namespace is also deployed as a runtime-config.json file to your website’s S3 bucket, enabling client-side discovery of backend resources.
You can define as many additional namespaces as you like, providing a convenient alternative to environment variables for passing deploy-time values such as DynamoDB table names to your Lambda functions or other compute resources.
Infrastructure
Section titled “Infrastructure”Writing Configuration
Section titled “Writing Configuration”Generated constructs automatically write relevant configuration to the connection namespace. You can also write your own values to any namespace.
The RuntimeConfig CDK construct is a stage-scoped singleton. Use set() to write a key into a namespace:
import { RuntimeConfig } from ':my-scope/common-constructs';
const rc = RuntimeConfig.ensure(this);
// Built-in 'connection' namespace (written automatically by generated constructs)rc.set('connection', 'apis', { ...rc.get('connection').apis, MyApi: api.url,});
// Custom namespaces for server-side configurationrc.set('tables', 'users', { tableName: usersTable.tableName, tableArn: usersTable.tableArn,});At synth/deploy time, RuntimeConfig creates an AWS AppConfig application containing:
- A Configuration Profile for each namespace
- A Hosted Configuration Version with the JSON data for each profile
- An instant Deployment to the
defaultenvironment
Use the runtime-config/entry module to write a key into a namespace:
# Writes to the 'connection' namespace (done automatically by generated modules)module "add_api_url" { source = "../../common/terraform/src/core/runtime-config/entry"
namespace = "connection" key = "apis" value = { "MyApi" = module.my_api.api_url }}
# Custom namespace for server-side configurationmodule "add_table_config" { source = "../../common/terraform/src/core/runtime-config/entry"
namespace = "tables" key = "users" value = { tableName = aws_dynamodb_table.users.name arn = aws_dynamodb_table.users.arn }}You must then declare the runtime-config/appconfig module to create the AppConfig resources from all namespace files:
module "appconfig" { source = "../../common/terraform/src/core/runtime-config/appconfig"
application_name = "my-app-runtime-config"
depends_on = [module.add_api_url, module.add_table_config]}Reading Configuration
Section titled “Reading Configuration”Server-side consumers need the AppConfig Application ID and IAM permissions to read configuration at runtime. Generated constructs handle this automatically.
Use appConfigApplicationId to get the AppConfig Application ID, and grantReadAppConfig() to grant read permissions:
const rc = RuntimeConfig.ensure(this);
// Get the AppConfig Application ID (lazy token, resolved at synth time)const appId = rc.appConfigApplicationId;
// Pass it as an environment variable to a Lambda functionconst myFunction = new Function(this, 'MyFunction', { // ... environment: { RUNTIME_CONFIG_APP_ID: appId, },});
// Grant the function permission to read from AppConfigrc.grantReadAppConfig(myFunction);Reference the appconfig module’s application_id output to get the AppConfig Application ID, and add the appropriate IAM policy statements:
module "appconfig" { source = "../../common/terraform/src/core/runtime-config/appconfig" application_name = "my-app-runtime-config"}
# Pass the AppConfig Application ID as an environment variableresource "aws_lambda_function" "my_function" { # ... environment { variables = { RUNTIME_CONFIG_APP_ID = module.appconfig.application_id } }}
# Grant the function permission to read from AppConfigresource "aws_iam_policy" "appconfig_read" { name = "AppConfigReadPolicy" policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Action = [ "appconfig:StartConfigurationSession", "appconfig:GetLatestConfiguration" ] Resource = ["${module.appconfig.application_arn}/*"] }] })}Server-Side Access via AppConfig
Section titled “Server-Side Access via AppConfig”Server-side consumers such as Lambda functions and agents can retrieve runtime configuration from AWS AppConfig using AWS Lambda Powertools.
All generated API and agent constructs are automatically configured with:
- The
RUNTIME_CONFIG_APP_IDenvironment variable (the AppConfig Application ID) - IAM permissions to read from AppConfig
Use getAppConfig from @aws-lambda-powertools/parameters:
import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
// Retrieve the 'connection' namespace as a parsed JSON objectconst config = await getAppConfig('connection', { application: process.env.RUNTIME_CONFIG_APP_ID!, environment: 'default', transform: 'json',});
// Access valuesconst apiUrl = config.apis?.MyApi;const cognitoProps = config.cognitoProps;You can also retrieve custom namespaces:
// Retrieve a custom 'tables' namespaceconst tablesConfig = await getAppConfig('tables', { application: process.env.RUNTIME_CONFIG_APP_ID!, environment: 'default', transform: 'json',});
const usersTableName = tablesConfig.users?.tableName;Use get_app_config from aws_lambda_powertools.utilities.parameters:
import osfrom aws_lambda_powertools.utilities import parameters
# Retrieve the 'connection' namespace as a parsed JSON objectconfig = parameters.get_app_config( name="connection", environment="default", application=os.environ["RUNTIME_CONFIG_APP_ID"], transform="json",)
# Access valuesapi_url = config.get("apis", {}).get("MyApi")cognito_props = config.get("cognitoProps")You can also retrieve custom namespaces:
# Retrieve a custom 'tables' namespacetables_config = parameters.get_app_config( name="tables", environment="default", application=os.environ["RUNTIME_CONFIG_APP_ID"], transform="json",)
users_table_name = tables_config.get("users", {}).get("tableName")Client-Side Access
Section titled “Client-Side Access”For websites, the connection namespace is deployed as a runtime-config.json file to the S3 bucket. See the React Website Runtime Configuration guide for details on how to access these values from your frontend code.