Page updated Jan 16, 2024

Preview: AWS Amplify's new code-first DX (Gen 2)

The next generation of Amplify's backend building experience with a TypeScript-first DX.

Get started

Modify Amplify-generated resources

Amplify GraphQL API uses a variety of auto-generated, underlying AWS services and resources. You can customize these underlying resources to optimize the deployed stack for your specific use case.

1amplify override api

Run the command above to override Amplify-generated GraphQL API resources including AWS AppSync API, Amazon DynamoDB table, Amazon OpenSearch domain, and more.

If you need to customize a specific Amplify-generated VTL resolver, review Override Amplify-generated resolvers first.

The command creates a new overrides.ts file under amplify/backend/api/<resource-name>/ which provides you the Amplify-generated resources as CDK constructs.

In your CDK project, you can access every underlying resource as an "L2" or "L1" construct. Access the generated resources as L2 constructs via the .resources property on the returned stack or access the generated resources as L1 constructs using the .resources.cfnResources property.

1const api = new AmplifyGraphQlApi(this, 'api', { <params> });
2
3// Access L2 resources under `.resources`
4api.resources.tables["Todo"].tableArn;
5
6// Access L1 resources under `.resources.cfnResources`
7api.resources.cfnResources.cfnGraphqlApi.xrayEnabled = true;
8Object.values(api.resources.cfnResources.cfnTables).forEach(table => {
9 table.pointInTimeRecoverySpecification = { pointInTimeRecoveryEnabled: false };
10});

Customize Amplify-generated AppSync GraphQL API resources

Apply all the overrides in the override(...) function. For example to enable X-Ray tracing for the AppSync GraphQL API:

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.api.GraphQLAPI.xrayEnabled = true;
5}

You can override the following GraphQL API resources that Amplify generates:

Amplify-generated resourceDescription
GraphQLAPIAWS AppSync GraphQL API resource
GraphQLAPIDefaultApiKeyAPI Key resource for the AppSync GraphQL API
GraphQLAPITransformerSchemaThe GraphQL schema that's being deployed. (The output of the GraphQL Transformer)
GraphQLAPINONEDSA "none" data source that is used for requests that don't exit the AppSync API
AmplifyDataStoreThe delta sync table used for Amplify DataStore's conflict resolution
AmplifyDataStoreIAMRoleIAM role used to access the delta sync table for DataStore
DynamoDBAccessIAM policy to access the DynamoDB resources from AppSync

Apply all the customizations on .resources.graphqlApi or .resources.cfnResources.cfnGraphqlApi. For example to enable X-Ray tracing for the AppSync GraphQL API:

1const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', {
2 definition: AmplifyGraphqlDefinition.fromFiles(
3 path.join(__dirname, 'schema.graphql')
4 ),
5 authorizationModes: {
6 defaultAuthorizationMode: 'API_KEY',
7 apiKeyConfig: {
8 expires: cdk.Duration.days(30)
9 }
10 }
11});
12
13amplifyApi.resources.cfnResources.cfnGraphqlApi.xrayEnabled = true;

Customize Amplify-generated resources for @model directive

Apply all the overrides in the override(...) function. Pass in the @model type name into resources.models[...] to modify the resources generated for that particular @model type. For example, to enable time-to-live on the Todo @model type's DynamoDB table:

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.models['Todo'].modelDDBTable.timeToLiveSpecification = {
5 attributeName: 'ttl',
6 enabled: true
7 };
8}

You can override the following @model directive resources that Amplify generates:

Amplify-generated resourceDescription
modelStackThe nested stack containing all resources for the @model type
modelDDBTableThe DynamoDB table containing the data for this @model type
modelIamRoleIAM role to access the DynamoDB table for this @model type
modelIamRoleDefaultPolicyIAM policy to access the delta sync table for this @model type in case DataStore is enabled
dynamoDBAccessDefault policy associated with the IAM role to access the DynamoDB table for this @model type
modelDatasourceThe AppSync DataSource to representing the DynamoDB table
invokeLambdaFunctionIAM policy for Lambda-based conflict resolution function

For example, you can override a model generated DynamoDB table configuration.

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.models['Todo'].modelDatasource.dynamoDbConfig['deltaSyncConfig'][
5 'baseTableTtl'
6 ] = '3600';
7}

Apply all the customizations on .resources.tables["MODEL_NAME"] or .resources.cfnResources.cfnTables["MODEL_NAME"]. Pass in the @model type name into .resources.cfnResources.cfnTables["MODEL_NAME"] to modify the resources generated for that particular @model type. For example, to enable time-to-live on the Todo @model type's DynamoDB table:

1const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', {
2 definition: AmplifyGraphqlDefinition.fromFiles(
3 path.join(__dirname, 'schema.graphql')
4 ),
5 authorizationModes: {
6 defaultAuthorizationMode: 'API_KEY',
7 apiKeyConfig: {
8 expires: cdk.Duration.days(30)
9 }
10 }
11});
12
13amplifyApi.resources.cfnResources.cfnTables['Todo'].timeToLiveSpecification = {
14 attributeName: 'ttl',
15 enabled: true
16};

Example - Configure DynamoDB table's billing mode

Set the DynamoDB billing mode for the DynamoDB table. Either "PROVISIONED" or "PAY_PER_REQUEST".

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.models['Post'].modelDDBTable.billingMode = 'PAY_PER_REQUEST';
5}
1const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', {
2 definition: AmplifyGraphqlDefinition.fromFiles(
3 path.join(__dirname, 'schema.graphql')
4 ),
5 authorizationModes: {
6 defaultAuthorizationMode: 'API_KEY',
7 apiKeyConfig: {
8 expires: cdk.Duration.days(30)
9 }
10 }
11});
12
13amplifyApi.resources.cfnResources.cfnTables['Todo'].billingMode =
14 'PAY_PER_REQUEST';

Example - Configure provisioned throughput for DynamoDB table or Global Secondary Index

Override the default ProvisionedThroughput provisioned for each @model table and its Global Secondary Indexes (GSI).

Only valid if the "DynamoDBBillingMode" is set to "PROVISIONED"

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.models['Post'].modelDDBTable.provisionedThroughput = {
5 readCapacityUnits: 5,
6 writeCapacityUnits: 5
7 };
8
9 /**
10 * When billing mode is set to "PROVISIONED", it is necessary to specify `provisionedThroughput` for every Global Secondary Index (GSI) that exists in the table.
11 */
12
13 resources.models[
14 'Post'
15 ].modelDDBTable.globalSecondaryIndexes[0].provisionedThroughput = {
16 readCapacityUnits: 5,
17 writeCapacityUnits: 5
18 };
19}

Example - Enable point-in-time recovery for DynamoDB table

Enable/disable DynamoDB point-in-time recovery for each @model table.

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.models['Post'].modelDDBTable.pointInTimeRecoverySpecification = {
5 pointInTimeRecoveryEnabled: true
6 };
7}
1const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', {
2 definition: AmplifyGraphqlDefinition.fromFiles(
3 path.join(__dirname, 'schema.graphql')
4 ),
5 authorizationModes: {
6 defaultAuthorizationMode: 'API_KEY',
7 apiKeyConfig: {
8 expires: cdk.Duration.days(30)
9 }
10 }
11});
12
13amplifyApi.resources.cfnResources.cfnTables[
14 'Todo'
15].pointInTimeRecoverySpecification = {
16 pointInTimeRecoveryEnabled: true
17};

Customize Amplify-generated resources for @searchable (OpenSearch) directive

Apply all the overrides in the override(...) function. For example, to modify the OpenSearch instance count:

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig = {
5 ...resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig,
6 instanceCount: 6
7 };
8}

You can override the following @searchable directive resources that Amplify generates:

Amplify-generated resourceDescription
OpenSearchDataSourceThe AppSync data source representing the OpenSearch integration
OpenSearchAccessIAMRoleIAM role to access OpenSearch domain
OpenSearchAccessIAMRoleDefaultPolicyIAM policy to access OpenSearch domain
OpenSearchDomainOpenSearch domain containing the @searchable data
OpenSearchStreamingLambdaIAMRoleIAM role to stream DynamoDB data to OpenSearch domain
OpenSearchStreamingLambdaIAMRoleDefaultPolicyIAM policy to stream DynamoDB data to OpenSearch domain
CloudwatchLogsAccessIAM policy for granting CloudWatch logs access
OpenSearchStreamingLambdaFunctionLambda function to stream DynamoDB data to OpenSearch domain
OpenSearchModelLambdaMappingEvent source mapping for DynamoDB table stream to Lambda function

Example - Configure Runtime for Streaming Lambda

You can define the runtime for the @searchable by setting the runtime value on the function object itself. This can be done to resolve a deprecated runtime in the event that you cannot upgrade your version of the Amplify CLI.

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.opensearch.OpenSearchStreamingLambdaFunction.runtime = 'python3.9';
5}

