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

# Manage custom images

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>In the [Gcore Customer Portal](https://portal.gcore.com), navigate to **Cloud** → **Images** and select the project and region. All operations below are performed from this page.</p>

    ## View images

    <p>The **Images** page lists all custom images in the region — name, resource type, size, architecture, tags, and creation date.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/images/manage-custom-images/images-actions-menu.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=35fcb7c5fe1dfa487fb6cd5b7c3dfd9c" alt="Images list with the actions menu open showing Create Virtual Instance, Rename, Edit tags, and Delete options" width="1024" height="273" data-path="images/docs/cloud/images/manage-custom-images/images-actions-menu.png" />
    </Frame>

    <p>Click the three-dot menu next to an image to create a virtual instance, rename it, edit its tags, or delete it.</p>

    ## Create virtual instance

    <p>Click the three-dot menu next to the image and select **Create Virtual Instance** to open the [virtual instance](/cloud/virtual-instances/create-an-instance) creation form with the image pre-selected as the boot source.</p>

    ## Rename

    <p>1. Click the three-dot menu next to the image and select **Rename**.</p>

    <p>2. Enter the new name and press **Enter** to confirm.</p>

    ## Edit tags

    <p>[Tags](/cloud/tags) are key-value pairs used to organize Cloud resources. Tag images by environment, team, or purpose to filter them later.</p>

    <p>1. Click the three-dot menu next to the image and select **Edit tags**.</p>

    <p>2. In the dialog, enter a **Key** and a **Value** for each tag. Click **+ Add tag** to add more tags.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/images/manage-custom-images/edit-tags-dialog.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=3016904303826edbbd53c0962a59062c" alt="Edit tags dialog with Key and Value fields and an Add tag button" width="1024" height="418" data-path="images/docs/cloud/images/manage-custom-images/edit-tags-dialog.png" />
    </Frame>

    <p>3. Click **Save**.</p>

    ## Delete

    <Warning>
      Deleting an image is permanent. If the image was uploaded with **Instance quick start** enabled, it cannot be deleted while instances created from it are still running.
    </Warning>

    <p>1. Click the three-dot menu next to the image and select **Delete**.</p>

    <p>2. In the confirmation dialog, click **Delete image**.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-tGG7PWTFMtYIhJ9/images/docs/cloud/images/manage-custom-images/delete-image-dialog.png?fit=max&auto=format&n=-tGG7PWTFMtYIhJ9&q=85&s=5365aec3ec20cd4608afdf183f65a7f1" alt="Delete image confirmation dialog stating the action is irreversible" width="535" height="207" data-path="images/docs/cloud/images/manage-custom-images/delete-image-dialog.png" />
    </Frame>

    <p>The image is removed from the list.</p>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Use the [Gcore Cloud API](/api-reference/cloud#tag/Images) to list, inspect, rename, and delete custom images previously [uploaded](/cloud/images/upload-an-image-to-the-storage) to a region.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with a [project ID](/api-reference/cloud/projects/list-projects) and a [region ID](/api-reference/cloud/regions/list-regions).
    </Info>

    <p>Set the following 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}"
    ```

    ## List custom images

    <p>The [list images](/api-reference/cloud#tag/Images/operation/ImagesViewSet.get) endpoint returns images visible in the region. Filter by `visibility=shared` to see only custom images, excluding public OS images.</p>

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

        client = Gcore()

        images = client.cloud.instances.images.list(visibility="shared")
        print(f"Count: {images.count}")
        for img in images.results:
            print(f"  {img.id}  {img.name}  {img.status}  {img.disk_format}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        import (
            "context"
            "fmt"
            "log"

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

        client := gcore.NewClient()
        ctx := context.Background()

        imageList, err := client.Cloud.Instances.Images.List(ctx, cloud.InstanceImageListParams{
            Visibility: cloud.InstanceImageListParamsVisibilityShared,
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Count: %d\n", imageList.Count)
        for _, img := range imageList.Results {
            fmt.Printf("  %s  %s  %s\n", img.ID, img.Name, img.Status)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl "https://api.gcore.com/cloud/v1/images/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID?visibility=shared" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Response:

        ```json theme={null}
        {
          "count": 1,
          "results": [
            {
              "id": "e418cec8-cf26-4146-aad8-82e3ca805d2e",
              "name": "my-custom-image",
              "status": "active",
              "visibility": "shared",
              "disk_format": "qcow2",
              "size": 12716032,
              "os_type": "linux",
              "architecture": "x86_64",
              "created_at": "2026-05-31T10:00:00+00:00"
            }
          ]
        }
        ```
      </Tab>
    </Tabs>

    ## Get image details

    <p>The [get image](/api-reference/cloud#tag/Images/operation/ImageDetailViewSet.get) endpoint returns full metadata for a single image by ID, including its format, size, OS type, and architecture.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        IMAGE_ID = "YOUR_IMAGE_ID"

        image = client.cloud.instances.images.get(IMAGE_ID)
        print(f"Name:         {image.name}")
        print(f"Status:       {image.status}")
        print(f"Format:       {image.disk_format}")
        print(f"Size:         {image.size} bytes")
        print(f"OS type:      {image.os_type}")
        print(f"Architecture: {image.architecture}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        imageID := "YOUR_IMAGE_ID"

        image, err := client.Cloud.Instances.Images.Get(ctx, imageID, cloud.InstanceImageGetParams{})
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Name:         %s\n", image.Name)
        fmt.Printf("Status:       %s\n", image.Status)
        fmt.Printf("Format:       %s\n", image.DiskFormat)
        fmt.Printf("Size:         %d bytes\n", image.Size)
        fmt.Printf("OS type:      %s\n", image.OsType)
        fmt.Printf("Architecture: %s\n", image.Architecture)
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        IMAGE_ID="YOUR_IMAGE_ID"

        curl "https://api.gcore.com/cloud/v1/images/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$IMAGE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Response:

        ```json theme={null}
        {
          "id": "e418cec8-cf26-4146-aad8-82e3ca805d2e",
          "name": "my-custom-image",
          "status": "active",
          "visibility": "shared",
          "disk_format": "qcow2",
          "size": 12716032,
          "os_type": "linux",
          "architecture": "x86_64",
          "ssh_key": "allow",
          "hw_firmware_type": null,
          "is_baremetal": false,
          "created_at": "2026-05-31T10:00:00+00:00"
        }
        ```
      </Tab>
    </Tabs>

    ## Update an image

    <p>The [update image](/api-reference/cloud#tag/Images/operation/ImageDetailViewSet.patch) endpoint modifies image properties — name, OS type, firmware type, and SSH key policy. The update takes effect immediately — no task polling is needed.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        IMAGE_ID = "YOUR_IMAGE_ID"

        image = client.cloud.instances.images.update(
            IMAGE_ID,
            name="my-custom-image-v2",
        )
        print(f"Updated name: {image.name}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        imageID := "YOUR_IMAGE_ID"

        image, err := client.Cloud.Instances.Images.Update(ctx, imageID, cloud.InstanceImageUpdateParams{
            Name: gcore.String("my-custom-image-v2"),
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Updated name: %s\n", image.Name)
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        IMAGE_ID="YOUR_IMAGE_ID"

        curl -X PATCH "https://api.gcore.com/cloud/v1/images/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$IMAGE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"name": "my-custom-image-v2"}'
        ```

        Response:

        ```json theme={null}
        {
          "id": "e418cec8-cf26-4146-aad8-82e3ca805d2e",
          "name": "my-custom-image-v2",
          "status": "active"
        }
        ```
      </Tab>
    </Tabs>

    ## Delete an image

    <p>The [delete image](/api-reference/cloud#tag/Images/operation/ImageDetailViewSet.delete) endpoint removes a custom image permanently. An image cannot be deleted while instances created from it are still running (when `cow_format` was enabled at upload time).</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        IMAGE_ID = "YOUR_IMAGE_ID"

        client.cloud.instances.images.delete_and_poll(IMAGE_ID)
        print("Image deleted.")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        imageID := "YOUR_IMAGE_ID"

        if err := client.Cloud.Instances.Images.DeleteAndPoll(ctx, imageID, cloud.InstanceImageDeleteParams{}); err != nil {
            log.Fatal(err)
        }
        fmt.Println("Image deleted.")
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        IMAGE_ID="YOUR_IMAGE_ID"

        curl -X DELETE "https://api.gcore.com/cloud/v1/images/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$IMAGE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Response:

        ```json theme={null}
        {
          "tasks": ["b63f0fff-1234-5678-abcd-ef0123456789"]
        }
        ```

        Poll `GET https://api.gcore.com/cloud/v1/tasks/{task_id}` until `state` is `FINISHED`.
      </Tab>
    </Tabs>
  </MethodSection>

  <MethodSection id="terraform" label="Terraform">
    <p>The `name` and `tags` attributes of `gcore_cloud_instance_image` update in place — the image ID does not change. The `url` and `os_version` attributes trigger image replacement: changing either causes Terraform to delete the existing image and [upload](/cloud/images/upload-an-image-to-the-storage) a new one, assigning a new image ID.</p>

    ## Rename

    <p>Update the `name` attribute and run `terraform apply`. Terraform sends a PATCH request to the API — the image ID does not change.</p>

    ```hcl theme={null}
    resource "gcore_cloud_instance_image" "example" {
      project_id       = var.project_id
      region_id        = var.region_id
      name             = "my-custom-image-v2"
      url              = "https://example.com/images/ubuntu-24.04-custom.qcow2"
      os_type          = "linux"
      hw_firmware_type = "uefi"
    }
    ```

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

    ## Edit tags

    <p>Add, update, or remove entries in the `tags` map and run `terraform apply`. Terraform updates tags in place without replacing the image.</p>

    ```hcl theme={null}
    resource "gcore_cloud_instance_image" "example" {
      project_id       = var.project_id
      region_id        = var.region_id
      name             = "my-custom-image"
      url              = "https://example.com/images/ubuntu-24.04-custom.qcow2"
      os_type          = "linux"
      hw_firmware_type = "uefi"

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

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

    ## Replace image

    <Warning>Changing `url` or `os_version` destroys the existing image and uploads a new one. The image ID changes — any resources referencing the old ID must be updated.</Warning>

    <p>Update the `url` attribute to a new image source and run `terraform apply`. Terraform shows `-/+` in the plan — destroy then create replacement — and executes both operations in sequence. Changing `os_version` triggers the same replacement.</p>

    ```hcl theme={null}
    resource "gcore_cloud_instance_image" "example" {
      project_id       = var.project_id
      region_id        = var.region_id
      name             = "my-custom-image"
      url              = "https://example.com/images/ubuntu-24.04-v2.qcow2"  # forces replacement
      os_type          = "linux"
      os_version       = "24.04"                                              # forces replacement if changed
      hw_firmware_type = "uefi"
    }
    ```

    ```bash theme={null}
    terraform plan   # shows: -/+ destroy and then create replacement
    terraform apply
    ```

    ## Delete

    <p>Remove or comment out the resource block, then run `terraform apply`. Terraform detects the missing declaration and deletes the image.</p>

    ```hcl theme={null}
    # Remove or comment out this block:
    # resource "gcore_cloud_instance_image" "example" {
    #   name         = "my-custom-image"
    #   url          = "https://example.com/images/ubuntu-24.04-custom.qcow2"
    #   project_id   = var.project_id
    #   region_id    = var.region_id
    # }
    ```

    ```bash theme={null}
    terraform apply
    ```
  </MethodSection>
</MethodSwitch>
