
## Update custom metadata

URL: https://docs.atlan.com/product/capabilities/build-apps/sdks/python/custom-metadata/how-tos/update-custom-metadata

> Modify existing custom metadata structures in Atlan using the Python SDK — add or update attribute types, display labels, and validation rules without recreating the full structure.

# AttributeDef: update custom metadata attributes

Use `AttributeDef` in the Atlan Python SDK to programmatically add or modify attributes on existing custom metadata type definitions.

:::warning[Custom metadata structure updates are complete replacements]
You need to send the entire custom metadata structure (all of its attributes) on each update.
:::

## Retrieve existing structure

To make sure you have the complete structure, it's easiest to start by [retrieving the existing custom metadata structure](https://docs.atlan.com/llms/governance/custom-metadata/retrieve-custom-metadata/llms.txt).

## Update custom metadata structure

Now that you have the existing structure, modify the object. You can add or remove as many properties as you want in a single update, but for simplicity the following describe how to add and remove a single property each.

### Add property

To add a property:

### Java

```java title="Add a property to the structure"
existing.toBuilder() // (6)
 .attributeDef(AttributeDef.of(client, // (2)
 "Extra", // (3)
 AtlanCustomAttributePrimitiveType.STRING, // (4)
 false)) // (5)
 .build(); // (6)
CustomMetadataDef updated = existing.update(client); // (7)
```

1. After retrieving the existing custom metadata structure, clone the structure into a mutable one using `toBuilder()`.
2. You can append a new attribute to its list of attributes by chaining `.attributeDef()`. Use the `AttributeDef.of()` factory method to define the attribute with the correct internal settings. Because this operation may need to retrieve information from Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.
3. When using the factory method, you need to provide at least a name;
4. ...a type;
5. ...and whether there can be multiple values for this property (true) or only a single value (false) on a given asset.
6. Then build the mutable structure.
7. And finally call the `.update()` method on the revised custom metadata structure to actually submit the changes to Atlan. Because this operation will persist the structure in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

### Python

```python title="Add a property to the structure"
from pyatlan.model.typedef import AttributeDef
from pyatlan.model.enums import AtlanCustomAttributePrimitiveType
from pyatlan.client.atlan import AtlanClient

client = AtlanClient()

attrs = existing.attribute_defs # (1)
attrs.append(
 AttributeDef.create( # (2)
 client=client, # (3)
 display_name="Extra", # (4)
 attribute_type=AtlanCustomAttributePrimitiveType.STRING,
 ),
)
existing.attribute_defs = attrs # (5)
response = client.typedef.update(existing) # (6)
```

1. Create a new list of attributes, starting with the list of existing attributes.
2. Add a new attribute to this list of attributes. Use the `AttributeDef.create()` factory method to define the attribute with the correct internal settings.
3. You must provide a client instance.
4. When using the factory method, you need to provide at least a name and a type.
5. Then set the attributes on the custom metadata structure to this revised list.
6. And finally call the `.typedef.update()` method sending the revised custom metadata structure to actually submit the changes to Atlan.

### Kotlin

```kotlin title="Add a property to the structure"
existing.toBuilder() // (6)
 .attributeDef(AttributeDef.of(client, // (2)
 "Extra", // (3)
 AtlanCustomAttributePrimitiveType.STRING, // (4)
 false)) // (5)
 .build() // (6)
val updated = existing.update(client) // (7)
```

1. After retrieving the existing custom metadata structure, clone the structure into a mutable one using `toBuilder()`.
2. You can append a new attribute to its list of attributes by chaining `.attributeDef()`. Use the `AttributeDef.of()` factory method to define the attribute with the correct internal settings. Because this operation may need to retrieve information from Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.
3. When using the factory method, you need to provide at least a name;
4. ...a type;
5. ...and whether there can be multiple values for this property (true) or only a single value (false) on a given asset.
6. Then build the mutable structure.
7. And finally call the `.update()` method on the revised custom metadata structure to actually submit the changes to Atlan. Because this operation will persist the structure in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

### Raw REST API

