Skip to main content

Function

A construct for a Lambda Function that allows you to develop it locally. Supports JS, TypeScript, Python, Golang, C#, Rust, and container runtime. It also applies a couple of defaults:

  • Sets the default memory setting to 1024MB.
  • Sets the default Lambda function timeout to 10 seconds.
  • Enables AWS X-Ray by default so you can trace your serverless applications.
  • AWS_NODEJS_CONNECTION_REUSE_ENABLED is turned on. Meaning that the Lambda function will automatically reuse TCP connections when working with the AWS SDK. Read more about this here.
  • Sets the IS_LOCAL environment variable for the Lambda function when it is invoked locally through the sst dev command.

Examples

Creating a Function

import { Function } from "sst/constructs";

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
});

Creating a Container Function

To create a container function, set runtime to "container" and point the handler to the directory containing the Dockerfile.

new Function(stack, "MyFunction", {
runtime: "container",
handler: "src/lambda",
});

Lambda will run the function specified in CMD section of the Dockerfile. If you want to create multiple functions from the same image but each with a different function, you can override the CMD:

new Function(stack, "MyFunction", {
runtime: "container",
handler: "src/lambda",
container: {
cmd: ["get.handler"]
}
});

new Function(stack, "MyFunction", {
runtime: "container",
handler: "src/lambda",
container: {
cmd: ["put.handler"]
}
});

Setting additional props

Use the cdk.lambda.FunctionOptions to set additional props.

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
timeout: 10,
environment: {
TABLE_NAME: "notes",
},
});

Setting default props

If you have properties that need to be applied to all the functions in your app, they can be set on the App construct using the setDefaultFunctionProps method.

app.setDefaultFunctionProps({
timeout: 20,
memorySize: 512,
});

Similarly, you can apply properties to all the functions in a specific Stack.

stack.setDefaultFunctionProps({
timeout: 20,
memorySize: 512,
});

Using SSM values as environment variables

import { StringParameter } from "aws-cdk-lib/aws-ssm";

const apiKey = StringParameter.valueFromLookup(stack, "my_api_key");

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
environment: {
API_KEY: apiKey,
},
});

The API_KEY environment variable can be accessed as process.env.API_KEY within the Lambda function.

Using IS_LOCAL environment variable

export async function main(event) {
return {
statusCode: 200,
headers: { "Content-Type": "text/plain" },
body: `Hello, World! Are we running locally: ${!!process.env.IS_LOCAL}`,
};
}

Configuring Node.js runtime

handler

The handler property points to the path of the entry point and handler function. Uses the format, /path/to/file.function. Where the first part is the path to the file, followed by the name of the function that's exported in that file.

For example, if your handler file is in src/lambda.ts and it exported a function called main. The handler would be src/lambda.main.

SST checks for a file with a .ts, .tsx, .js, or .jsx extension.

Configuring Python runtime

handler

Path to the entry point and handler function relative to the root. Uses the format, path/to/file.function. Where the first part is the path to the file, followed by the name of the function that's exported in that file. Note that you do not need a .py in the file path, just the name without the extension followed by the name of the handler function.

info

It is also necessary to have a requirements.txt (or Pipfile or poetry.lock) for the Python handler to know it is dealing with Python code.

new Function(stack, "PythonHelloWorld", {
handler: "packages/functions/src/lambda.hello",
runtime: "python3.11",
});

Configuring Go runtime

handler

Path to the handler function. Uses the format, /path/to/file.go or just /path/to.

Configuring Container runtime

handler

Path to the directory containing the Dockerfile relative to the root.

Configuring C#(.NET) runtime

handler

Path to the handler function. Uses the format, ASSEMBLY::TYPE::METHOD.

  • ASSEMBLY is the name of the .NET assembly file. If you haven't set the assembly name using the AssemblyName property in .csproj, the ASSEMBLY name will be the .csproj file name.
  • TYPE is the full name of the handler type. Consists of the Namespace and the ClassName.
  • METHOD is the name of the function handler.

Consider a project with MyApp.csproj and the following handler function:

