Basic vs Predefined vs Custom IAM Roles in GCP
Every access decision in GCP starts with choosing a role family. The three families (basic, predefined, and custom) differ in how broadly they grant permissions, who maintains them, and when they belong in production. Predefined roles are the correct default for almost everything. Custom roles fill specific gaps. Basic roles belong only in throwaway sandboxes.
Simple explanation
If you are new to GCP IAM, start here. These three role families answer one question: how broadly do you want to grant access?
Basic roles — three old roles (Viewer, Editor, Owner) that grant access across every service in a project. Created before the modern IAM system existed. Too broad for production.
Predefined roles — curated roles maintained by Google, each scoped to one service and one job function.
roles/bigquery.dataViewercan only read BigQuery data. It does nothing to Cloud Storage or Cloud Run. These are your default choice.Custom roles — roles you build by selecting specific permissions from GCP’s full permission catalog. Use them when no predefined role fits without over-granting in a way that matters. You maintain them; Google does not.
Start with predefined roles for every grant. Move to a custom role only
if the closest predefined option includes permissions you genuinely need
to exclude. If you are tempted to reach for Editor or
Owner, stop — that is the wrong direction.
How IAM role families work in GCP
In GCP, you never grant individual permissions directly. You grant IAM roles: named collections of permissions attached to a principal via a binding in an IAM policy. The role family you choose determines two things: the blast radius if that account is ever compromised, and the ongoing maintenance burden on your team.
Basic roles span many services simultaneously. A single compromised account with
Editoris a project-wide incident across every service in the project.Predefined roles are scoped to a specific service and function. A compromised account with
roles/bigquery.dataViewercan only read BigQuery. It has no access to Cloud Storage, Cloud SQL, or any other service.Custom roles can be scoped to exactly the permissions a job needs, but the definition does not update automatically as services evolve.
Job title analogy
A basic role is like the title “staff” — it grants entry to every part of the building by default. A predefined role is like “warehouse operative” — that person can work the warehouse, but the office, server room, and boardroom are still locked. A custom role is a bespoke access list printed specifically for one employee’s job. All three give “access,” but the scope is completely different.
Role family choice should also be paired with resource-level scoping. Even a narrow predefined role applied at project level grants that access across every resource of that type in the project. Binding the same role to a specific Cloud Storage bucket or BigQuery dataset limits it to that one resource. Both dimensions together are what least privilege actually means in practice.
Basic roles: what they actually grant
Basic roles predate the modern IAM system. There are three:
roles/viewer, roles/editor, and
roles/owner. They apply across all services in the
project at once.
Viewer — read-only access to most project resources, including Cloud Storage objects, Compute Engine instance metadata, and most API resource listings across every service
Editor — read and write on most resources: create, modify, and delete data in Cloud Storage, Cloud SQL, Firestore, Compute Engine, and most other services; cannot modify IAM policies
Owner — full project access including IAM policy management, member invitations, and the ability to delete the project
If you grant roles/editor to a service account that only
needs to read BigQuery data, that account can also delete your Cloud SQL
databases, overwrite your Cloud Storage buckets, and modify your Cloud Run
configuration. Not because you wanted that. Basic roles do not distinguish
between services. One compromised Editor account is a project-wide
incident.
There is one acceptable use case for basic roles: a temporary personal sandbox project where you are the only user and there is no sensitive data. Everywhere else, they create unnecessary risk that grows every time Google adds a new service.
Predefined roles: scoped by service and function
Predefined roles are created and maintained by Google. The naming convention
is roles/SERVICE.FUNCTION. Each role is scoped to one service
and one job function within that service. They are your default choice for
almost all access grants.
The same read / write / admin pattern repeats across services. Here are the equivalent tiers across three common ones:
| Service | Read only | Read + Write | Full admin |
|---|---|---|---|
| Cloud Storage | storage.objectViewer | storage.objectAdmin | storage.admin |
| BigQuery | bigquery.dataViewer | bigquery.dataEditor | bigquery.admin |
| Cloud Run | run.viewer | run.developer | run.admin |
When Google adds new capabilities to a service, the predefined roles for that service are updated automatically. Your existing bindings benefit from those updates without any action on your part. Custom roles work the opposite way.
If your project already has over-broad role grants, GCP’s IAM Recommender analyses 90 days of API call history and suggests narrower predefined roles for each principal. It is the fastest way to tighten legacy access without manually auditing every binding.
# Find predefined roles for a specific service
gcloud iam roles list --filter="name:roles/bigquery"
# Inspect what a specific predefined role actually grants
gcloud iam roles describe roles/bigquery.dataViewer
# Compare two candidate roles before deciding which to use
gcloud iam roles describe roles/storage.objectViewer
gcloud iam roles describe roles/storage.objectAdminWhen choosing a role for a CI/CD pipeline, look for roles ending in
Developer or Deployer. A pipeline that only
deploys to Cloud Run probably needs roles/run.developer,
not anything broader. For the exact commands to apply these grants, see
Managing IAM with gcloud.
Custom roles: precision with a maintenance cost
Custom roles let you build a role from individual permissions. Use them when no predefined role fits because the closest option grants specific permissions you need to exclude, specifically ones that genuinely matter for your security requirements.
The tradeoff is precision versus maintenance. A custom role is exactly what you define, nothing more and nothing less. But it stays exactly as you left it. When Google adds new capabilities to a service, predefined roles update automatically. Your custom role does not. A deployment pipeline role that was correct last year may now be missing permissions for a new feature your team started using, or may include permissions that were renamed or split.
# Create a custom role from a YAML definition
gcloud iam roles create runDeployerMinimal \
--project=my-app-prod \
--file=run-deployer-role.yaml
# run-deployer-role.yaml:
# title: "Cloud Run Deployer"
# description: "Deploy Cloud Run services without IAM access"
# stage: GA
# includedPermissions:
# - run.services.create
# - run.services.update
# - run.services.get
# - run.services.list
# - artifactregistry.repositories.downloadArtifacts
# Add a permission later if requirements change
gcloud iam roles update runDeployerMinimal \
--project=my-app-prod \
--add-permissions=run.services.deleteCustom roles have four lifecycle stages: ALPHA,
BETA, GA, and DISABLED. Setting a
role to DISABLED makes all its bindings inert without removing
the role or its policy entries. This is useful during audits and
decommissioning when you want to disable access without a destructive change.
A custom role that was correctly scoped last year may now be missing permissions your application needs, or may include permissions that were renamed. Schedule a quarterly review of each custom role. Predefined roles update automatically; custom roles do not.
For teams using infrastructure as code, managing custom role definitions in version control alongside IAM bindings in Terraform makes quarterly reviews practical: you can diff the permission list, track who last updated the definition, and roll back cleanly if needed.
Basic vs predefined vs custom: side-by-side
| Role family | Scope | Managed by | Best for | Main risk | Use in production? |
|---|---|---|---|---|---|
| Basic | All services in a project | Legacy (Google) | Throwaway personal sandboxes | Project-wide blast radius on any compromise | No — avoid |
| Predefined | One service, one function | Most production grants | Occasional minor over-grant | Yes — default choice | |
| Custom | Exactly what you define | Your team | Gaps predefined roles cannot fill | Permission drift without regular reviews | Only when predefined over-grants meaningfully |
Predefined roles are the best default for three reasons: Google maintains them so you get updates automatically, they map to real job functions (dataViewer, developer, deployer), and they have been designed around sensible permission boundaries for each service.
Basic roles are dangerous in production because their scope is the entire project. Every time Google adds a new service, a basic role immediately includes access to it — a growing attack surface you never explicitly approved.
Custom roles are powerful but come with a real operational cost. Every custom role you create is a definition your team must review, update, and eventually deprecate. That overhead is worth it when predefined roles genuinely over-grant in a way that matters. It is not worth it when the concern is theoretical rather than practical.
When to use each role type
Use basic roles only for temporary personal sandboxes
If you are spinning up a short-lived test project for personal learning with no sensitive data, basic roles remove friction. As soon as the project holds anything real, has more than one user, or is connected to any shared resource, replace them with predefined roles.
Use predefined roles for most production workloads
Service account that reads BigQuery data — grant
roles/bigquery.dataVieweron the specific dataset, notroles/editoron the projectCI/CD pipeline deploying to Cloud Run — grant
roles/run.developeron the specific Cloud Run service, not a broad developer or editor role at project levelSecurity reviewer who needs read-only audit access — grant
roles/logging.viewerandroles/iam.securityReviewer, notroles/vieweracross the whole projectPlatform admin managing one GCP service — use the predefined
SERVICE.adminrole for that service rather than project-level Owner
Use custom roles when predefined roles over-grant in a meaningful way
Custom roles are worth building when:
The closest predefined role includes a write or delete permission you need to exclude for a sensitive workload
You are scoping a service account for a very narrow job function where even a viewer-level predefined role includes permissions the workload should never have
Your organisation has a compliance requirement to document exactly which permissions each role grants, with an attached review cadence
Office keycard analogy
Basic roles are a master keycard for the entire building — every door, every floor. Predefined roles are floor-specific access cards: a developer card opens the engineering floor but not the server room or the finance department. Custom roles are hand-cut keys that open exactly the doors you specify. The hand-cut key is the most precise option, but you are responsible for updating it every time the locks change.
How to choose the right role family
Work through this in order for every access decision. For the commands to apply the grant once you have decided, see Managing IAM with gcloud. For the underlying principle, see Least Privilege in GCP.
Identify the service involved. Which GCP service does the identity need to interact with? Cloud Storage? BigQuery? Cloud Run? Pub/Sub?
Find the narrowest predefined role. Run
gcloud iam roles list —filter=“name:roles/SERVICE”and look for roles matching the actual job function: viewer, creator, developer, deployer.Inspect the role’s permissions before granting. Run
gcloud iam roles describe roles/ROLE_NAME. Check whether any included permissions are unnecessary for the task.Confirm it covers the real task. Does the predefined role include every permission the identity actually needs?
Create a custom role only if the over-grant genuinely matters. If the predefined role includes a permission you do not need but it poses no realistic risk for this workload, the maintenance cost of a custom role is not worth it.
Never fall back to basic roles in production. If you cannot find the right predefined role, use a custom role. Never treat Editor as a fallback.
For temporary access or access that should expire after a deployment window, combine your role choice with IAM Conditions. You can set a binding to expire at a specific date, restrict it to resources matching a name prefix, or require a specific resource tag — without needing a separate role.
Common mistakes
Granting
roles/editorto fix a permission error quickly. This unblocks the error but grants write access to every service in the project. Identify the specific permission missing, find the correct predefined role that includes it, and replace the Editor grant. The fix takes two commands and removes significant ongoing risk.Granting
roles/ownerto a service account. A service account with Owner can modify any IAM binding on the project, including granting itself or others new permissions. If a workload’s service account is ever compromised, Owner means total project compromise. Use the predefined admin role for the specific service instead. See Service Account Impersonation for safer patterns.Creating a custom role before checking predefined options. Run
gcloud iam roles list —filter=“name:roles/SERVICE”andgcloud iam roles describeon every candidate first. The right predefined role exists for most common tasks — the custom role maintenance burden is only worth taking on when it genuinely does not.Sharing one broad role across multiple workloads. Each service account should have role assignments tailored to its specific job. A shared powerful role means a compromise of any one workload exposes all the others.
Not scheduling reviews of custom roles. Custom role permissions go stale as services evolve. A role that was correctly scoped at creation may now be missing permissions added to the equivalent predefined role, or may include permissions that were renamed — silently breaking your application or silently granting more than intended.
Summary
- Basic roles are project-wide and cover every service simultaneously — avoid them in any production environment
- Predefined roles are service-scoped, maintained by Google, and the correct default for almost all access grants
- Custom roles give precise control but require your team to maintain, review, and update them on a schedule
- Always run
gcloud iam roles listanddescribebefore creating a custom role — the right predefined role exists for most tasks - Combine role family choice with resource-level binding scope for true least privilege
- Custom roles in
DISABLEDstage make all their bindings inert without removing policy entries - Least privilege requires both dimensions: which permissions (role family) and which resources (binding scope)
Frequently asked questions
What is the difference between basic and predefined roles in GCP?
Basic roles (Viewer, Editor, Owner) apply across every service in the project simultaneously — they predate modern IAM. Predefined roles are scoped to one service and one job function, like roles/bigquery.dataViewer for BigQuery read access only. Predefined roles are the correct default for almost all production grants. Basic roles are only appropriate in throwaway sandbox projects with no sensitive data.
Are predefined roles safer than basic roles?
Yes, significantly. A compromised account with roles/editor can delete Cloud SQL databases, overwrite Cloud Storage objects, and modify Cloud Run configuration. The same account with roles/bigquery.dataViewer can only read BigQuery data. Predefined roles limit the blast radius to one service and one function within that service.
When should I create a custom IAM role in GCP?
Create a custom role only when the closest predefined role over-grants permissions that matter for your security requirements. Before creating one, run gcloud iam roles list --filter="name:roles/SERVICE" to confirm no suitable predefined role exists. Custom roles require ongoing maintenance — they do not update automatically when Google adds new features to a service.
Is Owner ever appropriate in Google Cloud?
Owner is appropriate only for a small number of project administrators who manage billing, IAM, and project lifecycle. It should never be granted to service accounts or used for day-to-day operational work. For service-specific administration, use the predefined admin role for that service rather than project-level Owner.
How do I find the right predefined role for a task?
Run gcloud iam roles list --filter="name:roles/SERVICE" to list predefined roles for a service, then gcloud iam roles describe roles/ROLE_NAME to inspect its permissions. The GCP documentation for each service also lists available roles. For existing bindings, IAM Recommender analyses actual API usage over 90 days and suggests narrower alternatives.
What happens to bindings when I disable a custom role?
Setting a custom role to DISABLED stage makes all its bindings completely inert — principals with that role effectively have no permissions from it until the role is re-enabled. This lets you deactivate a role without deleting it or removing its policy entries, which is useful during audits and decommissioning.