```json showLineNumbers title="PUT /api/meta/types/typedefs"
{
 "businessMetadataDefs": [ // (1)
 },
 {...},
 {...},
 {...},
 {
 "name": "Extra", // (4)
 "displayName": "Extra", // (5)
 "description": "",
 "typeName": "string",
 "includeInNotification": false,
 "isIndexable": true,
 "isOptional": true,
 "isUnique": false,
 "indexType": "DEFAULT",
 "searchWeight": -1,
 "cardinality": "SINGLE",
 "valuesMinCount": 0,
 "valuesMaxCount": 1,
 "options": {
 "applicableEntityTypes": "[\"Asset\"]",
 "customApplicableEntityTypes": "[\"Database\",\"Schema\",\"Table\"]\n",
 "maxStrLength": "100000000",
 "isEnum": false,
 "multiValueSelect": false,
 "allowFiltering": true,
 "allowSearch": true,
 "primitiveType": "string",
 "customType": "users"
 }
 }
 ],
 "createdBy": "jsmith",
 "updatedBy": "jsmith",
 "createTime": 1648852296555,
 "updateTime": 1649172284333,
 "version": 2
 }
 ]
}
```

1. You need to specify the entire custom metadata structure, within the `businessMetadataDefs` array.
2. Include all the details of the custom metadata structure definition as you retrieved it.
3. Include all the details of the custom metadata attribute definitions, as you retrieved them.
4. Add the new attribute definition to the list of attribute definitions. Note that for the `name` during this update you can use any string you want, as it will be replaced by a system-generated hashed-string during creation of the property.
5. However, make sure you use the human-readable name you want for the property for the `displayName` of the attribute definition. Also make sure you set all the remaining pieces of the attribute definition according to the nature of the attribute you want to define.

### Change property

To change an existing property:

### Java

```java title="Change the custom metadata definition"
List revised = new ArrayList<>(); // (1)
for (AttributeDef attr : existing.getAttributeDefs()) else {
 revised.add(attr); // (4)
 }
}
existing.toBuilder() // (5)
 .clearAttributeDefs() // (6)
 .attributeDefs(revised) // (7)
 .build();
CustomMetadataDef updated = existing.update(client); // (8)
```

1. Create a new (mutable) empty list of attributes.
2. Iterate through the existing attributes in the custom metadata structure...
3. ...When you get to the attribute you want to change, modify it as-needed.

 :::warning[Some properties must not be changed]
Don't change the attribute's `primitiveType`, `isEnum`, `enumType`, `customType`, `multiValueSelect`, `isArchived`, `archivedAt`, or `archivedBy` properties. These should only be set at creation or through archival methods.
 :::
4. And add all attributes (existing and the modified one) into the list of revised attributes.
5. You must then clone the custom metadata structure into a mutable structure, using `toBuilder()`.
6. You then need to clear the existing attribute definitions (otherwise the next step will only *append* the same definitions again).
7. Then you can set the attributes on the custom metadata structure to this revised list, and build the structure.
8. And finally call the `.update()` method on the revised custom metadata structure to actually submit the changes to Atlan. Because this operation will persist the structure in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

### Python

```python title="Change the custom metadata definition"
from pyatlan.model.typedef import AttributeDef
from pyatlan.model.enums import AtlanCustomAttributePrimitiveType

revised = [] # (1)
for attr in existing.attribute_defs: # (2)
 if attr.display_name == "Extra":
 attr.display_name = "Something else" # (3)
 revised.append(attr) # (4)
existing.attribute_defs = revised # (5)

from pyatlan.client.atlan import AtlanClient

client = AtlanClient()
response = client.typedef.update(existing) # (6)
```