namespace Example
{
public class Hello
{
public Stream MyHandler(Stream stream)
{
//function logic
}
}
}

The handler would be, MyApp::Example.Hello::MyHandler.

Configuring F#(.NET) runtime

handler

The handler function. Uses the format, ASSEMBLY::TYPE::METHOD.

  • ASSEMBLY is the name of the .NET assembly file. If you haven't set the assembly name using the AssemblyName property in .fsproj, the ASSEMBLY name will be the .fsproj file name.
  • TYPE is the full name of the handler type, which consists of the Namespace and the ClassName.
  • METHOD is the name of the function handler.

Consider a project with MyApp.fsproj and the following handler function:

namespace Example

module Hello =

let Handler(request:APIGatewayHttpApiV2ProxyRequest) =
//function logic

The handler would be: MyApp::Example.Hello::MyHandler.

Configuring Java runtime

Building a deployment package with Gradle

To create a deployment package with your function's code and dependencies, use the Zip build type. For example:

task buildZip(type: Zip) {
from compileJava
from processResources
into('lib') {
from configurations.runtimeClasspath
}
}

This build configuration produces a deployment package in the build/distributions directory. The compileJava task compiles your function's classes. The processResources task copies the Java project resources into their target directory, potentially processing then. The statement into('lib') then copies dependency libraries from the build's classpath into a folder named lib.

On sst deploy, SST runs gradle build to build the function. The build output has the follow content:

build
├─ classes
├─ distributions
│  ├─ java-hello-world.tar
│  └─ java-hello-world.zip
├─ generated
├─ libs
│  └─ java-hello-world.jar
├─ scripts
└─ tmp

And SST uploads the distributions/java-hello-world.zip as the Lambda function's code.

