---
title: "Set up a Function"
section: "build-a-backend/functions"
platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
gen: 2
last-updated: "2025-03-25T21:50:31.000Z"
url: "https://docs.amplify.aws/react/build-a-backend/functions/set-up-function/"
---

Amplify Functions are powered by [AWS Lambda](https://aws.amazon.com/lambda/), and allow you to perform a wide variety of customization through self-contained _functions_. Functions can respond to events from other resources, execute some logic in-between events like an authentication flow, or act as standalone jobs. They are used in a variety of settings and use cases:

- Authentication flow customizations (e.g. attribute validations, allowlisting email domains)
- Resolvers for GraphQL APIs
- Handlers for individual REST API routes, or to host an entire API
- Scheduled jobs

To get started, create a new directory and a resource file, `amplify/functions/say-hello/resource.ts`. Then, define the Function with `defineFunction`:

```ts title="amplify/functions/say-hello/resource.ts"
import { defineFunction } from '@aws-amplify/backend';

export const sayHello = defineFunction({
  // optionally specify a name for the Function (defaults to directory name)
  name: 'say-hello',
  // optionally specify a path to your handler (defaults to "./handler.ts")
  entry: './handler.ts'
});
```

Next, create the corresponding handler file at `amplify/functions/say-hello/handler.ts`. This is where your function code will go.

```ts title="amplify/functions/say-hello/handler.ts"
import type { Handler } from 'aws-lambda';

export const handler: Handler = async (event, context) => {
  // your function code goes here
  return 'Hello, World!';
};
```

The handler file _must_ export a function named "handler". This is the entry point to your function. For more information on writing functions, refer to the [AWS documentation for Lambda function handlers using Node.js](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html).

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

```ts title="amplify/backend.ts"
import { defineBackend } from '@aws-amplify/backend';
// highlight-next-line
import { sayHello } from './functions/say-hello/resource';

defineBackend({
  // highlight-next-line
  sayHello
});
```

Now when you run `npx ampx sandbox` or deploy your app on Amplify, it will include your Function.

To invoke your Function, we recommend adding your [Function as a handler for a custom query with your Amplify Data resource](/[platform]/build-a-backend/data/custom-business-logic/). This will enable you to strongly type Function arguments and the return statement, and use this to author your Function's business logic. To get started, open your `amplify/data/resource.ts` file and specify a new query in your schema:

```ts title="amplify/data/resource.ts"
import { type ClientSchema, a, defineData } from "@aws-amplify/backend"
import { sayHello } from "../functions/say-hello/resource"

const schema = a.schema({
  // highlight-start
  sayHello: a
    .query()
    .arguments({
      name: a.string(),
    })
    .returns(a.string())
    .authorization(allow => [allow.guest()])
    .handler(a.handler.function(sayHello)),
  // highlight-end
})

export type Schema = ClientSchema<typeof schema>

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "iam",
  },
})
```

Now you can use this query from the `Schema` export to strongly type your Function handler:

```ts title="amplify/functions/say-hello/handler.ts"
import type { Schema } from "../../data/resource"

export const handler: Schema["sayHello"]["functionHandler"] = async (event) => {
  // arguments typed from `.arguments()`
  const { name } = event.arguments
  // return typed from `.returns()`
  return `Hello, ${name}!`
}
```

Finally, use the data client to invoke your Function by calling its associated query.

<!-- Platform: angular, javascript, nextjs, react, react-native, vue -->
```ts title="src/main.ts"
import type { Schema } from "./amplify/data/resource"
import { Amplify } from "aws-amplify"
import { generateClient } from "aws-amplify/api"
import outputs from "./amplify_outputs.json"

Amplify.configure(outputs)

const client = generateClient<Schema>()

// highlight-start
client.queries.sayHello({
  name: "Amplify",
})
// highlight-end
```
<!-- /Platform -->
<!-- Platform: android -->
```kt
data class SayHelloDetails(
    val name: String,
)

data class SayHelloResponse(
    val sayHello: SayHelloDetails
)

val document = """
    query SayHelloQuery(${'$'}name: String!) {
        sayHello(name: ${'$'}name) {
            name
            executionDuration
        }
    }
""".trimIndent()
val sayHelloQuery = SimpleGraphQLRequest<String>(
    document,
    mapOf("name" to "Amplify"),
    String::class.java,
    GsonVariablesSerializer())

Amplify.API.query(
    sayHelloQuery,
    {
        var gson = Gson()
        val response = gson.fromJson(it.data, SayHelloResponse::class.java)
        Log.i("MyAmplifyApp", "${response.sayHello.name}")
    },
    { Log.e("MyAmplifyApp", "$it")}
)
```
<!-- /Platform -->
<!-- Platform: flutter -->
First define a class that matches your response shape:

```dart
class SayHelloResponse {
  final SayHello sayHello;

  SayHelloResponse({required this.sayHello});

  factory SayHelloResponse.fromJson(Map<String, dynamic> json) {
    return SayHelloResponse(
      sayHello: SayHello.fromJson(json['sayHello']),
    );
  }
}

class SayHello {
  final String name;
  final double executionDuration;

  SayHello({required this.name, required this.executionDuration});

  factory SayHello.fromJson(Map<String, dynamic> json) {
    return SayHello(
      name: json['name'],
      executionDuration: json['executionDuration'],
    );
  }
}
```

Next, make the request and map the response to the classes defined above:

```dart
// highlight-next-line
import 'dart:convert';

// highlight-start
const graphQLDocument = '''
  query SayHello(\$name: String!) {
    sayHello(name: \$name) {
      name
      executionDuration
    }
  }
''';

final echoRequest = GraphQLRequest<String>(
  document: graphQLDocument,
  variables: <String, String>{"name": "Amplify"},
);

final response =
    await Amplify.API.query(request: echoRequest).response;
safePrint(response);

Map<String, dynamic> jsonMap = json.decode(response.data!);
SayHelloResponse SayHelloResponse = SayHelloResponse.fromJson(jsonMap);
safePrint(SayHelloResponse.sayHello.name);
// highlight-end
```
<!-- /Platform -->
<!-- Platform: swift -->
```swift
struct SayHelloResponse: Codable {
    public let sayHello: SayHello
    
    struct SayHello: Codable {
        public let name: String
        public let executionDuration: Float
    }
}

let document = """
    query EchoQuery($name: String!) {
        sayHello(name: $name) {
            name
            executionDuration
        }
    }
    """

let result = try await Amplify.API.query(request: GraphQLRequest<SayHelloResponse>(
    document: document,
    variables: [
        "name": "Amplify"
    ],
    responseType: SayHelloResponse.self
))
switch result {
case .success(let response):
    print(response.sayHello)
case .failure(let error):
    print(error)
}
```
<!-- /Platform -->

## Next steps

Now that you have completed setting up your first Function, you may also want to add some additional features or modify a few settings. We recommend you learn more about:

- [Environment variables and secrets](/[platform]/build-a-backend/functions/environment-variables-and-secrets/)
- [Grant access to other resources](/[platform]/build-a-backend/functions/grant-access-to-other-resources/)
- [Explore example use cases](/[platform]/build-a-backend/functions/examples/)
- [Modifying underlying resources with CDK](/[platform]/build-a-backend/functions/modify-resources-with-cdk/)