Example - Configure OpenSearch Streaming function name

Override the name of the AWS Lambda searchable streaming function

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.opensearch.OpenSearchStreamingLambdaFunction.FunctionName =
5 'CustomFunctionName';
6}

Example - Configure OpenSearch instance version

Override the elasticsearchVersion in the OpenSearch domain created by @searchable

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.opensearch.OpenSearchDomain.elasticsearchVersion = 'OpenSearch_1.3';
5}

Example - Configure OpenSearch instance type

Override the type of instance launched into the OpenSearch domain created by @searchable

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig = {
5 ...resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig,
6 instanceType: 'm3.medium.elasticsearch'
7 };
8}

Example - Configure OpenSearch instance count

Override the number of instances launched into the OpenSearch domain created by @searchable

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig = {
5 ...resources.opensearch.OpenSearchDomain.elasticsearchClusterConfig,
6 instanceCount: 2
7 };
8}

Example - Configure OpenSearch EBS volume size

Override the amount of disk space allocated to each instance in the OpenSearch domain created by @searchable

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.opensearch.OpenSearchDomain.ebsOptions = {
5 ...resources.opensearch.OpenSearchDomain.ebsOptions,
6 volumeSize: 10
7 };
8}

Customize Amplify-generated resources for @predictions directive

Apply all the overrides in the override(...) function. For example, to add a Path to IAM role that facilitates text translation:

1import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
2
3export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
4 resources.predictions.TranslateDataSourceServiceRole.path =
5 '/my/organization/';
6}

You can override the following @predictions directive resources that Amplify generates:

Amplify-generated resourceDescription
RekognitionDataSourceAppSync HTTP data source to connect to Amazon Rekognition service
RekognitionDataSourceServiceRoleAppSync service role to connect to Amazon Rekognition
TranslateDataSourceAppSync HTTP data source to connect to Amazon Translate service
translateTextAccessIAM policy to connect to Amazon Translate
LambdaDataSourceAppSync Lambda data source to connect to Amazon Polly
LambdaDataSourceServiceRoleAppSync service role to connect to Lambda function calling Amazon Polly
LambdaDataSourceServiceRoleDefaultPolicyIAM policy for AppSync to connect to Lambda function calling Amazon Polly
TranslateDataSourceServiceRoleAppSync service role to connect to Amazon Translate
predictionsLambdaIAMRoleIAM role for Lambda function calling Amazon Polly
predictionsLambdaFunctionLambda function calling Amazon Polly
PredictionsLambdaAccessIAM policy for Lambda function to access Amazon Polly
predictionsIAMRoleIAM role to access s3 bucket used by @predictions
PredictionsStorageAccessIAM policy to access S3 bucket used by @predictions
identifyTextAccessIAM policy to enable Identify Text
identifyLabelsAccessIAM policy to enable Identify Text

Place AppSync Resolvers in Custom-named Stacks

If you have a particularly large GraphQL schema, you may run into issues with too many resources defined in a stack. The most common case where this happens is in the ConnectionStack which contains the resolvers for all of the relational directives in the schema.

Creating a stack mapping does not create an additional root stack for the Amplify environment. All mapped stacks will still be placed under the existing Amplify environment root stack. To map a resolver to a different stack, update <project root>/amplify/api/<api name>/transform.conf.json with a "StackMapping" block. The StackMapping defines a map from resolver logical ID to stack name.

1{
2 "Version": 5,
3 "ElasticsearchWarning": true,
4 "StackMapping": {
5 "<Resolver logical ID>": "Custom stack name"
6 }
7}

The easiest way to determine a resolver logical ID is to run amplify api gql-compile and note the resolver logical ID in the list of Resources in the generated CloudFormation stack. Resolvers for model operations will be of the form <Get | List | Create | Update | Delete><model name>Resolver. Resolvers for relational directives are of the form <model name><field name>Resolver.

Example

Given the following schema:

1type Blog @model {
2 id: ID!
3 name: String!
4 posts: [Post] @hasMany
5}
6
7type Post @model {
8 id: ID!
9 title: String!
10 content: String
11 blog: Blog @belongsTo
12}

To map the CreatePostResolver and the relational resolvers to a stack named 'MyCustomStack', add the following in transform.conf.json:

1"StackMapping": {
2 "CreatePostResolver": "MyCustomStack",
3 "BlogpostsResolver": "MyCustomStack",
4 "PostblogResolver": "MyCustomStack",
5}