On sst dev, SST runs gradle build first. And then it unzips distributions/java-hello-world.zip to distributions. Now the distributions/lib folder contains all the dependency libraries. Both distributions/lib/* and libs/* are included as class paths when invoking the function under Live Lambda Dev.

note

Currenly, we only support Java projects built with Gradle. If you need to support other build systems, please join our Discord community and message us in the #help channel.

handler

The handler function. Uses the format, package.Class::method.

  • package is the package name.
  • Class is the class name.
  • method is the name of the function handler.

Consider a project with the following handler function:

package example

public class Handler implements RequestHandler<Map<String,String>, String>{

@Override
public Map<String, Object> handleRequest(Map<String, String> input, Context context) {
}
}

The handler would be: example.Handler::handleRequest.

options

If you want to configure the bundling process, you can pass in the FunctionBundleJavaProps.

new Function(stack, "MyLambda", {
java: {
buildTask: "bundle",
buildOutputDir: "output",
},
handler: "example.Handler::handleRequest",
runtime: "java17",
});

Configuring Rust runtime (beta)

handler

Path to the handler function. Uses the format, /path/to/file.rs.

Note that there needs to be a bin field in your Cargo.toml with a name that matches the file's name.

For example, if your handler file is in src/main.rs, then you should include the following block in your Cargo.toml:

[[bin]]
name = "main"
path = "src/main.rs"

Function URLs

Using the basic config

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
url: true,
});

Authorization

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
url: {
authorizer: "iam",
},
});

Disabling CORS

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
url: {
cors: false,
},
});

Configuring CORS

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
url: {
cors: {
allowMethods: ["GET", "POST"],
allowOrigins: ["https://domain.com"],
},
},
});

Enabling streaming

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
url: {
streaming: true,
},
});

Advanced examples

Configuring a Dead Letter Queue

const queue = new Queue(stack, "MyDLQ");

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
deadLetterQueue: queue.cdk.queue,
});

Configuring Provisioned Concurrency

const fn = new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
currentVersionOptions: {
provisionedConcurrentExecutions: 5,
},
});

const version = fn.currentVersion;

Note that Provisioned Concurrency needs to be configured on a specific Function version. By default, versioning is not enabled, and setting currentVersionOptions has no effect. By accessing the currentVersion property, a version is automatically created with the provided options.

Configuring VPC

import * as ec2 from "aws-cdk-lib/aws-ec2";

// Create a VPC
const vpc = new ec2.Vpc(stack, 'MyVPC');

// Alternatively use an existing VPC
const vpc = ec2.Vpc.fromLookup(stack, 'VPC', { ... });

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
}
});

If you need access to resources within a VPC, then run your AWS Lambda function within a VPC. If you do not require this access, then do not run it within a VPC.

Read more about working with VPC.

Using Existing IAM Roles

By default, a `Function`` creates its own IAM role. To use an existing IAM role, import it into your app.

import * as iam from "aws-cdk-lib/aws-iam";

const role = iam.Role.fromRoleName(stack, "ImportedRole", "my-existing-role");

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
role,
});

If sharing an imported IAM role across multiple stacks, import it only once. This prevents multiple stacks from appending identical policies repeatedly. Consider importing the role in a shared stack and referencing it in others.

// Shared stack
import * as iam from "aws-cdk-lib/aws-iam";
import { StackContext } from "sst/constructs";

export function Shared({ app, stack }: StackContext) {
return {
role: iam.Role.fromRoleName(stack, "ImportedRole", "my-existing-role"),
}
}

// Other stack
import { use, StackContext } from "sst/constructs";

export function Other({ app, stack }: StackContext) {
const { role } = use(Shared);

new Function(stack, "MyFunction", {
handler: "src/lambda.handler",
role,
});
}

Constructor

new Function(scope, id, props)

Parameters

FunctionProps

architecture?

Type : "x86_64" | "arm_64"

Default : "x86_64"

The CPU architecture of the lambda function.

new Function(stack, "Function", {
architecture: "arm_64",
})

bind?

Type : Array<BindingResource>

Bind resources for the function

new Function(stack, "Function", {
handler: "src/function.handler",
bind: [STRIPE_KEY, bucket],
})

container?

Type : ContainerProps

Used to configure container function properties

copyFiles?

Type : Array<FunctionCopyFilesProps>

Used to configure additional files to copy into the function bundle

new Function(stack, "Function", {
copyFiles: [{ from: "src/index.js" }]
})

disableCloudWatchLogs?

Type : boolean

Default : false

Disable sending function logs to CloudWatch Logs.

Note that, logs will still appear locally when running sst dev .

new Function(stack, "Function", {
handler: "src/function.handler",
disableCloudWatchLogs: true
})

diskSize?

Type : number | ${number} MB | ${number} GB

Default : "512 MB"

The amount of disk storage in MB allocated.

new Function(stack, "Function", {
handler: "src/function.handler",
diskSize: "2 GB",
})

enableLiveDev?

Type : boolean

Default : true

Can be used to disable Live Lambda Development when using sst start . Useful for things like Custom Resources that need to execute during deployment.

new Function(stack, "Function", {
handler: "src/function.handler",
enableLiveDev: false
})

environment?

Type : Record<string, string>

Configure environment variables for the function

new Function(stack, "Function", {
handler: "src/function.handler",
environment: {
TABLE_NAME: table.tableName,
}
})

functionName?

Type : string | (FunctionNameProps) => string

Default : Auto-generated function name

By default, the name of the function is auto-generated by AWS. You can configure the name by providing a string.

new Function(stack, "Function", {
handler: "src/function.handler",
functionName: "my-function",
})

go?

Type : GoProps

Used to configure go function properties

handler?

Type : string

Path to the entry point and handler function. Of the format:

/path/to/file.function .

new Function(stack, "Function", {
handler: "src/function.handler",
})

hooks?

Type : FunctionHooks

Hooks to run before and after function builds

java?

Type : JavaProps

Used to configure java function properties

layers?

Type : Array<string | ILayerVersion>

Default : no layers

A list of Layers to add to the function's execution environment.

Note that, if a Layer is created in a stack (say stackA ) and is referenced in another stack (say stackB ), SST automatically creates an SSM parameter in stackA with the Layer's ARN. And in stackB , SST reads the ARN from the SSM parameter, and then imports the Layer.

This is to get around the limitation that a Lambda Layer ARN cannot be referenced across stacks via a stack export. The Layer ARN contains a version number that is incremented everytime the Layer is modified. When you refer to a Layer's ARN across stacks, a CloudFormation export is created. However, CloudFormation does not allow an exported value to be updated. Once exported, if you try to deploy the updated layer, the CloudFormation update will fail. You can read more about this issue here - https://github.com/sst/sst/issues/549.

new Function(stack, "Function", {
layers: ["arn:aws:lambda:us-east-1:764866452798:layer:chrome-aws-lambda:22", myLayer]
})

logRetention?

Type : "one_day" | "three_days" | "five_days" | "one_week" | "two_weeks" | "one_month" | "two_months" | "three_months" | "four_months" | "five_months" | "six_months" | "one_year" | "thirteen_months" | "eighteen_months" | "two_years" | "three_years" | "five_years" | "six_years" | "seven_years" | "eight_years" | "nine_years" | "ten_years" | "infinite"

Default : Logs retained indefinitely

The duration function logs are kept in CloudWatch Logs.

When updating this property, unsetting it doesn't retain the logs indefinitely. Explicitly set the value to "infinite".

new Function(stack, "Function", {
handler: "src/function.handler",
logRetention: "one_week"
})

memorySize?

Type : number | ${number} MB | ${number} GB

Default : "1 GB"

The amount of memory in MB allocated.

new Function(stack, "Function", {
handler: "src/function.handler",
memorySize: "2 GB",
})

nodejs?

Type : NodeJSProps

Used to configure nodejs function properties

permissions?

Type : Permissions

Attaches the given list of permissions to the function. Configuring this property is equivalent to calling attachPermissions() after the function is created.

new Function(stack, "Function", {
handler: "src/function.handler",
permissions: ["ses"]
})

prefetchSecrets?

Type : boolean

Default : false

Prefetches bound secret values and injects them into the function's environment variables.

new Function(stack, "Function", {
handler: "src/function.handler",
prefetchSecrets: true
})

python?

Type : PythonProps

Used to configure python function properties

runtime?

Type : "container" | "rust" | "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "python3.7" | "python3.8" | "python3.9" | "python3.10" | "python3.11" | "python3.12" | "dotnetcore3.1" | "dotnet6" | "dotnet8" | "java8" | "java11" | "java17" | "java21" | "go1.x" | "go"

Default : "nodejs18.x"

The runtime environment for the function.

new Function(stack, "Function", {
handler: "function.handler",
runtime: "nodejs18.x",
})

timeout?

Type : number | ${number} second | ${number} seconds | ${number} minute | ${number} minutes | ${number} hour | ${number} hours | ${number} day | ${number} days

Default : "10 seconds"

The execution timeout in seconds.

new Function(stack, "Function", {
handler: "src/function.handler",
timeout: "30 seconds",
})

tracing?

Type : "active" | "pass_through" | "disabled"

Default : "active"

Enable AWS X-Ray Tracing.

new Function(stack, "Function", {
handler: "src/function.handler",
tracing: "pass_through",
})

url?

Type : boolean | FunctionUrlProps

Default : Disabled

Enable function URLs, a dedicated endpoint for your Lambda function.

new Function(stack, "Function", {
handler: "src/function.handler",
url: true
})
new Function(stack, "Function", {
handler: "src/function.handler",
url: {
authorizer: "iam",
cors: {
allowedOrigins: ['https://example.com'],
},
},
})

Properties

An instance of Function has the following properties.

id

Type : string

url

Type : undefined | string

The AWS generated URL of the Function.

Methods

An instance of Function has the following methods.

attachPermissions

attachPermissions(permissions)

Parameters

Attaches additional permissions to function.

fn.attachPermissions(["s3"]);

bind

bind(constructs)

Parameters

  • constructs Array<BindingResource>

Binds additional resources to function.

fn.bind([STRIPE_KEY, bucket]);

GoProps

Used to configure Go bundling options

buildTags?

Type : Array<string>

Default : []

The build tags to use when building the Go module.

go: {
buildTags: ["enterprise", "pro"],
}

cgoEnabled?

Type : boolean

Default : false

Whether to enable CGO for the Go build.

go: {
cgoEnabled: true,
}

ldFlags?

Type : Array<string>

Default : ["-s", "-w"]

The ldflags to use when building the Go module.

go: {
ldFlags: ["-X main.version=1.0.0"],
}

JavaProps

Used to configure Java package build options

buildOutputDir?

Type : string

Default : "distributions"

The output folder that the bundled .zip file will be created within.

new Function(stack, "Function", {
java: {
buildOutputDir: "output"
}
})

buildTask?

Type : string

Default : "build"

Gradle build command to generate the bundled .zip file.

new Function(stack, "Function", {
java: {
buildTask: "bundle"
}
})

experimentalUseProvidedRuntime?

Type : "provided" | "provided.al2"

Default : Not using provided runtime

Use custom Amazon Linux runtime instead of Java runtime.

new Function(stack, "Function", {
java: {
experimentalUseProvidedRuntime: "provided.al2"
}
})

NodeJSProps

Type : string

Use this to insert an arbitrary string at the beginning of generated JavaScript and CSS files.

nodejs: {
banner: "console.log('Function starting')"
}

esbuild?

Type : BuildOptions

This allows you to customize esbuild config.

format?

Type : "esm" | "cjs"

Default : "esm"

Configure format

nodejs: {
format: "cjs"
}

install?

Type : Array<string>

Packages that will be excluded from the bundle and installed into node_modules instead. Useful for dependencies that cannot be bundled, like those with binary dependencies.

nodejs: {
install: ["pg"]
}

loader?

Type : Record<string, Loader>

Configure additional esbuild loaders for other file extensions

nodejs: {
loader: {
".png": "file"
}
}

minify?

Type : boolean

Default : false

Enable or disable minification

nodejs: {
minify: true
}

sourcemap?

Type : boolean

Default : false

Configure if sourcemaps are generated when the function is bundled for production. Since they increase payload size and potentially cold starts they are not generated by default. They are always generated during local development mode.

nodejs: {
sourcemap: true
}

splitting?

Type : boolean

Default : false

If enabled, modules that are dynamically imported will be bundled as their own files with common dependencies placed in shared chunks. This can help drastically reduce cold starts as your function grows in size.

nodejs: {
splitting: true
}

PythonProps

Used to configure Python bundling options

dockerBuild?

Type : FunctionDockerBuildProps

Build options to pass to the docker build command.

installCommands?

Type : Array<string>

Default : "[]"

A list of commands to override the default installing behavior for Python dependencies.

Each string in the array is a command that'll be run. For example:

new Function(stack, "Function", {
python: {
installCommands: [
'export VARNAME="my value"',
'pip install --index-url https://domain.com/pypi/myprivatemodule/simple/ --extra-index-url https://pypi.org/simple -r requirements.txt .',
]
}
})

noDocker?

Type : boolean

This options skips the Python bundle step. If you set this flag to true , you must ensure that either:

  1. Your Python build does not require dependencies.
  2. Or, you've already installed production dependencies before running sst deploy .

One solution to accomplish this is to pre-compile your production dependencies to some temporary directory, using pip's --platform argument to ensure Python pre-built wheels are used and that your builds match your target Lambda runtime, and use SST's copyFiles

option to make sure these dependencies make it into your final deployment build.

This can also help speed up Python Lambdas which do not have external dependencies. By default, SST will still run a docker file that is essentially a no-op if you have no dependencies. This option will bypass that step, even if you have a Pipfile , a poetry.toml , a pyproject.toml , or a requirements.txt (which would normally trigger an all-dependencies Docker build).

Enabling this option implies that you have accounted for all of the above and are handling your own build processes, and you are doing this for the sake of build optimization.

FunctionHooks

afterBuild?

Type : (FunctionProps, string) => Promise<void>

Hook to run after build

beforeBuild?

Type : (FunctionProps, string) => Promise<void>

Hook to run before build

ContainerProps

buildArgs?

Type : Record<string, string>

Default : No build args

Build args to pass to the docker build command.

container: {
buildArgs: {
FOO: "bar"
}
}

buildSsh?

Type : string

Default : No --ssh flag is passed to the build command

SSH agent socket or keys to pass to the docker build command. Docker BuildKit must be enabled to use the ssh flag

container: {
buildSsh: "default"
}

cacheFrom?

Type : Array<FunctionDockerBuildCacheProps>

Default : No cache from options are passed to the build command

Cache from options to pass to the docker build command. DockerCacheOption[].

container: {
cacheFrom: [{ type: 'registry', params: { ref: 'ghcr.io/myorg/myimage:cache' }}],
}

cacheTo?

Type : FunctionDockerBuildCacheProps

Default : No cache to options are passed to the build command

Cache to options to pass to the docker build command. DockerCacheOption[].

container: {
cacheTo: { type: 'registry', params: { ref: 'ghcr.io/myorg/myimage:cache', mode: 'max', compression: 'zstd' }},
}

cmd?

Type : Array<string>

Specify or override the CMD on the Docker image.

container: {
cmd: ["index.handler"]
}

file?

Type : string

Name of the Dockerfile.

container: {
file: "path/to/Dockerfile.prod"
}

FunctionUrlProps

authorizer?

Type : "none" | "iam"

Default : "none"

The authorizer for the function URL

new Function(stack, "Function", {
handler: "src/function.handler",
url: {
authorizer: "iam",
},
})

cors?

Type : boolean | FunctionUrlCorsProps

Default : true

CORS support for the function URL

new Function(stack, "Function", {
handler: "src/function.handler",
url: {
cors: true,
},
})
new Function(stack, "Function", {
handler: "src/function.handler",
url: {
cors: {
allowedMethods: ["GET", "POST"]
allowedOrigins: ['https://example.com'],
},
},
})

streaming?

Type : boolean

Default : false *

Stream the response payload.

FunctionNameProps

functionProps

Type : FunctionProps

The function properties

stack

Type : Stack

The stack the function is being created in

FunctionUrlCorsProps

allowCredentials?

Type : boolean

Default : false

Specifies whether credentials are included in the CORS request.

allowHeaders?

Type : Array<string>

Default : Allow all headers.

The collection of allowed headers.

// Allow all headers
allowHeaders: ["*"]

// Allow specific headers
allowHeaders: ["Accept", "Content-Type", "Authorization"]

allowMethods?

Type : Array<"*" | "GET" | "PUT" | "HEAD" | "POST" | "DELETE" | "PATCH" | "OPTIONS">

Default : Allow all methods.

The collection of allowed HTTP methods.

// Allow all methods
allowMethods: ["*"]

// Allow specific methods
allowMethods: ["GET", "POST"]

allowOrigins?

Type : Array<string>

Default : Allow all origins.

The collection of allowed origins.

// Allow all origins
allowOrigins: ["*"]

// Allow specific origins. Note that the url protocol, ie. "https://", is required.
allowOrigins: ["https://domain.com"]

exposeHeaders?

Type : Array<string>

Default : No expose headers are allowed.

The collection of exposed headers.

maxAge?

Type : ${number} second | ${number} seconds | ${number} minute | ${number} minutes | ${number} hour | ${number} hours | ${number} day | ${number} days

Default : No caching

Specify how long the results of a preflight response can be cached

maxAge: "1 day"

FunctionCopyFilesProps

Used to configure additional files to copy into the function bundle

new Function(stack, "Function", {
copyFiles: [{ from: "src/index.js" }]
})

from

Type : string

Source path relative to sst.config.ts

to?

Type : string

Destination path relative to function root in bundle

FunctionDockerBuildProps

cacheFrom?

Type : Array<FunctionDockerBuildCacheProps>

Default : No cache from args are passed

Cache from options to pass to the docker build command.

cacheFrom: [{type: "gha"}],

cacheTo?

Type : FunctionDockerBuildCacheProps

Default : No cache to args are passed

Cache to options to pass to the docker build command.

cacheTo: {type: "gha"},

FunctionDockerBuildCacheProps