`Ref` and `Fn::GetAtt` are CloudFormation's two ways to read a value from another part of the template. They are not interchangeable — they return different things, and the resource-type docs are the only authority on which is needed. ## What `Ref` returns `Ref` takes one argument: a logical name. What it returns depends on **what kind of thing the logical name refers to**: | Logical name refers to | `Ref` returns | |------------------------|---------------| | A **Parameter** | The parameter's value (string, number, list, etc.) | | A **Resource** | The resource's "default identifier" — usually the physical ID/name/ARN — varies per resource type | | A **Pseudo parameter** | The pseudo parameter's value (e.g., `!Ref AWS::Region` → `us-east-1`) | | A **Condition** | Reserved for use with the `Condition` key, not in property values | The resource-default-identifier varies. Examples: - `AWS::EC2::Instance` → instance ID (`i-1234...`) - `AWS::S3::Bucket` → bucket name (`my-bucket`) - `AWS::IAM::Role` → role name (not ARN) - `AWS::SNS::Topic` → topic ARN (yes ARN, unlike IAM Role) The choice of "default attribute" is per-resource and inconsistent — always check the resource's "Return values" section in the AWS docs. ## What `Fn::GetAtt` returns `Fn::GetAtt` takes two arguments: logical resource name + attribute name. It returns a **specific named attribute** of that resource: ```yaml !GetAtt MyBucket.Arn # ARN, when Ref returns just bucket name !GetAtt MyDB.Endpoint.Address # nested attribute via dot notation !GetAtt MyLB.DNSName # DNS name (not in Ref) !GetAtt EC2Instance.AvailabilityZone ``` JSON syntax differs — list of two strings: ```json { "Fn::GetAtt": ["MyDB", "Endpoint.Address"] } ``` YAML supports the dotted shorthand `!GetAtt LogicalName.Attribute` or the long form `!GetAtt [LogicalName, Attribute]`. ## Decision rule 1. Need the resource's default identifier? → `!Ref` 2. Need any other attribute? → `!Fn::GetAtt` 3. Reading a Parameter's value? → always `!Ref` 4. Reading a pseudo parameter? → always `!Ref` (or via `!Sub`'s `${}` syntax) When in doubt, look up the resource type's "Return values" section. It lists `Ref` (the default) and `Fn::GetAtt` (every other accessible attribute). ## Cascading effect Both `Ref` and `Fn::GetAtt` create an **implicit dependency** between resources. CFN walks these references to determine creation order. When the referenced resource is replaced (see [[CFN Update Behaviors and the Replacement Trap]]), the referencing resource is updated too — even if its template definition didn't change. This cascade can be surprising. To make a dependency explicit without using `Ref`/`GetAtt`, use the `DependsOn` resource attribute. To break a circular dependency, factor through Outputs/Exports. ## Related - [[CFN Fn-Sub String Interpolation]] - [[CFN Pseudo Parameters]] - [[CFN Cross-Stack References Outputs and ImportValue]] - [[CFN Update Behaviors and the Replacement Trap]]