appconfig-extension
Fetches AppConfig configuration and feature flags via the AWS AppConfig Lambda Extension. The extension runs as a sidecar process and handles polling, caching, and session token management internally, with no AWS SDK required.
Use this middleware instead of @middy/appconfig when your Lambda function uses the AppConfig Lambda Layer. For SDK-direct access (IAM role assumption, X-Ray capture) use @middy/appconfig instead.
Prerequisites
Add the AWS AppConfig Lambda Extension layer to your Lambda function.
Incompatible with AWS Lambda Code Signing. The extension is deployed as an AWS-published Lambda Layer. If your function has a Code Signing Configuration that restricts layers to your own approved signing profiles, this layer cannot be attached. In that case use @middy/appconfig instead.
Install
To install this middleware you can use NPM:
npm install --save @middy/appconfig-extension Options
fetchData(object) (required): Mapping of internal key name to AppConfig target.application(string) (required): Application name or ID.environment(string) (required): Environment name or ID.configuration(string) (required): Configuration profile name or ID.flag(string | string[]) (optional): One or more feature flag keys to filter the response.
disablePrefetch(boolean) (defaultfalse): Disable prefetching on cold start.cacheKey(string) (default@middy/appconfig-extension): Cache key for the fetched data. Must be unique across middleware.cacheKeyExpiry(object) (default{}): Per-fetchData-key cache expiry overrides (ms;-1= forever,0= no cache).cacheExpiry(number) (default-1): How long fetch data responses should be cached.-1: cache forever,0: never cache,n: cache for n ms.setToContext(boolean) (defaultfalse): Copy fetched values ontorequest.context.
Notes
- Lambda is required to have IAM permission for
appconfig:StartConfigurationSessionandappconfig:GetLatestConfiguration. - The extension polls AppConfig on a schedule controlled by
AWS_APPCONFIG_EXTENSION_POLL_INTERVAL_SECONDS. SetcacheExpiryto match this interval to avoid serving stale configuration. - The extension listens on port
2772by default. Override with theAWS_APPCONFIG_EXTENSION_HTTP_PORTenvironment variable.
Troubleshooting
ECONNREFUSED 127.0.0.1:2772at invocation time means the AppConfig Lambda Extension layer is not attached to your function. Add the layer ARN (region- and architecture-specific) from the AWS docs linked under Prerequisites.HTTP 400/BadRequestExceptiontypically means theapplication,environment, orconfigurationvalue infetchDatadoes not match an existing AppConfig resource. Use the resource name or ID exactly as defined in AppConfig.HTTP 403means the layer reached AppConfig but IAM denied the call. Grantappconfig:StartConfigurationSessionandappconfig:GetLatestConfigurationfor the specific configuration profile ARNs your function reads.- The layer ARN is regional. A function deployed to
us-east-1cannot reuse theeu-west-1ARN; pick the matching row from the AWS layer list.
Sample usage (JSON configuration)
import middy from '@middy/core'
import appConfigExtension from '@middy/appconfig-extension'
export const handler = middy()
.use(
appConfigExtension({
fetchData: {
config: {
application: 'my-app',
environment: 'production',
configuration: 'my-config'
}
}
})
)
.handler((event, context) => {
return {
statusCode: 200,
body: JSON.stringify({ message: 'hello world' })
}
}) Sample usage (feature flags)
import middy from '@middy/core'
import appConfigExtension from '@middy/appconfig-extension'
export const handler = middy()
.use(
appConfigExtension({
fetchData: {
flags: {
application: 'my-app',
environment: 'production',
configuration: 'my-flags',
flag: ['featureA', 'featureB']
}
},
setToContext: true
})
)
.handler(async (event, context) => {
const { featureA } = context.flags
return {
statusCode: 200,
body: JSON.stringify({ featureEnabled: featureA.enabled })
}
}) Usage with TypeScript
Configuration values in AppConfig can be arbitrary structured data. By default fetched values have type unknown. Use appConfigExtensionParam<T>() to provide type hints:
import middy from '@middy/core'
import { getInternal } from '@middy/util'
import appConfigExtension, { appConfigExtensionParam } from '@middy/appconfig-extension'
interface MyConfig {
featureFlag: boolean
maxRetries: number
}
const lambdaHandler = (event, context) => {
return {
statusCode: 200,
body: JSON.stringify({ message: 'hello world' })
}
}
export const handler = middy()
.use(
appConfigExtension({
fetchData: {
config: appConfigExtensionParam<MyConfig>({
application: 'my-app',
environment: 'production',
configuration: 'my-config'
})
}
})
)
.before(async (request) => {
const { config } = await getInternal('config', request)
// config.featureFlag (boolean)
// config.maxRetries (number)
})
.handler(lambdaHandler) Last updated: