Page updated Mar 28, 2024

Functions

Under active development: The Functions experience for Amplify Gen 2 is under active development. The experience may change between versions of @aws-amplify/backend. Try it out and provide feedback at https://github.com/aws-amplify/amplify-backend/issues/new/choose

To create a function, start by creating a file amplify/functions/my-demo-function/resource.ts. Paste the following content into the file.

amplify/functions/my-demo-function/resource.ts
1import { defineFunction } from '@aws-amplify/backend';
2
3export const myDemoFunction = defineFunction({
4 /*
5 name?: string // optional parameter to specify a function name. In this case, it will default to "my-demo-function" (the name of the directory where the function is defined)
6 entry?: string // optional path to the function code. Defaults to ./handler.ts
7 */
8});

Next, create amplify/functions/my-demo-function/handler.ts. This is where your function code will go.

amplify/functions/my-demo-function/handler.ts
1export const handler = async (event) => {
2 // your function code goes here
3 return 'You made a function!';
4};

The handler file must export an async function named "handler". This is the entry point to your function. For more information on writing functions, see https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html

Lastly, this function needs to be added to your backend.

amplify/backend.ts
1import { defineBackend } from '@aws-amplify/backend';
2import { myDemoFunction } from './functions/my-demo-function/resource';
3
4defineBackend({
5 myDemoFunction
6});

Now when you run npx amplify sandbox or deploy your app on Amplify, it will include your backend function. See the examples below for connecting your functions to event sources.

Environment variables

Environment variables can be configured in defineFunction using the environment property.

amplify/functions/my-demo-function/resource.ts
1import { defineFunction } from '@aws-amplify/backend';
2
3export const myDemoFunction = defineFunction({
4 environment: {
5 ENV_VAR_NAME: 'someValueHere'
6 }
7});

Any environment variables specified here will be available to the function at runtime.

Some environment variables are constant across all branches and deployments. But many environment values differ between deployment environments. Branch-specific environment variables can be configured for Amplify hosting deployments.

Suppose you created a branch-specific environment variable in hosting called "API_ENDPOINT" which had a different value for your "staging" vs "prod" branch. If you wanted that value to be available to your function you can pass it to the function using

amplify/functions/my-demo-function/resource.ts
1export const myDemoFunction = defineFunction({
2 environment: {
3 API_ENDPOINT: process.env.API_ENDPOINT
4 }
5});

Accessing environment variables

Within your function handler, you can access environment variables using the normal process.env global object provided by the Node runtime. However, this does not make it easy to discover what environment variables will be available at runtime. Amplify generates an env symbol that can be used in your function handler and provides typings for all variables that will be available at runtime. Copy the following code to use it.

amplify/functions/my-demo-function/handler.ts
1import { env } from '$amplify/env/my-demo-function'; // the import is '$amplify/env/<function-name>'
2
3export const handler = async (event) => {
4 env. // the env object has intellisense for all environment variables that are available to the function
5 return 'You made a function!';
6};
Learn more
Understanding the "env" symbol and how to manually configure your Amplify project to use it

At the end of AWS Cloud Development Kit's (AWS CDK) synthesis, Amplify gathers names of environment variables that will be available to the function at runtime and generates the file .amplify/generated/env/<function-name>.ts.

If you created your project with create-amplify, then Amplify has already set up your project to use the env symbol.

If you did not, you will need to manually configure your project. Within your amplify/tsconfig.json file add a paths compiler option:

amplify/tsconfig.json
1{
2 "compilerOptions": {
3 "paths": {
4 "$amplify/*": ["../.amplify/generated/*"]
5 }
6 }
7}

Secret access

Sometimes it is necessary to provide a secret value to a function. For example, it may need a database password or an API key to perform some business use case. Environment variables should NOT be used for this because environment variable values are included in plaintext in the function configuration. Instead, secret access can be used.

Before using a secret in a function, you need to define a secret. After you have defined a secret, you can reference it in your function config.

amplify/functions/my-demo-function/resource.ts
1import { defineFunction, secret } from '@aws-amplify/backend';
2
3export const myDemoFunction = defineFunction({
4 environment: {
5 API_KEY: secret('myApiKey') // this assumes you created a secret named "myApiKey"
6 }
7});

You can use this secret value at runtime in your function the same as any other environment variable. However, you will notice that the value of the environment variable is not stored as part of the function configuration. Instead, the value is fetched when your function runs and is provided in memory.

amplify/functions/my-demo-function/handler.ts
1import { env } from '$amplify/env/my-demo-function';
2
3export const handler = async (event) => {
4 env.API_KEY; // this is the value of secret named "myApiKey"
5 return 'You made a function!';
6};

Resource access

When you grant a function access to another resource in your Amplify backend (such as granting access to storage), that will configure environment variables for that function to make SDK calls to the AWS services it has access to. Those environment variables are typed and available as part of the env object.

Example defineStorage that grants myDemoFunction access to files in foo/*.

amplify/storage/resource.ts
1import { myDemoFunction } from '../functions/my-demo-function/resource';
2
3export const storage = defineStorage({
4 name: 'myProjectFiles',
5 access: (allow) => ({
6 'foo/*': [allow.resource(demoFunction).to(['read', 'write', 'delete'])]
7 })
8});

This access definition will add the environment variable myProjectFiles_BUCKET_NAME to the function. This environment variable can be accessed on the env object.

Here's an example of how it can be used to upload some content to S3.

amplify/functions/my-demo-function/handler.ts
1import { env } from '$amplify/env/my-demo-function';
2import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
3
4const s3Client = new S3Client();
5
6export const handler = async (event) => {
7 await s3Client.send(
8 new PutObjectCommand({
9 Bucket: env.myProjectFiles_BUCKET_NAME,
10 Key: 'foo/someFile.txt',
11 Body: 'this is an example'
12 })
13 );
14};

Additional configuration

defineFunction comes out-of-the-box with sensible but minimal defaults. The following options are provided to tweak the function configuration.

timeoutSeconds

By default, functions will time out after 3 seconds. This can be configured to any whole number of seconds up to 15 minutes.

amplify/functions/my-demo-function/resource.ts
1export const myDemoFunction = defineFunction({
2 timeoutSeconds: 60 // 1 minute timeout
3});

memoryMB

By default, functions have 512 MB of memory allocated to them. This can be configured from 128 MB up to 10240 MB. Note that this can increase the cost of executing the function. For more pricing information see here.

amplify/functions/my-demo-function/resource.ts
1export const myDemoFunction = defineFunction({
2 memoryMB: 256 // allocate 256 MB of memory to the function.
3});

runtime

Currently, only Node runtimes are supported by defineFunction. However, you can change the Node version that is used by the function. The default is the oldest Node LTS version that is supported by AWS Lambda (currently Node 18).

If you which to use an older version of Node, keep an eye on the Lambda Node version deprecation schedule. As Lambda removes support for old Node versions, you will have to update to newer supported versions.

amplify/functions/my-demo-function/resource.ts
1export const myDemoFunction = defineFunction({
2 runtime: 20 // use Node 20
3});

entry

By default, Amplify will look for your function handler in a file called handler.ts in the same directory as the file where defineFunction is called. To point to a different handler location, specify an entry value.

amplify/functions/my-demo-function/resource.ts
1export const myDemoFunction = defineFunction({
2 entry: './path/to/handler.ts' // this path should either be absolute or relative to the current file
3});

name

By default, functions are named based on the directory the defineFunction call is placed in. In the above example, defining the function in amplify/functions/my-demo-function/resource.ts will cause the function to be named my-demo-function by default.

If an entry is specified, then the name defaults to the basename of the entry path. For example, an entry of ./signup-trigger-handler.ts would cause the function name to default to signup-trigger-handler.

This optional property can be used to explicitly set the name of the function.

amplify/functions/my-demo-function/resource.ts
1export const myDemoFunction = defineFunction({
2 entry: './demo-function-handler.ts',
3 name: 'overrideName' // explicitly set the name to override the default naming behavior
4});

Example - Create a Function trigger for Auth

Auth has several events that can trigger functions to perform custom sign up, sign in and other tasks. In this example you will configure a "preSignUp" trigger.

First, in your auth definition, add the following:

amplify/auth/resource.ts
1export const auth = defineAuth({
2 loginWith: {
3 email: true
4 },
5 triggers: {
6 // configure a trigger to point to a function definition
7 preSignUp: defineFunction({
8 entry: './pre-sign-up-handler.ts'
9 });
10 }
11});

Then create the function definition at amplify/auth/pre-sign-up-handler.ts.

amplify/auth/pre-sign-up-handler.ts
1import type { PreSignUpTriggerHandler } from 'aws-lambda';
2
3export const handler: PreSignUpTriggerHandler = async (event) => {
4 // your code here
5};

Note: The PreSignUpTriggerHandler type comes from the @types/aws-lambda npm package. This package contains types for different kinds of Lambda handlers, events, and responses.

Assuming that your auth definition is already added to your backend, you don't need to explicitly add your preSignUp function to the defineBackend properties. Since the preSignUp function is attached to the auth definition, Amplify is able to figure out that the function should be included in the deployment.

Now when you deploy your app and a user signs up, this Lambda will fire before the signup.

For more information on auth triggers see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html

Example - Use a function resolver in your data model

See Custom business logic

Example - Use a function as a custom authorizer in your data model

See Custom data access patterns

Example - Create a Function trigger for Storage

See Configure storage triggers