1. Create a new empty list of attributes.
2. Iterate through the existing attributes in the custom metadata structure...
3. ...When you get to the attribute you want to change, you can change its `display_name`, but not much else. (You shouldn't change its type, hashed-string name, etc.)
4. And add all attributes (existing and the modified one) into the list of revised attributes.
5. Then set the attributes on the custom metadata structure to this revised list.
6. And finally call the `typedef.update()` method sending the revised custom metadata structure to actually submit the changes to Atlan.

### Kotlin

```java title="Change the custom metadata definition"
val revised = mutableListOf() // (1)
for (attr in existing.attributeDefs) else {
 revised.add(attr) // (4)
 }
}
existing.toBuilder() // (5)
 .clearAttributeDefs() // (6)
 .attributeDefs(revised) // (7)
 .build()
val updated = existing.update(client) // (8)
```

1. Create a new (mutable) empty list of attributes.
2. Iterate through the existing attributes in the custom metadata structure...
3. ...When you get to the attribute you want to change, modify it as-needed.

 :::warning[Some properties must not be changed]
Don't change the attribute's `primitiveType`, `isEnum`, `enumType`, `customType`, `multiValueSelect`, `isArchived`, `archivedAt`, or `archivedBy` properties. These should only be set at creation or through archival methods.
 :::
4. And add all attributes (existing and the modified one) into the list of revised attributes.
5. You must then clone the custom metadata structure into a mutable structure, using `toBuilder()`.
6. You then need to clear the existing attribute definitions (otherwise the next step will only *append* the same definitions again).
7. Then you can set the attributes on the custom metadata structure to this revised list, and build the structure.
8. And finally call the `.update()` method on the revised custom metadata structure to actually submit the changes to Atlan. Because this operation will persist the structure in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

### Raw REST API

```json showLineNumbers title="PUT /api/meta/types/typedefs"
{
 "businessMetadataDefs": [ // (1)
 },
 {...},
 {...},
 {...},
 {
 "name": "okm7BDXjTQx4iYPT5u7ilu", // (4)
 "displayName": "Something else", // (5)
 "description": "",
 "typeName": "string",
 "includeInNotification": false,
 "isIndexable": true,
 "isOptional": true,
 "isUnique": false,
 "indexType": "DEFAULT",
 "searchWeight": -1,
 "cardinality": "SINGLE",
 "valuesMinCount": 0,
 "valuesMaxCount": 1,
 "options": {
 "applicableEntityTypes": "[\"Asset\"]",
 "customApplicableEntityTypes": "[\"Database\",\"Schema\",\"Table\"]\n",
 "maxStrLength": "100000000",
 "isEnum": false,
 "multiValueSelect": false,
 "allowFiltering": true,
 "allowSearch": true,
 "primitiveType": "string",
 "customType": "users"
 }
 }
 ],
 "createdBy": "jsmith",
 "updatedBy": "jsmith",
 "createTime": 1648852296555,
 "updateTime": 1649172284333,
 "version": 2
 }
 ]
}
```

1. You need to specify the entire custom metadata structure, within the `businessMetadataDefs` array.
2. Include all the details of the custom metadata structure definition as you retrieved it.
3. Include all the details of the custom metadata attribute definitions, as you retrieved them.
4. For the attribute you want to modify, include its hashed-string name as with all the other attribute definitions.
5. However, for the `displayName` of the attribute you want to modify, change it to the new human-readable name you want to use.

### Remove property

To remove a property:

### Java

```java title="Remove a property from the structure"
List revised = new ArrayList<>(); // (1)
for (AttributeDef attr : existing.getAttributeDefs()) else {
 revised.add(attr); // (4)
 }
}
existing.toBuilder() // (5)
 .clearAttributeDefs() // (6)
 .attributeDefs(revised) // (7)
 .build();
CustomMetadataDef updated = existing.update(client); // (8)
```

1. Create a new (mutable) empty list of attributes.
2. Iterate through the existing attributes in the custom metadata structure...
3. ...When you get to the attribute you want to remove, call the `.archive()` method against it passing the name of the user deleting the attribute.
4. And add all attributes (existing and the removed one) into the list of revised attributes.
5. You must then clone the custom metadata structure into a mutable structure, using `toBuilder()`.
6. You then need to clear the existing attribute definitions (otherwise the next step will only *append* the same definitions again).
7. Then you can set the attributes on the custom metadata structure to this revised list, and build the structure.
8. And finally call the `.update()` method on the revised custom metadata structure to actually submit the changes to Atlan. Because this operation will persist the structure in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

### Python

```python title="Change the custom metadata definition"
from pyatlan.model.typedef import AttributeDef
from pyatlan.model.enums import AtlanCustomAttributePrimitiveType

revised = [] # (1)
for attr in existing.attribute_defs: # (2)
 if attr.display_name == "Extra":
 attr.archive(by="jsmith") # (3)
 revised.append(attr) # (4)
existing.attribute_defs = revised # (5)

from pyatlan.client.atlan import AtlanClient

client = AtlanClient()
response = client.typedef.update(existing) # (6)
```

1. Create a new empty list of attributes.
2. Iterate through the existing attributes in the custom metadata structure...
3. ...When you get to the attribute you want to remove, call the `.archive()` method against it passing the name of the user deleting the attribute.
4. And add all attributes (existing and the archived one) into the list of revised attributes.
5. Then set the attributes on the custom metadata structure to this revised list.
6. And finally call the `.update()` method on the revised custom metadata structure to actually submit the changes to Atlan.

### Kotlin

```kotlin title="Remove a property from the structure"
val revised = mutableListOf() // (1)
for (attr in existing.attributeDefs) else {
 revised.add(attr) // (4)
 }
}
existing.toBuilder() // (5)
 .clearAttributeDefs() // (6)
 .attributeDefs(revised) // (7)
 .build()
val updated = existing.update(client) // (8)
```

1. Create a new (mutable) empty list of attributes.
2. Iterate through the existing attributes in the custom metadata structure...
3. ...When you get to the attribute you want to remove, call the `.archive()` method against it passing the name of the user deleting the attribute.
4. And add all attributes (existing and the removed one) into the list of revised attributes.
5. You must then clone the custom metadata structure into a mutable structure, using `toBuilder()`.
6. You then need to clear the existing attribute definitions (otherwise the next step will only *append* the same definitions again).
7. Then you can set the attributes on the custom metadata structure to this revised list, and build the structure.
8. And finally call the `.update()` method on the revised custom metadata structure to actually submit the changes to Atlan. Because this operation will persist the structure in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

### Raw REST API

```json showLineNumbers title="PUT /api/meta/types/typedefs"
{
 "businessMetadataDefs": [ // (1)
 },
 {...},
 {...},
 {...},
 {
 "name": "okm7BDXjTQx4iYPT5u7ilu", // (4)
 "displayName": "Extra-archived-1649172285912", // (5)
 "description": "",
 "typeName": "string",
 "includeInNotification": false,
 "isIndexable": true,
 "isOptional": true,
 "isUnique": false,
 "indexType": "DEFAULT",
 "searchWeight": -1,
 "cardinality": "SINGLE",
 "valuesMinCount": 0,
 "valuesMaxCount": 1,
 "options": {
 "applicableEntityTypes": "[\"Asset\"]",
 "customApplicableEntityTypes": "[\"Database\",\"Schema\",\"Table\"]\n",
 "maxStrLength": "100000000",
 "isEnum": false,
 "multiValueSelect": false,
 "allowFiltering": true,
 "allowSearch": true,
 "primitiveType": "string",
 "customType": "users",
 "isArchived": true, // (6)
 "archivedBy": "jsmith", // (7)
 "archivedAt": 1649172285912 // (8)
 }
 }
 ],
 "createdBy": "jsmith",
 "updatedBy": "jsmith",
 "createTime": 1648852296555,
 "updateTime": 1649172284333,
 "version": 2
 }
 ]
}
```

1. You need to specify the entire custom metadata structure, within the `businessMetadataDefs` array.
2. Include all the details of the custom metadata structure definition as you retrieved it.
3. Include all the details of the custom metadata attribute definitions, as you retrieved them.
4. For the attribute you want to remove, include its hashed-string name as with all the other attribute definitions.
5. However, for the `displayName` of the attribute you want to remove, append `-archived-` and a millisecond epoch for the current system time.
6. Within the `options` for the attribute definition, set `isArchived` to `true`.
7. Within the `options` for the attribute definition, set `archivedBy` to the name of the user who is deleting the attribute.
8. Within the `options` for the attribute definition, set `archivedAt` to the millisecond epoch appended to the `displayName`.

:::warning[Removed properties are only soft-deleted]
Note that removing a property only archives (soft-deletes) it. When retrieving the custom metadata structure again, you will still see the deleted attribute definition in the structure, but its `attributeDefs.options.isArchived` property will be set to `true` and its `displayName` will have been changed to include the time at which it was archived.
:::

---
