Skip to content

sh-cloud-software/cdk-code-custom-command-example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Code.fromCustomCommand — CDK Example

This repository demonstrates how lambda.Code.fromCustomCommand works and when to reach for it.

What is Code.fromCustomCommand?

Code.fromCustomCommand(outputDir, command, options) lets you run an arbitrary shell command during CDK synthesis and use the directory it produces as a Lambda code asset. Under the hood CDK calls Node's spawnSync synchronously, waits for the command to finish, then treats outputDir exactly like Code.fromAsset() — zipping it and staging it to S3.

lambda.Code.fromCustomCommand(
  path.join(__dirname, '..', 'dist', 'lambda'), // output CDK will package
  ['bash', 'scripts/build.sh', 'dist/lambda'],  // command run during synthesis
  { commandOptions: { stdio: 'inherit' } },      // forwarded to spawnSync
)

When is this useful?

1. Polyglot or custom-toolchain builds

CDK's built-in Code.fromAsset bundles whatever is already on disk. Code.fromCustomCommand lets you drive the build step from within the CDK app itself — useful when:

  • Your Lambda is written in Rust, Go, or another language with its own build tool (cargo build, go build, …).
  • You need a bundler (esbuild, webpack, rollup) with flags or plugins that NodejsFunction doesn't expose.
  • You want to run post-processing steps (stripping debug symbols, injecting a version file, etc.) before the asset is zipped.

2. Downloading or retrieving pre-built artifacts

When there is no CDK-native way to pull in an asset from an external source — a private package registry, an S3 bucket, a GitHub release — you can shell out to aws s3 cp, curl, or any other tool and write the result to outputDir.

3. Running synth-time side effects (ignoring the asset)

Because the command runs unconditionally on every synth, you can use Code.fromCustomCommand purely for its side effects — generating config files, writing environment manifests, seeding a local cache — and simply point outputDir at a throwaway directory. The Lambda asset CDK produces from that directory can be a stub; the real value was the side effect.

How does the process work?

Execution flow

cdk synth / cdk diff / cdk deploy / npm test (when the test synthesizes the stack)
  │
  └─▶ CDK executes your app (bin/main.ts)
        │
        └─▶ new SampleStack(...)
              │
              └─▶ Code.fromCustomCommand(outputDir, command, options)
                    │
                    ├─ spawnSync(command[0], command.slice(1), options.commandOptions)
                    │   runs synchronously — CDK blocks until it exits
                    │
                    ├─ non-zero exit  →  synthesis fails immediately
                    │
                    └─ exit 0  →  CDK treats outputDir like Code.fromAsset(outputDir)
                                  (zip + stage to S3 asset store)

When the script runs

Command Script runs? Reason
cdk synth Synthesis executes the CDK app
cdk diff Diff synthesizes first
cdk deploy Deploy synthesizes first
npm test Tests that call Template.fromStack() synthesize the stack
npm run build Only compiles TypeScript; CDK app is never executed

Key properties

  • Synchronous — synthesis blocks on the command. Long-running builds will slow down every synth.
  • No caching — CDK runs the command on every synth, regardless of whether inputs changed. Add your own up-to-date check inside the script if you need to skip unnecessary work.
  • commandOptions — forwarded directly to Node's SpawnSyncOptions. Use this to control cwd, env, shell, stdio, and more.
  • Failure is fatal — a non-zero exit code aborts synthesis. Make your script exit cleanly on success and with a descriptive error message on failure.

Repository structure

bin/
  main.ts              # CDK app entry point
lib/
  sample-stack.ts      # Stack using Code.fromCustomCommand
scripts/
  build.sh             # Custom build script called during synthesis
test/
  sample-stack.test.ts # CDK assertions tests (also trigger the script)

Useful commands

Command Description
npm run build Compile TypeScript to JS (does not run the build script)
npm run watch Watch for changes and recompile
npm run test Run Jest unit tests (synthesizes the stack, so the build script runs)
npx cdk synth Emit the synthesized CloudFormation template (build script runs)
npx cdk diff Compare deployed stack with current state (build script runs)
npx cdk deploy Deploy the stack to your AWS account/region (build script runs)