The aws:lambda/callbackFunction:CallbackFunction resource, part of the Pulumi AWS provider, packages JavaScript functions into Lambda deployments automatically, handling code serialization, dependency bundling, and AWS configuration. This guide focuses on three capabilities: inline JavaScript deployment, factory functions for cold start optimization, and API Gateway event handling.
CallbackFunction creates IAM roles with broad default policies when you don’t specify role or policies explicitly. The examples may reference npm packages that must be in your project dependencies. The examples are intentionally small. Combine them with your own IAM configuration, VPC networking, and event sources.
Create a function from inline JavaScript code
Most serverless deployments start with a simple function that responds to events, without manual ZIP file creation or build steps.
import * as aws from "@pulumi/aws";
// Create an AWS Lambda function that fetches the Pulumi website and returns the HTTP status
const lambda = new aws.lambda.CallbackFunction("fetcher", {
callback: async(event) => {
try {
const res = await fetch("https://www.pulumi.com/robots.txt");
console.info("status", res.status);
return res.status;
}
catch (e) {
console.error(e);
return 500;
}
},
});
The callback property accepts an async JavaScript function that becomes your Lambda handler. Pulumi serializes the function, packages dependencies, and uploads everything to AWS Lambda automatically. The function can use standard Node.js APIs like fetch and returns values directly.
Optimize cold starts with factory functions
Applications with expensive setup (Express servers, database connections) benefit from running initialization once at module load time rather than on every invocation.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as express from "express";
import * as serverlessExpress from "aws-serverless-express";
import * as middleware from "aws-serverless-express/middleware";
const lambda = new aws.lambda.CallbackFunction<any, any>("mylambda", {
callbackFactory: () => {
const app = express();
app.use(middleware.eventContext());
let ctx;
app.get("/", (req, res) => {
console.log("Invoked url: " + req.url);
fetch('https://www.pulumi.com/robots.txt').then(resp => {
res.json({
message: "Hello, world!\n\nSucceeded with " + ctx.getRemainingTimeInMillis() + "ms remaining.",
fetchStatus: resp.status,
fetched: resp.text(),
});
});
});
const server = serverlessExpress.createServer(app);
return (event, context) => {
console.log("Lambda invoked");
console.log("Invoked function: " + context.invokedFunctionArn);
console.log("Proxying to express");
ctx = context;
serverlessExpress.proxy(server, event, <any>context);
}
}
});
The callbackFactory property accepts a function that runs once when Lambda loads your module. It performs expensive initialization (creating the Express app, configuring middleware), then returns the actual handler function that Lambda invokes for each request. This separates one-time setup from per-request logic, reducing cold start impact on subsequent invocations.
Handle API Gateway requests with typed events
API Gateway integrations require functions that accept specific event shapes and return HTTP-formatted responses.
import * as apigateway from "@pulumi/aws-apigateway";
import { APIGatewayProxyEvent, Context } from "aws-lambda";
const api = new apigateway.RestAPI("api", {
routes: [
{
path: "/api",
eventHandler: async (event: APIGatewayProxyEvent, context: Context) => {
return {
statusCode: 200,
body: JSON.stringify({
eventPath: event.path,
functionName: context.functionName,
})
};
},
},
],
});
export const url = api.url;
The eventHandler receives APIGatewayProxyEvent and Context parameters with typed access to request details. The function returns an object with statusCode and body properties that API Gateway translates into HTTP responses. The RestAPI resource wires the function to API Gateway routes automatically.
Beyond these examples
These snippets focus on specific CallbackFunction features: inline JavaScript code packaging, factory functions for initialization optimization, and API Gateway event handling. They’re intentionally minimal rather than full serverless applications.
The examples may reference pre-existing infrastructure such as npm packages (express, aws-serverless-express, aws-apigateway). They focus on function configuration rather than provisioning IAM roles or VPC networking.
To keep things focused, common Lambda patterns are omitted, including:
- IAM role and policy configuration (role, policies)
- Memory and timeout tuning (memorySize, timeout)
- Environment variables and secrets (environment)
- VPC networking (vpcConfig)
- Lambda Layers for shared code (layers)
- Code bundle customization (codePathOptions)
These omissions are intentional: the goal is to illustrate how CallbackFunction packages and deploys JavaScript code, not provide drop-in serverless modules. See the CallbackFunction resource reference for all available configuration options.
Let's create AWS Lambda Functions from JavaScript Callbacks
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Function Definition & Handlers
callback for simple handlers that run on every invocation. Use callbackFactory when you have expensive initialization work (like setting up an Express server) that should run once when the Lambda module loads. You must provide exactly one, not both.Permissions & IAM
role or policies, CallbackFunction creates a role with FullAccess to many services: Lambda, CloudWatch, S3, DynamoDB, SQS, Kinesis, CloudFormation, Cognito, and X-Ray. For production, explicitly provide role or policies following least-privilege principles.role and policies are mutually exclusive. Provide role to use an existing IAM role ARN, or policies to have CallbackFunction create a role with specific policy ARNs attached.Code Packaging & Layers
codePathOptions.extraIncludePaths to add local directories or files, and codePathOptions.extraExcludePackages to remove unneeded Node.js packages from the bundle.aws.lambda.LayerVersion with your shared code packaged in an AssetArchive, then attach it to functions using the layers property. Layer contents are extracted to /opt at runtime.nodejs/node_modules path within the layer zip file. Also add path mapping to your tsconfig.json with baseUrl and paths configuration to resolve imports during compilation.Configuration & Limits
memorySize property.durableConfig may only be available in limited regions, including us-east-2.Using a different cloud?
Explore serverless guides for other cloud providers: