GCP VM Images Explained: Public, Custom, and Families
Every Compute Engine VM starts from an image. An image defines the operating system, pre-installed software, and disk layout that the VM boots from. GCP provides hundreds of public images maintained by Google and OS vendors. For teams that need every VM to start in a known, consistent state, custom images are the solution: bake your configuration in once, and every new VM is identical from first boot.
This page explains what VM images are, how public and custom images differ, what image families are for, and when a custom image is worth building. It also covers practical CLI examples and a clear comparison with snapshots and instance templates.
VM images in GCP explained simply
Picture a rubber stamp and an ink pad. The stamp defines a shape. Every time you press it onto paper, you get an identical impression. The stamp itself never changes, no matter how many copies you make.
A VM image works the same way. The image is the stamp. Each new VM is an impression. Compute Engine copies the image onto a fresh persistent disk and boots the VM from it. Once the VM is running, it is completely independent. You can modify the VM all you like and it will not alter the image it came from.
An image is a starting template, not an ongoing connection. The VM and the image go their separate ways the moment the VM boots. Delete the image later and the VM keeps running fine.
If you are just getting started with Compute Engine, the image choice is simple: pick a public image for the OS you want (Debian, Ubuntu, Windows Server) and you are done. Custom images come into play when you need that stamp to include your own software and configuration.
How VM images work in Compute Engine
When you create a VM, whether through the console, gcloud, or Terraform, you specify an image. Compute Engine then does the following:
- You select an image (or an image family, which resolves to the latest image in that group)
- Compute Engine creates a new persistent disk and copies the image data onto it
- The VM boots from that disk
- The image is left unchanged and can be used to create any number of additional VMs
There are three categories of images in GCP:
Public images: Provided by Google and OS vendors. Always available, regularly patched, no setup required.
Custom images: Images you create from an existing VM or disk. Used to pre-install software and configuration so every new VM starts in a specific known state.
Shared images: Custom images stored in one project and shared with other projects via IAM. Common in organisations where a platform team owns the approved base image and application teams consume it.
Public images vs custom images
The choice between public and custom images comes down to how much consistency you need at VM creation time.
| Public images | Custom images | |
|---|---|---|
| Maintained by | Google or OS vendor | Your team |
| Security patches | Automatic via image family | You rebuild and re-release |
| Setup time per VM | Requires startup script or manual config | Zero; everything is pre-baked |
| Typical use | Dev environments, quick launches, standard servers | Production fleets, golden images, regulated environments |
| Cost | Free for Linux; licence fee for Windows | Storage cost for the image |
| Complexity | Low | Higher; requires a build and release process |
Use a public image when you are learning, prototyping, or running a single VM. A startup script can handle any additional software installation at boot. Consider a custom image when you are managing many VMs that all need the same configuration, when boot speed matters, or when you need a repeatable and auditable baseline across environments.
Security-conscious teams often combine a custom image with instance templates to lock both the disk state and the VM configuration in one versioned unit. Note that Linux public images are free. Windows Server images include a Microsoft licence cost added to the VM price.
Image families explained
An image family is a named group of related images. The family name always resolves to the most recent non-deprecated image in that group.
Think of it like a magazine subscription. When you subscribe, you always receive the latest issue automatically. If you had ordered a specific back issue instead, you would be stuck with that one forever. Image families work the same way: reference the family name and you always get the latest patched version. Hardcode a specific image name and you are pinned to that version until someone manually updates every script and template that references it.
For example, the debian-12 family in the debian-cloud
project currently points to a name like debian-12-bookworm-v20250312.
When Google releases a patched version next month, the family pointer updates
automatically. Any script or Terraform config referencing the family name
gets the new version without any changes.
Use —image-family and —image-project
in every script, instance template, and Terraform config. Never reference
a specific image name like debian-12-bookworm-v20240415. This
rule applies equally to public images and your own custom images.
# Reference the family to always get the latest patched image
gcloud compute instances create my-vm \
--image-family=debian-12 \
--image-project=debian-cloud \
--zone=us-central1-a \
--machine-type=e2-medium
# Check which specific image the family currently resolves to
gcloud compute images describe-from-family debian-12 \
--project=debian-cloud
# List all images in a family
gcloud compute images list --filter="family:debian-12"The same principle applies in
Terraform:
use data “google_compute_image” with the family
argument set to a family name rather than referencing a specific image name.
When to use VM images
Here are concrete scenarios where your image choice actually matters:
Launching a standard Linux VM: Use a public image. Pick the OS family you need (
debian-12,ubuntu-2204-lts) and let image families handle patching. No extra setup required when creating your first VM.Building a repeatable app server fleet: Create a custom golden image with your application and agents pre-installed. Every new VM starts identically, with no startup scripts diverging over time across instances.
Standardising security baselines: Bake your monitoring agent, endpoint security tool, and OS hardening configuration into one approved image. All teams in the organisation boot from it instead of configuring each VM independently.
Faster autoscaling: When a managed instance group needs to scale quickly, VMs that boot from a pre-configured custom image are ready faster than VMs that run a long startup script to install dependencies at boot.
Disaster recovery and cloning: An image of a known-good VM state lets you recreate that VM in any region. Combine this with snapshots for ongoing disk backup.
VM images vs snapshots vs instance templates
These three concepts are often confused. They serve different purposes and are used at different points in the VM lifecycle.
| Concept | What it stores | Primary purpose | Can boot a new VM? |
|---|---|---|---|
| VM image | Disk contents captured as a template | Create new VMs from a known state | Yes, directly |
| Disk snapshot | Point-in-time incremental disk backup | Backup and recovery | No, must create a disk first |
| Instance template | VM configuration spec (no disk data) | Create many VMs from one definition | No, references an image |
Image vs snapshot: An image is a template for new VMs. A snapshot is a backup of an existing disk. You take snapshots of running VMs to protect their data. You create images of configured VMs to replicate that configuration elsewhere. You can convert a snapshot into an image, but you cannot boot directly from a snapshot.
Image vs instance template: An image defines what is on the disk. An instance template defines the full VM specification: machine type, network, disk size, service account, and which image to use. Instance templates reference images; they do not replace them. For any VM fleet managed by a managed instance group, you need both.
How they work together: A platform team builds a golden image and assigns it to a family. They then create an instance template that references that family. The managed instance group uses the template. When the image is updated, a new template version points to the new family and the group rolls out updated VMs without changing any downstream automation.
Creating a custom image
The standard workflow for building a golden image:
- Start from a public base image that matches your target OS
- Configure the VM: install packages, agents, harden the OS
- Stop the VM before imaging (a stopped disk is consistent; imaging a running disk risks capturing partial writes)
- Create the image from the boot disk and assign it to a family
- Test a VM launched from the new image before putting it into production
- Deprecate the old image version once the new one is validated
# Stop the VM before imaging to ensure a clean, consistent disk state
gcloud compute instances stop my-app-server --zone=us-central1-a
# Create an image from the stopped VM's boot disk
gcloud compute images create golden-app-image-v2 \
--source-disk=my-app-server \
--source-disk-zone=us-central1-a \
--family=golden-app \
--description="App server with monitoring agent v3.1 and CIS hardening"
# Verify the image was created
gcloud compute images list --filter="family:golden-app"
# Create a new VM from the custom image
gcloud compute instances create new-app-server \
--image-family=golden-app \
--image-project=YOUR_PROJECT_ID \
--zone=us-central1-a \
--machine-type=e2-mediumThe machine type you pick when launching from the image is independent of the machine type used to build it. The image only captures disk contents, not the VM configuration.
Versioning and deprecating old images
As you build new image versions, deprecate old ones rather than deleting them immediately. A deprecated image is still usable but is marked as outdated. You can link to the replacement so anyone still referencing the old name knows what to switch to.
# Deprecate the previous version and point to the replacement
gcloud compute images deprecate golden-app-image-v1 \
--state=DEPRECATED \
--replacement=golden-app-image-v2Deleting an image does not affect VMs or disks already created from it. But you cannot create new VMs or disks from a deleted image. Deprecate first, then delete only after confirming no automation still references the old image name or ID.
Sharing images across projects
In larger organisations, the standard pattern is a dedicated image project: a single GCP project that only stores approved golden images. Application teams reference images from that project without needing write access to it.
This avoids duplicating images into every project and ensures all teams boot from the same patched, approved base. The platform team controls the image lifecycle. Application teams simply consume whatever the family resolves to.
# Grant a consuming project's Compute Engine service account read access to the image
gcloud compute images add-iam-policy-binding golden-app-image-v2 \
--project=platform-images \
--member=serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--role=roles/compute.imageUser
# Create a VM in a consuming project using the platform image
gcloud compute instances create my-app-server \
--image-family=golden-app \
--image-project=platform-images \
--zone=us-central1-a \
--machine-type=e2-mediumTo grant access to all images in an image project rather than individual
images, grant roles/compute.imageUser at the project level
instead of on a specific image resource. Combine the shared image pattern
with instance templates
to version the full VM spec alongside the image.
Common mistakes with VM images
Imaging a running VM without stopping it first. Using
—forceto image a running disk may capture an inconsistent state if writes were in progress at that moment. Stop the VM before creating the image for a clean result.Hardcoding specific image names. Names like
debian-12-bookworm-v20240415become stale and will eventually be deprecated. Your scripts keep using the old image silently. Reference image families so scripts automatically get the latest patched version.Not assigning custom images to a family. Without a family, every script, template, and Terraform config must be updated by hand each time you release a new image version. Assign a family at image creation time so version bumps propagate automatically.
Using a custom image when a public image plus startup script would be simpler. Custom images add real operational overhead: a build process, a release workflow, and a deprecation policy. For lighter configuration, a public image with a short startup script is often the better tradeoff. Build a custom image when pre-baking genuinely saves time or enforces a security baseline that cannot reliably be scripted at boot.
Every VM created from the image inherits whatever is inside it, including any API keys, passwords, or certificates baked into the disk. This applies to every VM created by every team that uses the image. Fetch secrets at boot time using Secret Manager or inject them through a startup script. Baking secrets into an image is one of the most common ways credentials end up in the wrong hands.
Summary
- Every Compute Engine VM boots from an image: it is the template for the boot disk
- Public images are maintained by Google and OS vendors; use them for standard VMs and development
- Custom images let you pre-bake software, agents, and configuration so every VM starts in a known state
- Image families always resolve to the latest non-deprecated image; use them instead of hardcoded names
- Stop the VM before imaging for a consistent, clean disk state
- Deprecate old image versions rather than deleting them immediately
- Share images across projects via IAM rather than duplicating them into every project
- Never bake secrets into images: use Secret Manager or startup scripts to inject them at boot
Frequently asked questions
What is a VM image in GCP?
A VM image is a template that defines the operating system, file system, and pre-installed software on a Compute Engine boot disk. When you create a VM, GCP copies the selected image onto a new persistent disk and boots from it. Without an image, there is nothing to boot. GCP provides hundreds of ready-to-use public images, and you can also create your own custom images.
What is the difference between a VM image and a disk snapshot?
An image is a template for creating new VM boot disks. It is the starting point for new VMs. A snapshot is a point-in-time backup of an existing disk used for recovery, not for bootstrapping new VMs. You cannot boot a VM directly from a snapshot. You can, however, create an image from a snapshot if you want to turn a backup into a reusable template.
What is an image family and why should I use it?
An image family is a named group of related images. The family name always resolves to the latest non-deprecated image in that group. Using --image-family=debian-12 instead of a specific name like debian-12-bookworm-v20240415 means your scripts and Terraform configs automatically pick up the latest security-patched version without any code changes. Always prefer family names over hardcoded image names in automation.
Should I use a public image or a custom image?
Start with a public image. They are maintained by Google and OS vendors, patched regularly, and free to use for Linux. Move to a custom image when you need every VM to boot with the same pre-installed software, agents, or baseline configuration. Custom images eliminate per-VM setup time but require a process to build, test, and update them as the OS receives patches.
Can I share a custom image across GCP projects?
Yes. Store the image in a dedicated image project, then grant the consuming project read access using IAM: gcloud compute images add-iam-policy-binding IMAGE_NAME --project=image-project --member=serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com --role=roles/compute.imageUser. The consuming project references the image with --image-family=FAMILY --image-project=image-project.