> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tags

> Tags are key-value pairs for organizing and identifying Gcore Cloud resources, with rules, filtering, and cost report usage.

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    <p>Tags are key-value pairs used to organize and identify Cloud resources. Each tag consists of a key (like `env`) and a value (like `production`). Tags can be added during resource creation or to existing resources.</p>

    ## During resource creation

    <p>Tags can be added directly during the resource creation process.</p>

    1. In the [Gcore Customer Portal](https://portal.gcore.com), navigate to **Cloud** > **Virtual Instances** > **Virtual Instances**, then click **Create Instance**.
    2. In the **Additional options** section, select the **Add tags** checkbox.
    3. Enter a **Key** and **Value** for each tag.
    4. Click **Add tag** to add more tags if needed.
    5. Complete the resource creation.

    <Frame>
      <img src="https://mintcdn.com/gcore/3Ju99x240BAsT7PX/images/docs/cloud/tags/tags-image1.png?fit=max&auto=format&n=3Ju99x240BAsT7PX&q=85&s=faeb06c3ec740c6e67232d8c191704fc" alt="Add tags checkbox and key-value fields in the Additional options section during instance creation" width="627" height="143" data-path="images/docs/cloud/tags/tags-image1.png" />
    </Frame>

    ## On existing resources

    <p>Tags can also be added to resources that already exist.</p>

    1. In the Customer Portal, navigate to **Cloud** > **Networking** > **Load Balancers**, then open a load balancer.
    2. Navigate to the **Tags** tab.
    3. Select **Add custom tags**, then enter key-value pairs.
    4. Click **Save changes**. (Optional) Click **Reset tags** to discard unsaved tag edits.

    <Frame>
      <img src="https://mintcdn.com/gcore/3Ju99x240BAsT7PX/images/docs/cloud/tags/tags-image2.png?fit=max&auto=format&n=3Ju99x240BAsT7PX&q=85&s=c1348432924dfb8c5396f4ac74162c78" alt="Tags tab on a load balancer with Add custom tags selected and key-value fields visible" width="993" height="109" data-path="images/docs/cloud/tags/tags-image2.png" />
    </Frame>

    ## Filter resources by tag

    <p>Filter tagged resources directly from the resource list.</p>

    1. Navigate to the resource list page (**Cloud** > **Virtual Instances** > **Virtual Instances**).
    2. Open the filter dropdown (default **Name**) and select **Tag Value**.
    3. Enter a tag value in the search field (placeholder **Search by Tag Value**).

    ## Tag formatting rules

    <p>Tag keys and values must follow these requirements. Invalid tags are rejected during resource creation or update.</p>

    | Parameter | Requirement |
    | - | - |
    | Key length | 3–255 characters |
    | Value length | 3–255 characters |
    | Forbidden characters | `=` in keys |
    | Whitespace | Leading and trailing spaces are trimmed |

    <Warning>
      Tag keys cannot contain the `=` character.
    </Warning>

    ## Common tagging patterns

    <p>Consistent tag naming across resources simplifies filtering and cost allocation.</p>

    | Pattern | Example tags |
    | - | - |
    | Environment | `env:production`, `env:staging`, `env:development` |
    | Service | `service:auth`, `service:payment` |
    | Ownership | `team:backend`, `owner:devops` |
    | Cost tracking | `cost-center:marketing`, `project:website` |

    ## Use tags in cost reports

    <p>Tags appear in the [Cost Report](/cloud/getting-started/view-statistics-on-expenses) table as a dedicated column. Filter and search resources by tag to analyze spending by environment, team, or project.</p>

    <p>The detailed CSV export includes all tag values assigned to each resource.</p>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Add tags to Cloud resources when creating them or update tags on existing resources via the [Gcore API](/api-reference/overview).</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with a
      [project ID](/api-reference/cloud#tag/Projects/operation/ProjectsListV1.get)
      and a [region ID](/api-reference/cloud#tag/Regions/operation/RegionListV1.get).
    </Info>

    <p>Open a terminal and set these environment variables before running the examples:</p>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    export GCORE_CLOUD_PROJECT_ID="{YOUR_PROJECT_ID}"
    export GCORE_CLOUD_REGION_ID="{YOUR_REGION_ID}"
    ```

    <Note>
      The `metadata` field is deprecated. Use the `tags` field for new implementations.
    </Note>

    ## Add tags to a new resource

    <p>Include the `tags` field as a JSON object when creating a resource. The following example creates a Virtual Instance with two tags.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore
        from gcore.types.cloud.instance_create_params import (
            InterfaceNewInterfaceExternalSerializerPydantic,
            VolumeCreateInstanceCreateVolumeFromImageSerializer,
        )

        client = Gcore()

        # Select a flavor: 2 vCPU / 4 GB RAM
        flavors = client.cloud.flavors.list()
        flavor = next(
            f for f in flavors
            if f.vcpus == 2 and f.ram == 4096
        )

        # Select a public Ubuntu 22.04 image
        images = client.cloud.images.list(visibility="public")
        image = next(i for i in images if "ubuntu-22.04" in i.name.lower() and "arm64" not in i.name.lower())

        instance = client.cloud.instances.create_and_poll(
            flavor=flavor.flavor_name,
            interfaces=[InterfaceNewInterfaceExternalSerializerPydantic(type="external")],
            volumes=[
                VolumeCreateInstanceCreateVolumeFromImageSerializer(
                    source="image",
                    image_id=image.id,
                    size=10,
                    type_name="standard",
                    boot_index=0,
                )
            ],
            tags={"env": "production", "team": "backend"},
        )
        print(f"Instance {instance.id} created with tags: {[(t.key, t.value) for t in instance.tags if not t.read_only]}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"
            "os"

            "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/cloud"
            "github.com/G-Core/gcore-go/shared/constant"
        )

        func main() {
            client := gcore.NewClient(
                option.WithCloudProjectID(mustInt(os.Getenv("GCORE_CLOUD_PROJECT_ID"))),
                option.WithCloudRegionID(mustInt(os.Getenv("GCORE_CLOUD_REGION_ID"))),
            )

            params := cloud.InstanceNewParams{
                Flavor: "g2-standard-2-4",
                Interfaces: []cloud.InstanceNewParamsInterfaceUnion{
                    {OfExternal: &cloud.InstanceNewParamsInterfaceExternal{
                        Type: constant.ValueOf[constant.External](),
                    }},
                },
                Volumes: []cloud.InstanceNewParamsVolumeUnion{
                    {OfImage: &cloud.InstanceNewParamsVolumeImage{
                        Source:    constant.ValueOf[constant.Image](),
                        ImageID:   "your-image-id",
                        Size:      gcore.Int(10),
                        TypeName:  "standard",
                        BootIndex: gcore.Int(0),
                    }},
                },
                Tags: map[string]string{"env": "production", "team": "backend"},
            }

            instance, err := client.Cloud.Instances.NewAndPoll(context.Background(), params)
            if err != nil {
                log.Fatalf("failed to create instance: %v", err)
            }
            fmt.Printf("Instance %s created\n", instance.ID)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST "https://api.gcore.com/cloud/v2/instances/${GCORE_CLOUD_PROJECT_ID}/${GCORE_CLOUD_REGION_ID}" \
          -H "Authorization: APIKey ${GCORE_API_KEY}" \
          -H "Content-Type: application/json" \
          -d '{
            "flavor": "g2-standard-2-4",
            "interfaces": [{"type": "external"}],
            "volumes": [{
              "source": "image",
              "image_id": "your-image-id",
              "size": 10,
              "type_name": "standard",
              "boot_index": 0
            }],
            "tags": {
              "env": "production",
              "team": "backend"
            }
          }'
        ```

        Response:

        ```json theme={null}
        {"tasks": ["abc-def-123"]}
        ```
      </Tab>
    </Tabs>

    ## Update tags on an existing resource

    <p>Update tags on any existing resource with a PATCH request. Tags are merged: existing tags not included in the request are preserved.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore

        client = Gcore()
        instance_id = "your-instance-id"

        result = client.cloud.instances.update(
            instance_id=instance_id,
            tags={"env": "staging", "team": "backend"},
        )
        user_tags = [(t.key, t.value) for t in result.tags if not t.read_only]
        print(f"Updated tags: {user_tags}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        result, err := client.Cloud.Instances.Update(context.Background(),
            "your-instance-id",
            cloud.InstanceUpdateParams{
                Tags: map[string]string{"env": "staging", "team": "backend"},
            },
        )
        if err != nil {
            log.Fatalf("failed to update tags: %v", err)
        }
        fmt.Printf("Updated instance: %s\n", result.ID)
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/cloud/v1/instances/${GCORE_CLOUD_PROJECT_ID}/${GCORE_CLOUD_REGION_ID}/your-instance-id" \
          -H "Authorization: APIKey ${GCORE_API_KEY}" \
          -H "Content-Type: application/json" \
          -d '{"tags": {"env": "staging", "team": "backend"}}'
        ```

        Response: the full instance object with updated tags.

        ```json theme={null}
        {
          "instance_id": "...",
          "tags": [
            {"key": "env", "value": "staging", "read_only": false},
            {"key": "team", "value": "backend", "read_only": false},
            {"key": "image_id", "value": "...", "read_only": true}
          ]
        }
        ```
      </Tab>
    </Tabs>

    <Note>
      System tags (e.g. `image_id`, `os_type`, `os_version`) have `"read_only": true` in the response and cannot be modified.
    </Note>

    ## Filter resources by tag

    <p>Use query parameters to list only resources that match specific tag keys or values.</p>

    | Parameter | Format | Example |
    | - | - | - |
    | `tag_key_value` | JSON object | `{"env":"production"}` |
    | `tag_key` | plain string | `env` |
    | `tag_value` | plain string | `production` |

    <p>The `tag_key_value` parameter accepts a JSON-encoded object. To filter by a single tag:</p>

    ```bash theme={null}
    curl "https://api.gcore.com/cloud/v1/instances/${GCORE_CLOUD_PROJECT_ID}/${GCORE_CLOUD_REGION_ID}?tag_key_value=%7B%22env%22%3A%22production%22%7D" \
      -H "Authorization: APIKey ${GCORE_API_KEY}"
    ```

    <p>To filter by multiple tags simultaneously, include all key-value pairs in the same JSON object:</p>

    ```bash theme={null}
    # URL-decoded form for readability:
    # tag_key_value={"env":"production","team":"backend"}
    curl "https://api.gcore.com/cloud/v1/instances/${GCORE_CLOUD_PROJECT_ID}/${GCORE_CLOUD_REGION_ID}?tag_key_value=%7B%22env%22%3A%22production%22%2C%22team%22%3A%22backend%22%7D" \
      -H "Authorization: APIKey ${GCORE_API_KEY}"
    ```

    <p>Using the Python SDK:</p>

    ```python theme={null}
    import json
    from gcore import Gcore

    client = Gcore()

    instances = list(client.cloud.instances.list(
        tag_key_value=json.dumps({"env": "production"}),
    ))
    print(f"Found {len(instances)} instances tagged env=production")
    ```
  </MethodSection>

  <MethodSection id="terraform" label="Terraform">
    <p>In the [Gcore Terraform provider](https://registry.terraform.io/providers/G-Core/gcore/latest/docs), Cloud tags are configured through the `metadata_map` attribute. This is the provider-level name for what the Customer Portal and API expose as tags.</p>

    <Note>
      `metadata_map` is a Terraform provider attribute, not an API field. It maps to the `tags` field in the Gcore API. The deprecated API field is `metadata` (without `_map`), which is unrelated.
    </Note>

    <Info>
      An [API token](/account-settings/api-tokens) is required. Configure the [Gcore Terraform provider](https://registry.terraform.io/providers/G-Core/gcore/latest/docs) with a project ID and region ID before running the examples below.
    </Info>

    ## Configure the provider

    <p>Add the provider block and define your project and region before declaring any resources:</p>

    ```hcl theme={null}
    terraform {
      required_providers {
        gcore = {
          source  = "G-Core/gcore"
          version = ">= 0.3.0"
        }
      }
    }

    provider "gcore" {
      api_token = var.api_token
    }

    variable "api_token" {
      type      = string
      sensitive = true
    }
    ```

    ## Add tags to an instance

    <p>Specify tags using the `metadata_map` attribute. Each key-value pair becomes a searchable tag on the resource — the same tags visible in the Customer Portal and filterable via the API.</p>

    ```hcl theme={null}
    data "gcore_project" "project" {
      name = "Default"
    }

    data "gcore_region" "region" {
      name = "Luxembourg-3"
    }

    resource "gcore_instance" "tagged_instance" {
      project_id = data.gcore_project.project.id
      region_id  = data.gcore_region.region.id

      name      = "my-instance"
      flavor_id = "g2-standard-2-4"

      volume {
        source     = "image"
        image_id   = "your-image-id"
        size       = 10
        type_name  = "standard"
        boot_index = 0
      }

      interface {
        type = "external"
      }

      metadata_map = {
        env  = "production"
        team = "backend"
      }
    }
    ```

    ## Add tags to other resources

    <p>The `metadata_map` attribute is supported on most Cloud resources. The pattern is identical regardless of resource type:</p>

    ```hcl theme={null}
    resource "gcore_loadbalancerv2" "tagged_lb" {
      project_id = data.gcore_project.project.id
      region_id  = data.gcore_region.region.id

      name   = "my-lb"
      flavor = "lb1-1-2"

      metadata_map = {
        env  = "production"
        team = "backend"
      }
    }
    ```

    ## Apply and verify

    <p>Apply the configuration and verify the tags were set:</p>

    ```bash theme={null}
    terraform init
    terraform apply

    # Verify tags via the Gcore API after apply
    curl "https://api.gcore.com/cloud/v1/instances/${PROJECT_ID}/${REGION_ID}/$(terraform output -raw instance_id)" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      | python -c "import sys,json; [print(t) for t in json.load(sys.stdin)['tags'] if not t['read_only']]"
    ```
  </MethodSection>
</MethodSwitch>
