export const meta = {
  title: `Use CDK to add custom AWS resources`,
  description: 'The Amplify CLI provides the ability to add custom AWS resources with AWS Cloud Development Kit (CDK). Running the `amplify add custom` command in your Amplify project provides CDK starter stacks along with mechanisms to reference other Amplify-generated resources.',
};

The Amplify CLI provides the ability to add custom AWS resources with AWS Cloud Development Kit (CDK). Running the `amplify add custom` command in your Amplify project provides CDK starter stacks along with mechanisms to reference other Amplify-generated resources.

> The [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/latest/guide/home.html) is an open source software development framework to define your cloud application resources using familiar programming languages, such as Typescript.

```bash
amplify add custom
```
```console
? How do you want to define this custom resource? …  (Use arrow keys or type to filter)
❯ AWS CDK
  AWS CloudFormation
```

A skeleton CDK stack is generated in the `amplify/backend/custom/<resource-name>` directory. Edit the `cdk-stack.ts` file to define the additional AWS resources. Add additional CDK constructs using the `package.json`. Run `amplify build` to download all NPM dependencies for this custom resource and synthesize the CDK stack.

<Callout>

To migrate from AWS CDK v1 to v2, refer to the [migration documentation](/cli/migration/aws-cdk-migration/).

</Callout>


The following example creates an SNS topic whose notification messages are forwarded via email:

```ts
import * as cdk from 'aws-cdk-lib';
import * as AmplifyHelpers from '@aws-amplify/cli-extensibility-helper';
import { Construct } from 'constructs';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subs from 'aws-cdk-lib/aws-sns-subscriptions';

export class cdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps, amplifyResourceProps?: AmplifyHelpers.AmplifyResourceProps) {
    super(scope, id, props);
    /* Do not remove - Amplify CLI automatically injects the current deployment environment in this input parameter */
    new cdk.CfnParameter(this, 'env', {
      type: 'String',
      description: 'Current Amplify CLI env name',
    });

    const amplifyProjectInfo = AmplifyHelpers.getProjectInfo();
    const snsTopicResourceName = `sns-topic-${amplifyProjectInfo.projectName}-${cdk.Fn.ref('env')}`;
    const topic = new sns.Topic(this, 'sns-topic', {
      topicName: snsTopicResourceName,
    });

    topic.addSubscription(new subs.EmailSubscription('<your-email-address>'));
    new cdk.CfnOutput(this, 'snsTopicArn', {
      value: topic.topicArn,
      description: 'The arn of the SNS topic',
    });
  }
}
```

> Note: Always append the Amplify environment name to a resource name to ensure correct behavior with Amplify's multi-environment workflows.

<Callout warning>

When creating custom resources using Amplify CLI, the CLI may require additional permissions outside the Amplify managed policy, [`AdministratorAccess-Amplify`](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AdministratorAccess-Amplify).
Please refer to the Amplify [IAM Policy](/cli/reference/iam) documentation for additional information regarding the necessary permissions for Amplify CLI and for more information on providing additional permissions to your Amplify CLI IAM user refer to [AWS IAM User](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_change-permissions.html#users_change_permissions-add-directly-console) documentation.

</Callout>

## Reference Amplify project and environment name

Amplify provides you helper functions to get Amplify project information such as the project name and the current Amplify environment name.

### Reference Amplify project name

Use the `AmplifyHelpers.getProjectInfo()` function to retrieve the project name:

```ts
import * as AmplifyHelpers from '@aws-amplify/cli-extensibility-helper';

// ...

const projectName = AmplifyHelpers.getProjectInfo().projectName;
```

### Reference Amplify environment name

There are two access patterns for the environment for two different use cases. Using the right access mechanism for the right use case is critical to ensure multi-environment workflows function properly.

If you want to use the environment name as a variable for a resource, use `cdk.Fn.ref('env')`:

```ts
const role = new iam.Role(this, 'CustomRole', {
  assumedBy: new iam.AccountRootPrincipal(),
  roleName: `${roleResourceNamePrefix}-${cdk.Fn.ref('env')}` // Reference to Amplify "env" name
})
```

If you want to apply conditional logic based on the current environment name, use `AmplifyHelpers.projectInfo()`:

```ts
import * as AmplifyHelpers from '@aws-amplify/cli-extensibility-helper';

// ...

const envName = AmplifyHelpers.getProjectInfo().envName;

if (envName === "prod") {
  // ...
} else {
  // ...
}
```

## Reference Amplify-generated resources

The CDK stack for custom AWS resources can reference Amplify-generated resources' CloudFormation outputs. To reference another resource, first add the resource as a dependency.

```ts
import { AmplifyDependentResourcesAttributes } from "../../types/amplify-dependent-resources-ref";

const dependencies: AmplifyDependentResourcesAttributes = AmplifyHelpers.addResourceDependency(this,
  amplifyResourceProps.category,
  amplifyResourceProps.resourceName,
  [{
    category: "function", // api, auth, storage, function, etc.
    resourceName: "<resource-name>" // find the resource at "amplify/backend/<category>/<resourceName>"
  } /* add more dependencies as needed */] 
);
```

Then use the `cdk.Fn.ref` function to create a dynamic reference of the dependencies' outputs.

```ts
const myFunctionArn = cdk.Fn.ref(dependencies.function.<resource-name>.Arn)
```

The `dependencies` variable has the auto-generated `AmplifyDependentResourcesAttributes` type which includes all Amplify-generated resource output. Run `amplify build` to regenerate `AmplifyDependentResourcesAttributes` if you don't see your category, resource, or parameters.
