npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

aws-cdk-conf-n-tags

v0.1.2

Published

Per-environment configuration loading (schema-validated) and stack tagging for AWS CDK apps.

Readme

aws-cdk-conf-n-tags

npm license

Per-environment configuration loading and stack tagging for AWS CDK apps.

  • One YAML file per environment, selected with --context env=<name>.
  • Schema-validated with zod — typos and bad values fail loudly at synth time, and the validated config is fully typed.
  • Account/region guard — refuses to synth an environment against the wrong AWS account or region.
  • Immutable config — the loaded values are frozen; this is a config object, not a place to stash resource references.
  • Centralized tagging — apply arbitrary tags plus auto CreatedBy / WorkDir tags to every resource in a stack.

Install

This package is used inside an AWS CDK app. If you don't have one yet, scaffold it first with the CDK CLI in an empty directory:

mkdir my-infra && cd my-infra
cdk init app --language typescript

Then, from inside that CDK app directory (where package.json and cdk.json live), install this package:

npm install aws-cdk-conf-n-tags zod

This both adds the entries to your package.json dependencies and installs them, in one step (modern npm writes to package.json by default — no --save needed). If you prefer, you can instead add the dependencies to package.json by hand and then run npm install with no arguments.

aws-cdk-lib (^2), constructs (^10), and zod (^4) are peer dependencies. Your CDK app already has the first two; install zod yourself — you import it to declare your schema, and a single shared zod instance is required for validation to work (a second copy would break the internal schema checks).

Quick start

1. Declare your schema

Extend BaseConfigSchema (which already covers awsAccount, awsRegion, tags, and the tag-name overrides) with the parameters your stack needs:

// config-schema.ts
import { BaseConfigSchema } from 'aws-cdk-conf-n-tags';
import { z } from 'zod';

export const ConfigSchema = BaseConfigSchema.extend({
  vpcId: z.string(),
  asgMinCapacity: z.number().int().default(1),
  asgMaxCapacity: z.number().int().default(1),
  ec2InstanceType: z.string().default('t4g.micro'),
  auroraEngineVersion: z.enum(['5.7', '8.0']).default('5.7'),
  serverlessMinCapacity: z.number().min(0.5).default(1),
  certificateArns: z.array(z.string()).optional(),
});

2. Load and use it in your stack

import { Stack, type StackProps } from 'aws-cdk-lib';
import { Vpc } from 'aws-cdk-lib/aws-ec2';
import type { Construct } from 'constructs';
import { Config } from 'aws-cdk-conf-n-tags';
import { ConfigSchema } from './config-schema.js';
import { MyAsg } from './my-asg.js'; // your own construct

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Resolves env from `--context env=...`, reads config/<env>.yaml,
    // validates it, and checks the account/region. `conf.values` is typed + frozen.
    const conf = Config.load(this, ConfigSchema);

    // Tag every resource in the stack (config tags + auto CreatedBy/WorkDir).
    conf.tagStack(this);

    // Pass config values to constructs explicitly.
    const vpc = Vpc.fromLookup(this, 'vpc', { vpcId: conf.values.vpcId });
    new MyAsg(this, 'asg', { vpc, min: conf.values.asgMinCapacity });
  }
}

3. Add a config file per environment

# config/production.yaml
awsAccount: "012345678901"   # quote it — preserves leading zeros
awsRegion: us-west-2

vpcId: vpc-0abc123def4567890
asgMinCapacity: 2
auroraEngineVersion: "8.0"

tags:
  Product: my-product
  Cluster: web-001
  Env: Production
  RetentionDays: 28          # non-string values are coerced to strings when tagging

Deploy with:

cdk deploy --context env=production

Using from JavaScript

The package ships both ESM and CommonJS builds, so it works in JavaScript CDK apps (cdk init app --language javascript) just as well as TypeScript ones. The API is identical — you only give up the compile-time layer (z.infer types and tsc checking). Runtime validation still catches typos, bad types, and out-of-range values and applies defaults, because that is zod behavior, not TypeScript.

ESM JavaScript (a project with "type": "module" in its package.json):

import { Stack } from 'aws-cdk-lib';
import { Config, BaseConfigSchema } from 'aws-cdk-conf-n-tags';
import { z } from 'zod';

const ConfigSchema = BaseConfigSchema.extend({
  vpcId: z.string(),
  asgMinCapacity: z.number().int().default(1),
});

export class MyStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const conf = Config.load(this, ConfigSchema);
    conf.tagStack(this);
    // conf.values.vpcId, conf.values.asgMinCapacity, ...
  }
}

CommonJS JavaScript (the default cdk init --language javascript template) is the same, with require:

const { Config, BaseConfigSchema } = require('aws-cdk-conf-n-tags');
const { z } = require('zod');

Tip: even in .js files, editors like VS Code read the package's bundled type declarations and offer autocomplete and hover docs on conf.values.

