-
Notifications
You must be signed in to change notification settings - Fork 0
Compatibility
The adapter targets AWS Lambda's Node runtime. It uses no Node-version-specific features beyond native ESM and the bundled node:buffer module (imported only by read-lambda-body.js and local.js — the main handler has no node:* imports).
| Runtime | Status | Notes |
|---|---|---|
nodejs20.x |
✅ | LTS, default target. engines.node: '>=20'. |
nodejs22.x |
✅ | Current LTS at time of writing. |
nodejs18.x |
❌ | End-of-life on AWS Lambda. Won't run — engines.node blocks the install. |
| Lambda container images | ✅ | Any base image on the supported Node runtime list. |
For non-Lambda hosting (testing, local dev), the local-debug bridges expand the surface — see below.
All four supported via a single auto-detecting factory:
| Trigger | Payload format | Result envelope |
|---|---|---|
| API Gateway REST API | 1.0 | APIGatewayProxyResult |
| API Gateway HTTP API | 2.0 | APIGatewayProxyStructuredResultV2 |
| Lambda Function URL | 2.0 | APIGatewayProxyStructuredResultV2 |
| Application Load Balancer | 1.0-ish |
ALBResult (+ multiValueHeaders on ALB multi-value mode) |
See Event shapes for the detection rules and per-shape gotchas.
Unlike dynamodb-toolkit-koa, dynamodb-toolkit-express, or dynamodb-toolkit-fetch, this package has no framework peer. @types/aws-lambda is a dev-only type dependency; the production runtime is AWS Lambda's Node runtime, which is ambient on the target platform.
peerDependencies:
{
"peerDependencies": {
"dynamodb-toolkit": "^3.7.0"
}
}The bridges in dynamodb-toolkit-lambda/local.js let you run the Lambda handler under any of these runtimes without deploying:
| Runtime | Bridge | Notes |
|---|---|---|
| Node 20+ | createNodeListener |
http.createServer(listener).listen(port). |
| Bun | createFetchBridge |
Bun.serve({port, fetch: bridge}). |
| Deno | createFetchBridge |
Deno.serve({port}, bridge). |
| Cloudflare Workers | createFetchBridge |
export default {fetch: bridge}. |
| Hono / itty-router | createFetchBridge |
Pass the raw Request. |
| Koa / Express (as glue) | createNodeListener |
10 lines of glue; see Local debug bridges. |
The Node bridge depends on node:http + node:buffer; the Fetch bridge depends on node:buffer only (used for base64 ↔ bytes). Bun and Deno ship node:buffer as a compat shim; Cloudflare Workers ship it as part of the nodejs_compat flag.
The adapter's unit test suite runs identically under Node / Bun / Deno via the local-debug bridges:
| Runtime | Command | Tests / Asserts | Notes |
|---|---|---|---|
| Node | npm test |
84 / 174 | Includes a .cjs smoke (Node-only) |
| Bun | npm run test:bun |
79 / 169 | Same suite minus the .cjs smoke |
| Deno | npm run test:deno |
79 / 169 | Same |
The 5-test delta is the .cjs smoke scoped to Node via tape6's node config key — CommonJS-from-ESM-sibling semantics differ between Bun and Deno, so it doesn't run there.
TypeScript smoke (npm run ts-test / ts-test:bun / ts-test:deno): identical counts on all three.
engines.node is >=20. Two sub-floors worth knowing:
-
require(esm)interop for CJS consumers — 20.19+ on the 20.x line, 22.12+ on 22.x, unflagged everywhere newer. The.cjssmoke test exercises this. -
Native TypeScript — Node 22.6+ (with
--experimental-strip-types) or 23.6+ (unflagged). Used bynpm run ts-test. Bun and Deno run.tsnatively without special setup.
Both smoke-tests are included so you can verify your target runtime handles the adapter correctly.
AWS Lambda's nodejs20.x runtime image ships Node 20.15 at the time of writing; .cjs interop and native TS are not available there. Use ESM for handler modules (the "type": "module" flag in package.json) and compile TypeScript ahead of deployment.
require('dynamodb-toolkit-lambda') works on Nodes that ship require(esm) (20.19+ / 22.12+ / anything newer):
const {createLambdaAdapter} = require('dynamodb-toolkit-lambda');
const {createNodeListener} = require('dynamodb-toolkit-lambda/local.js');AWS Lambda's nodejs20.x image ships 20.15, which predates require(esm). CJS handlers on Lambda need to either:
- Wait for the Lambda runtime to advance to 20.19+ (rolling release), or
- Use an ESM handler module (
"type": "module"+import).
ESM is the recommended default on Lambda — the AWS CLI / IaC tooling supports it natively.
Hand-written .d.ts sidecars ship next to each .js file. package.json declares main, module, and types for all resolution styles:
{
"main": "./src/index.js",
"module": "./src/index.js",
"types": "./src/index.d.ts",
"exports": {
".": "./src/index.js",
"./*": "./src/*"
}
}The factory is generic in TItem so typed Adapter<Item, Key> instances flow through without casts:
import {Adapter} from 'dynamodb-toolkit';
import {createLambdaAdapter, type LambdaAdapterOptions} from 'dynamodb-toolkit-lambda';
interface Planet extends Record<string, unknown> {
name: string;
climate?: string;
}
type PlanetKey = Pick<Planet, 'name'>;
const adapter = new Adapter<Planet, PlanetKey>({client, table: 'planets', keyFields: ['name']});
const opts: LambdaAdapterOptions<Planet> = {
mountPath: '/planets',
keyFromPath: (raw, a) => ({[a.keyFields[0].name]: raw}),
policy: {defaultLimit: 25, maxLimit: 200}
};
export const handler = createLambdaAdapter(adapter, opts);See tests/test-typed.ts in the source tree for a runnable typed example.
The adapter imports from aws-lambda (namespace @types/aws-lambda) for event / result / context types. @types/aws-lambda is a dev-only type dependency — nothing at runtime depends on it. If your TypeScript config is strict and you don't explicitly add it to your project, you'll get a "cannot find module 'aws-lambda'" error — install it yourself:
npm install --save-dev @types/aws-lambdaCallers who don't care about the precise event type can use the re-exported LambdaEvent / LambdaResult aliases from this package, which expand to the same union:
import type {LambdaEvent, LambdaResult} from 'dynamodb-toolkit-lambda';
const myWrapper = async (event: LambdaEvent): Promise<LambdaResult> => /* ... */;-
ESM-only source.
.js+ hand-written.d.ts, no build step. Runs on Lambda via the native ESM loader ("type": "module"). -
Zero runtime dependencies.
dynamodb-toolkitis a peer dep; no framework peer. -
node:bufferis the onlynode:*import at runtime, and only insideread-lambda-body.js+local.js. The mainindex.jshas no Node-specific imports — it runs verbatim on any runtime with a reasonableBuffershim, which covers every Lambda-compatible environment.
The adapter's own test matrix exercises the full route pack:
- 79 tests, 169 assertions under Bun / Deno (via the local-debug bridges).
-
84 tests, 174 assertions under Node (adds a
.cjsrequire-interop smoke). - TypeScript smoke tests via
ts-test— runs on Node (native.tssupport on 22.6+), Bun, and Deno.
No sam local integration test is wired into CI — the local-debug bridges give equivalent coverage with no Docker dependency. If you need sam local confirmation for a specific trigger config (e.g. a custom authorizer), exercise it manually against the dev bridge first, then sam-local only for the trigger-side verification.