Skip to content
AB
2 min readIntermediateReliable AWS Lambda Execution · Part 2

Why My Lambda Handlers Only Wire Dependencies

Keep handlers focused on transport concerns and dependency wiring so application behavior stays reusable and easy to test.

Ashish BhakhandPublished

A Lambda handler is an adapter between AWS and an application. When it also owns business rules, persistence, and notifications, those rules become difficult to reuse from a queue worker or test without AWS-shaped input.

I give handlers four jobs:

  1. translate and validate the incoming request;
  2. read authenticated context;
  3. construct concrete dependencies;
  4. map the application result to HTTP.
Code
const users = new MongoUserRepository(getDatabase());
const emails = new SesEmailGateway(getSesClient());
const register = registerUser({ users, emails });

export const handler = withHttp(async (request) => {
  const input = registrationSchema.parse(request.body);
  const user = await register(input);

  return {
    statusCode: 201,
    body: JSON.stringify({ id: user.id }),
  };
});

The handler reads almost like configuration. Registration rules live in registerUser, email delivery lives behind a gateway, and MongoDB queries live in the repository.

Reuse expensive clients#

AWS recommends initializing SDK clients and database connection machinery outside the handler so warm invocations can reuse them:

Code
const documentClient = DynamoDBDocumentClient.from(new DynamoDBClient({}));

export const handler = withHttp(async (request) => {
  // use the reused client through an adapter
});

Do not store request-specific data in module globals. Warm execution environments are reused, and state can leak between invocations.

Dependency injection does not require a container#

Plain constructor arguments and factory functions are often enough. A dependency-injection framework becomes useful only when the object graph is large enough to justify its lifecycle and registration model.

Explicit wiring has an important benefit: opening the handler shows which infrastructure a function can touch.

Know what to test#

Most decisions belong to use-case tests. Handler tests should cover the adapter contract: malformed input, authentication context, status codes, and serialization. Do not repeat every business test through API Gateway events.

Thin handlers do not reduce a Lambda to “just glue.” They make the glue honest. AWS-specific work stays visible at the entry point, while the behavior that matters remains portable TypeScript.

← Back to all writing