How it behaves

  • Environment selectionConfig.load reads the env name from CDK context (--context env=<name>; the key is configurable). It then loads config/<env>.yaml relative to the current working directory.
  • Validation — unknown keys are rejected by default (unknownKeys: 'strict'), so a mistyped key like asgMinCapcity errors instead of silently using a default. Types, enums, numeric ranges, and required/default are all enforced by your schema. Switch to 'strip' or 'passthrough' if you need leniency.
  • Account/region guardawsAccount / awsRegion in the file are checked against CDK_DEFAULT_ACCOUNT / CDK_DEFAULT_REGION (override via options, or disable with verifyAccountRegion: false).
  • Immutabilityconf.values is Object.freeze'd, so it can't double as a mutable bag for created resources. Share those via explicit args or the StackResources helper instead.

Sharing resources between constructs

Because conf.values is frozen, it can't accumulate created resources the way a single mutable config object used to. To hand resources (VPC, database, …) from one construct to the next, you have two options.

Explicit props (most type-safe). Give each construct exactly what it needs:

const vpc = Vpc.fromLookup(this, 'vpc', { vpcId: conf.values.vpcId });
const db = new MyDb(this, 'db', { vpc, conf });
new MyBackup(this, 'backup', { dbCluster: db.cluster });

StackResources (one bag, fail-loud). If you prefer threading a single object through every construct, use the exported StackResources container. Unlike a plain object, reading a resource that hasn't been created yet throws a clear error instead of yielding undefined — valuable in JavaScript stacks where there's no compiler to catch it:

import { Config, StackResources } from 'aws-cdk-conf-n-tags';

const res = new StackResources();
res.set('vpc', Vpc.fromLookup(this, 'vpc', { vpcId: conf.values.vpcId }));
const db = res.set('db', new MyDb(this, 'db', { conf, res })); // set() returns the value

new MyBackup(this, 'backup', { conf, res });   // internally reads res.get('db').cluster

// res.get('cache') before the cache is created throws:
//   Resource "cache" was requested before it was created. Check the order ...

set(key, value) stores and returns the value; get(key) returns it or throws; has(key) checks; keys() lists what's been set. In TypeScript, parameterize it for typed keys and values: new StackResources<{ vpc: IVpc; db: MyDb }>().

API

Config.load(scope, schema, options?)

Returns a Config with:

| Member | Description | |---|---| | conf.values | The validated, frozen config (typed as z.infer<typeof schema>). | | conf.environment | The resolved environment name. | | conf.path | Absolute path of the file that was loaded. | | conf.tagStack(scope, options?) | Tag a stack using this config's tags + auto-tags. |

options (all optional):

| Option | Default | Description | |---|---|---| | contextKey | 'env' | CDK context key holding the environment name. | | environment | — | Provide the env name explicitly (skips context). | | configDir | 'config' | Directory holding <env>.yaml, relative to cwd. | | configPath | — | Explicit file path (overrides configDir). | | cwd | process.cwd() | Base directory for relative paths. | | unknownKeys | 'strict' | 'strict' | 'strip' | 'passthrough'. | | verifyAccountRegion | true | Cross-check account/region. | | account / region | CDK_DEFAULT_* | Expected account/region. |

tagStack(scope, options?)

Standalone tagging (no Config needed). Applies the working-directory tag, the created-by tag, then the explicit tags map, to every taggable resource in scope.

import { tagStack } from 'aws-cdk-conf-n-tags';

tagStack(stack, {
  tags: { Product: 'my-product', Env: 'Production' },
  auto: { workDir: false },                 // disable individual auto-tags
  tagNames: { createdBy: 'Blame' },         // rename auto-tag keys
  providers: { createdBy: () => 'ci-bot' }, // override how a value is computed
});

By default CreatedBy is derived from git config user.name / user.email (falling back to $USER), and WorkDir is process.cwd().

StackResources<T>

A fail-loud container for resources created during synthesis — see Sharing resources between constructs.

| Method | Description | |---|---| | set(key, value) | Store a resource and return it. | | get(key) | Return it, or throw if it was never set. | | has(key) | Whether a resource has been set. | | keys() | The keys set so far. |

loadConfig(schema, options)

The validation core without any CDK scope — useful for tests or non-CDK tooling. Returns { values, path }. See LoadOptions for the option shape.

Migrating from the original Config class

If you used the original JavaScript Config (which flattened every YAML key onto the instance and doubled as a mutable dependency bag):

  • Read config via conf.values.<key> instead of conf.<key>.
  • Declare a zod schema instead of relying on scattered || default fallbacks.
  • Stop writing resources back onto the config object (conf.vpc = vpc); pass them to constructs explicitly.
  • setTags(stack)conf.tagStack(stack).

Development

npm install
npm run build         # tsup → dist (ESM + CJS + d.ts/d.cts)
npm test              # vitest
npm run typecheck     # tsc --noEmit
npm run check:exports # publint + attw

Run a single test: npx vitest run test/loader.test.ts (or -t "<name>").

License

BSD-3-Clause © Eduard Moskvin