GCP Fundamentals

The GCP Resource Hierarchy Explained: Organization, Folders, Projects, and Why It Runs Everything

Open the Google Cloud console for the first time and it asks you to “select a project.” You create one, spin up a VM, everything works. Six months later there are forty projects, three teams, a finance person asking who spent ₹4 lakh on BigQuery last month, and a security review wondering why a marketing developer can read the production database. Nobody designed this — it grew. Whether it grew into a mess or not comes down to the one thing almost nobody studies on day one: the GCP resource hierarchy.

Here is the whole idea in one sentence. Everything in Google Cloud lives in a tree, and three things flow down that tree automatically: who can do what (IAM), what is forbidden (Org Policy), and who pays (billing). Get the tree right and governance is something you set once at the top and forget. Get it wrong and you grant permissions project by project, chase org-wide policy through forty places, and reconcile bills by hand forever. The hierarchy isn’t paperwork for the auditors — it’s the single most load-bearing design decision in your whole Google Cloud estate, invisible until the day it saves you or sinks you.

This article builds the mental model from the ground up. We start with an analogy you already understand (a company’s org chart and the building it works in), define every node — Organization → Folders → Projects → Resources — and trace how a permission, a guardrail, and a rupee each travel from the root to a running VM. You’ll get the decision tables for folder-vs-project, the real limits, the gcloud and Terraform to build a clean hierarchy, and the handful of mistakes that lock teams out of their own org. By the end the “select a project” prompt looks completely different — because you’ll finally see the tree behind it.

What problem this solves

Without a hierarchy, every cloud resource is an island. Imagine a company where every laptop, door key, and expense card is configured individually — no departments, no shared policies, no roll-up reporting. Onboarding a hire means touching every system by hand; firing someone means hoping you found every grant; asking “what did engineering spend?” means summing receipts one by one. That is exactly what a flat pile of parentless GCP projects feels like at scale.

The resource hierarchy solves four pains at once. Access control at scale: grant a team once on the folder that contains thirty projects and inheritance does the rest. Guardrails that can’t be bypassed: instead of hoping nobody makes a public bucket or a VM with an external IP, an Org Policy at the top makes it structurally impossible, everywhere, forever. Billing roll-up: spend maps to teams and cost centers that match your real org chart. Blast-radius containment: because a project is a hard boundary, a compromised credential in dev cannot touch prod.

Who hits this? Everyone eventually, but it bites hardest at the jump from “one developer, one project” to “multiple teams, shared accountability.” Learn it early and you never become the team retrofitting governance onto forty ungoverned projects — you put the tree in place while it’s cheap.

Pain without a hierarchy What it looks like in production What the hierarchy gives you
Access granted per project 30 separate IAM grants to add one team; orphaned access after people leave One grant on a folder, inherited by every project under it
No enforceable guardrails “Please don’t make buckets public” in a wiki nobody reads Org Policy at the root makes it impossible everywhere
Billing is a spreadsheet Manually summing per-project invoices to answer “what did team X spend?” Spend rolls up the tree to folders / cost centers
Everything can reach everything A leaked dev key can hit prod data Project boundary contains the blast radius
Onboarding is bespoke New project = re-do all the security settings by hand New project inherits IAM + policy from its folder automatically
No clear ownership “Whose project is this?” with no answer Folder structure mirrors the org chart; ownership is obvious

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You need almost nothing to follow the concepts — if you understand a company org chart, you are ready. To run the hands-on parts you should have a Google account, the ability to install or use the gcloud CLI (or Cloud Shell, which has it pre-installed), and ideally access to a Google Cloud Organization via Google Workspace or Cloud Identity. If you only have a personal Gmail account, you will have projects but no Organization node — that distinction matters, and we cover it explicitly below. If the CLI is new to you, start with Getting started with the gcloud CLI, Console and Cloud Shell and come back.

Where this fits: the resource hierarchy is the foundation layer — everything else in GCP sits on top of it. IAM decides who can act on the nodes; the hierarchy decides the shape those actions inherit through. Networking (Shared VPC), billing, and governance (Org Policy) all attach to nodes in this tree. This article is the conceptual base for GCP IAM fundamentals: roles, service accounts and policy, for Org Policy guardrails on the resource hierarchy, and for the full GCP foundation blueprint with Organization and Shared VPC. If you already know AWS, the closest analogue is AWS Organizations + accounts + OUs; if you know Azure, it is Management Groups + Subscriptions + Resource Groups — but the GCP version has its own rules, which we will be precise about.

You already know… The GCP equivalent Key difference to remember
AWS Organization (root) Organization node One Organization per Workspace/Cloud Identity domain
AWS Organizational Unit (OU) Folder GCP folders nest up to a fixed depth; OUs nest deeper
AWS Account Project The project is GCP’s hard isolation + billing boundary
AWS resource (EC2, S3) Resource (VM, bucket) Lives inside exactly one project
Azure Management Group Folder Similar inheritance model
Azure Subscription Project (billing-wise) A project ties to one billing account at a time
Azure Resource Group (no exact peer) GCP has no sub-project grouping node; labels fill the gap
AWS SCP / Azure Policy Org Policy constraint Inherited down the tree as a guardrail

Core concepts

Here is the mental model — install it carefully, because every later section is just a consequence of it.

Think of the hierarchy as a company that occupies a building. The Organization is the company itself — the root that owns everything and where top-level rules live. Folders are the departments and teams (Engineering, Finance, Marketing) — grouping things that share a manager, a budget, and a set of rules. Projects are the individual workspaces where work happens (an app’s dev environment, a data warehouse, a website’s prod stack) — each a private office with its own door, keys, and expense account. Resources — VMs, buckets, databases — are the desks and equipment inside an office. Everything sits in one office; every office belongs to a department; every department rolls up to the company.

What makes the tree powerful: rules set high up flow down automatically. A “no smoking” policy applies to every desk without being re-stated per room; a department head’s authority covers every office under them, including ones created next year. This downward flow is inheritance, and three different things inherit down the GCP tree: IAM allow policies (who can do what — grant a role on a folder and the grantee has it on every project beneath), Org Policy constraints (what’s forbidden — set “no external IPs” on a folder and no child can sneak past it), and billing/labels (spend rolls up into a structure you can report on).

Now define each node precisely — the analogy gets you 90% there; details are where people trip.

The Organization is the root, created automatically when you set up Google Workspace or Cloud Identity for a domain (say kloudvin.com). Exactly one per domain. Critically — a personal @gmail.com account gives you no Organization at all, so your projects float as orphans with no inherited IAM, no Org Policy, no centralized billing. It’s the biggest “where’s my Organization?” surprise for beginners, and the answer is always “you need a Workspace or Cloud Identity domain.”

Folders are optional grouping nodes under the Organization (or other folders) that organize projects and apply shared IAM and policy. A folder maps to a department, an environment (prod vs non-prod), or a team. They nest to a limited depth (see limits) and require an Organization.

Projects are the workhorse and most important node — a hard boundary that owns its resources, has a globally unique immutable Project ID (e.g. kloudvin-prod-web-7421) and Project Number, enables its own APIs, holds its own IAM, and attaches to one billing account at a time. Resources can’t span projects (except deliberate setups like Shared VPC). It’s where billing aggregates, most quotas apply, and the blast radius stops.

Resources are everything you deploy — a VM, a bucket, a Cloud SQL instance, a BigQuery dataset — each in exactly one project. They’re the leaves.

Node Plain-English meaning Required? Holds IAM? Attaches billing? Created by
Organization The whole company (root) Auto with Workspace/Cloud Identity Yes (top of inheritance) Indirectly (via projects) Domain setup
Folder A department / team / environment Optional Yes (inherited by children) No You (org has it)
Project A specific workspace for an app/env Yes — you always have ≥1 Yes Yes — one account at a time You
Resource A VM, bucket, DB, dataset Yes — the actual workload Some (e.g. bucket IAM) No (rolls up to project) You

The limits that shape the design

The tree isn’t infinitely deep or wide, and the real numbers steer you toward shallow, sane structures. Treat these as guardrails on the shape of your hierarchy.

Limit Real value What it constrains Design implication
Folder nesting depth Up to 10 levels below the Organization How deep folders can stack Keep it to 2–3; you’ll never need 10
Folders under one parent 300 (org or folder) Fan-out at any single node Group by team/env, not per-project
Projects per Organization A default quota (e.g. low thousands), increasable How many live projects you can hold Clean up unused; request increases early
Project creation rate A per-account/quota rate limit Bursty automated project creation Throttle factories; batch with backoff
IAM bindings per allow policy 1,500 members per policy (≈250 with conditions) Members directly on one node Bind groups, never individuals — one binding = a whole team
Org Policy scope Set at Org / Folder / Project only Where constraints attach Resources inherit; you can’t pin a policy to a single bucket via Org Policy
Project ID 6–30 chars, lowercase/digits/hyphen, global-unique, immutable Naming Pick a convention once; you live with it forever
Deleted-project recovery ~30-day soft-delete window ID reuse + restore Don’t script instant delete-then-recreate with same ID

The 1,500-bindings limit is the technical reason “always grant to groups” is more than style — a few group bindings on a folder scale to thousands of people, while per-user bindings hit the ceiling. And the generous 10-level depth is a trap: you can nest ten deep, but policy reasoning doesn’t survive it. Shallow wins.

The three things that inherit — side by side

People conflate IAM inheritance and Org Policy inheritance because both “flow down.” They’re different mechanisms with different math, and keeping them distinct is the key insight of this topic.

What flows down Direction Combine rule Mental model Set at
IAM allow policy (grants) Org → Folder → Project → Resource Additive (union) — you keep every role granted at any ancestor level “Permissions accumulate as you go up the chain” Any node
Org Policy (constraints) Org → Folder → Project Most-restrictive-wins by default — a parent deny cannot be loosened by a child unless the constraint allows merging “Guardrails tighten as they stack; children can’t escape a parent’s no” Org / Folder / Project
Billing / cost Resource → Project → Folder → Org Aggregated (sum) “Money rolls up for reporting” Project attaches; reporting rolls up

Read that table twice. IAM is additive going down (a child can only add, never subtract an inherited role). Org Policy is restrictive going down (a parent’s prohibition is the floor; children can be equal or tighter, never looser). Cost aggregates going up. Almost every confusing thing about GCP governance dissolves once these three rules sit separately in your head. So to answer “can this person do this on this resource?”, GCP walks up the resource’s ancestry — resource, project, every ancestor folder, the Organization — and unions every IAM binding. Effective permissions are the sum, which is exactly why a single roles/owner at the Organization is catastrophic (it lands on everything) and why you grant low and narrow.

Inside the Organization node

The Organization is the keystone, so let’s be exact about what hangs off it.

It’s created automatically and exactly once when a domain is provisioned for Workspace or Cloud Identity. Its name is your domain (kloudvin.com), it has a numeric ID, and it’s owned by the domain rather than any single user — which is why you designate human administrators via IAM rather than relying on a personal account.

Two roles matter enormously here. Organization Administrator (roles/resourcemanager.organizationAdmin) manages the Organization’s IAM and structure but is not automatically allowed to do everything inside projects. Organization Policy Administrator (roles/orgpolicy.policyAdmin) sets the guardrails. A new Organization’s first need is to grant these to a real person — better, a small admin group — because the bootstrap state is sparse by design.

Organization-level concern Role / mechanism Why it lives at the Org
Manage hierarchy & IAM at top roles/resourcemanager.organizationAdmin Single point to delegate downward
Set guardrails roles/orgpolicy.policyAdmin Constraints inherit to everything
Create folders roles/resourcemanager.folderCreator Folders only exist under an Org
Create projects roles/resourcemanager.projectCreator Controls who can spawn projects
Link billing roles/billing.admin (on billing account) Associate projects to accounts
Security command center roles/securitycenter.admin Org-wide threat & posture view

One subtle point: Organization Admin is structural, not all-powerful inside projects. Managing the tree doesn’t, by itself, let you read every database — you’d need data-plane roles too. GCP deliberately separates “manage the hierarchy” from “use the resources” so a platform admin isn’t implicitly a god over production data.

So set only broad, rarely-changing things at the Organization: company-wide guardrails (no public IPs, allowed regions, no SA-key creation), org-wide audit logging, and the small set of admin groups. Do not grant teams their working access here — that belongs low and narrow on folders or projects. A grant at the Org is the widest possible blast radius; touch the Org IAM policy rarely.

Inside Folders

Folders are where the hierarchy earns its keep. The beginner mistake is using none (a flat sprawl) or inventing a baroque ten-level structure nobody can navigate. The right answer is a shallow tree that mirrors how your organization actually splits responsibility and budget.

A folder groups projects (and sub-folders) that share three things: the people who should have access, the policies that should apply, and a budget/cost center. Share all three → same folder. Differ on any → a signal they belong in different folders.

Two dominant patterns, which most real orgs blend. Environment-first splits at the top on prod vs non-prod (a production folder and a non-production folder, team folders inside each) — trivial to apply strict guardrails to all of prod in one place. Team-first splits at the top on org structure (a folder per department: engineering, data, marketing, with environment sub-folders inside) — crisp per-team ownership and budgets.

Pattern Top-level split Best when Strength Watch-out
Environment-first prod / non-prod Compliance & guardrails differ sharply by environment One place to lock down all of prod Team ownership is one level deeper
Team-first per team / BU Strong team autonomy and separate budgets Ownership & cost map to org chart Applying “all prod” rules spans many folders
Hybrid (common) team → environment, or environment → team Most mid/large orgs Balances both Pick one ordering and be consistent

A worked folder example with real numbers

Take a fictional company, KloudVin Retail, with three engineering teams (Web, Mobile, Data) and a hard requirement that production is strictly governed. A clean hybrid hierarchy:

Organization: kloudvinretail.com
├── Folder: bootstrap            (seed/Terraform state, org-admin only)
├── Folder: common               (shared services: logging, networking host)
│   ├── Project: kvr-logging-prod
│   └── Project: kvr-net-host-prod      (Shared VPC host)
├── Folder: production           (Org Policy: no external IP, regions = asia-south1/2)
│   ├── Folder: web
│   │   └── Project: kvr-web-prod
│   ├── Folder: mobile
│   │   └── Project: kvr-mobile-prod
│   └── Folder: data
│       └── Project: kvr-data-prod
└── Folder: non-production       (looser policy, sandbox-friendly)
    ├── Folder: web
    │   ├── Project: kvr-web-dev
    │   └── Project: kvr-web-staging
    ├── Folder: mobile
    │   └── Project: kvr-mobile-dev
    └── Folder: data
        └── Project: kvr-data-dev

Now watch the leverage. To give the Data team access to all their data projects across environments, grant the group gcp-data-eng@kloudvinretail.com a role on the data folder under production and the one under non-production — two grants cover four projects, and any new data project dropped in either folder inherits the access automatically. To enforce “production never gets an external IP,” set one Org Policy on the production folder — it covers web, mobile, and data prod at once, including projects created next year. That’s the entire value proposition of folders in two sentences.

Goal Without folders With this folder design
Data team access to all data projects 4 separate project grants, updated on every new project 2 folder grants, auto-inherited forever
Lock down all production Re-apply policy in every prod project 1 Org Policy on production folder
Shared logging for everyone Configure per project 1 logging project under common, sink set high
Onboard a new “payments” team Create + secure each project by hand Add payments folders; projects inherit

Inside Projects

The project is the most consequential node. It’s simultaneously four things — an isolation boundary, an API surface, an IAM scope, and a billing unit. Internalize those four hats and projects stop being confusing.

Every project has three identifiers, and people mix them up constantly:

Identifier Example Mutable? Globally unique? What it’s for
Project ID kvr-web-prod No (set at creation) Yes The human-friendly key you use in gcloud, URLs, IAM
Project Number 849213776054 No Yes The immutable numeric ID services use internally
Project Name “KVR Web Prod” Yes No A display label; change it freely

The Project ID is the one that bites: globally unique across all of Google Cloud, 6–30 characters, lowercase letters/digits/hyphens, and immutable after creation. Pick a convention (<org>-<team>-<env>) and stick to it — you live with these IDs forever. An ID frees up for reuse only after a deleted project is fully purged.

Why the project boundary matters

Resources in different projects are isolated by default — a service account in kvr-web-dev can’t touch a bucket in kvr-web-prod without an explicit grant. That’s the blast-radius property: a mistake, a leaked key, or a runaway job stays contained to its project. You open specific holes (cross-project IAM, Shared VPC, VPC peering) deliberately when needed, but isolation is the default — which is what makes projects the unit of safety.

Project “hat” What it means Consequence
Isolation boundary Resources don’t cross projects by default Contains blast radius; dev can’t hit prod
API surface Each project enables its own APIs Enable compute.googleapis.com per project before using it
IAM scope Holds its own allow policy (plus inherited) Grant working access here, narrowly
Billing unit Ties to one billing account Spend aggregates here; cost reports start here

The project lifecycle and the 30-day grace period

Projects don’t vanish instantly when deleted. A deleted project enters a ~30-day recovery window (“soft-deleted”) where you can restore it, before permanent purge and ID release. That’s a safety net for fat-fingered deletes and a gotcha: you can’t immediately reuse the ID. Don’t script “delete then recreate with the same ID” expecting it to work in seconds.

Project state What it means Can you restore? Billing?
Active Normal, running n/a Yes
Deleted (soft) Scheduled for deletion, ~30-day window Yes, via gcloud projects undelete Stops accruing for most resources
Purged Permanently gone after the window No No

Enabling APIs — the per-project gotcha

A fresh project can do almost nothing until you enable the relevant APIs on it. Creating a VM means enabling compute.googleapis.com in that project first. This trips up everyone once — a gcloud command fails with “API not enabled” and the fix is a one-liner. APIs are per-project, so enabling Compute in one project does nothing for another. In a clean foundation you bake the standard API set into project-factory Terraform so every new project starts ready.

# Enable the APIs a typical web project needs, in one shot
gcloud services enable \
  compute.googleapis.com \
  storage.googleapis.com \
  sqladmin.googleapis.com \
  logging.googleapis.com \
  monitoring.googleapis.com \
  --project=kvr-web-prod

How a permission, a guardrail, and a rupee travel the tree

This is the section that makes it click. We’ll trace three things from the root down to one running VM (web-vm-01 in kvr-web-prod).

Trace 1 — a permission (IAM, additive downward). Three grants exist: on the Org, gcp-sre@ has roles/compute.viewer; on the production folder, gcp-web-eng@ has roles/compute.instanceAdmin.v1; on the project, an on-call engineer has roles/compute.osLogin. GCP walks up the VM’s ancestry and unions them: SRE can view it (Org), web-eng can manage it (folder), on-call can SSH in (project). No level reduces another — IAM only adds. The effective policy is the sum.

Trace 2 — a guardrail (Org Policy, restrictive downward). The Org sets constraints/compute.vmExternalIpAccess to deny all, and the non-production folder tries to allow external IPs for sandbox convenience. For this kind of list/boolean constraint, the parent’s restriction holds unless the constraint is explicitly configured to merge with parents — and an org-wide hard deny is enforced exactly so children can’t loosen it. A guardrail set high is a floor: children can be equal or tighter, never looser, unless you design it to allow that. (Some constraints support merging and exceptions, but the safe default is “parent’s no wins.”)

Trace 3 — a rupee (billing, aggregating upward). web-vm-01 accrues cost, which lands on kvr-web-prod and its billing account. For reporting, spend rolls up: by project, and via folders/labels, by team and environment. Money flows the opposite direction from permissions and policy — up into the reports, not down into the resources.

Thing Starts at Travels Combines by Who can override a parent?
IAM grant Any node Downward Union (additive) N/A — children only add
Org Policy Org/Folder/Project Downward Most-restrictive (default) Only if constraint allows merge/exception
Billing/cost Resource Upward Sum N/A — it’s reporting

If you remember nothing else from this article, remember this table. The three behaviors — grants add downward, guardrails restrict downward, cost sums upward — are the entire physics of GCP governance.

Architecture at a glance

Picture the hierarchy as a left-to-right pipeline: “where the rules live” feeding “where the work runs” feeding “where money and logs roll up.” Far left is the Organization — the root, holding the broadest IAM grants and the org-wide Org Policy guardrails. Those flow rightward (down the tree) into Folders, which group projects by environment and team and add folder-scoped grants and policies. Folders feed Projects — the isolation boundaries where APIs are enabled and resources live. Inside each project sit the actual Resources: a VM, a bucket, a database. Trace a permission from Org → folder → project → resource and you’ve followed the additive IAM path; trace an Org Policy along the same arrows and you’ve followed the restrictive guardrail path.

Then notice the return arrow along the bottom: billing and centralized logging aggregate back up. Spend rolls into the project and up into folders and cost centers, and a logging sink set high captures audit logs from everything beneath into a central logging project. The diagram shows this two-way flow — rules flowing down-and-right, money and telemetry flowing back up — with numbered markers on the spots beginners most often trip.

Left-to-right GCP resource hierarchy architecture: an Organization zone holding org-wide IAM and Org Policy guardrails flows into a Folders zone grouping production and non-production team folders, which flows into a Projects zone of isolated billing-bounded projects, which contains a Resources zone with a Compute Engine VM, Cloud Storage bucket and Cloud SQL database; arrows show IAM grants and Org Policy inheriting downward while billing and centralized logging aggregate back up to a logging project, with four numbered badges marking the no-Organization Gmail trap, folder-level inherited IAM, the project billing link, and the resource isolation boundary.

The shape to carry in your head: a tree you read top-down for rules and bottom-up for money. Design the tree once, and access, guardrails, and cost reporting all fall out of its shape for free.

Real-world scenario

Company: KloudVin Retail, a mid-size Indian e-commerce firm, ~120 engineers across Web, Mobile, and Data teams, running on Google Cloud with a hard PCI-adjacent requirement that production be tightly governed and auditable.

The starting mess. They began the way everyone does: a few engineers, ad-hoc projects, one shared billing account, and no Organization (bootstrapped on Gmail accounts). Eighteen months in: 47 parentless projects, IAM granted per project (one engineer had roles/owner on 31 of them because “it was easier”), no enforceable guardrails (three buckets were world-readable, found in a pen test), and finance closing each month by summing 47 billing CSVs in a spreadsheet. A security review flagged the public buckets and over-broad ownership as critical.

The redesign. The platform team stood up Cloud Identity for kloudvinretail.com, creating the Organization node and a root to govern from. They built the hybrid hierarchy shown earlier — bootstrap, common (central logging + Shared VPC host), production, and non-production folders, each with team sub-folders — and migrated the 47 orphans under the right folders with gcloud beta projects move, mapping each by environment and team.

The guardrails. On the production folder: deny external IPs (constraints/compute.vmExternalIpAccess), pin locations to asia-south1/asia-south2 (constraints/gcp.resourceLocations), and disable SA-key creation (constraints/iam.disableServiceAccountKeyCreation) to kill the leaked-key risk class. At the Organization: public-access-prevention so the world-readable-bucket incident could never recur anywhere.

The access cleanup. Blanket roles/owner grants gone, replaced by group-based folder-scoped roles: gcp-web-eng@ got instanceAdmin + storage.admin on the web folders, gcp-data-eng@ got BigQuery + storage on the data folders, on-call got narrow project access. The 31-project owner dropped to exactly what their job needed.

The outcome. Month-end billing went from a 47-CSV ritual to one console view broken down by folder and team. The next pen test found no public buckets — the Org Policy made them impossible. Onboarding a new “Payments” team became: create two folders, drop in projects, inherited IAM and policy apply automatically. The redesign took about three weeks; the governance is permanent. The hard-won lesson is this article’s thesis — the hierarchy isn’t overhead, it’s the cheapest governance you’ll ever buy, and cheapest of all before you have 47 orphan projects.

Advantages and disadvantages

The hierarchy is close to mandatory at any real scale, but it’s honest to name its costs — mostly upfront design effort and a learning curve — against its compounding benefits.

Advantages Disadvantages / costs
Set IAM once high, inherited everywhere — huge admin savings Upfront design effort; a bad early structure is annoying to reshape
Org Policy guardrails that cannot be bypassed by children Org Policy semantics (merge vs deny, exceptions) have a learning curve
Billing rolls up to teams/cost centers automatically Requires Workspace/Cloud Identity to get an Organization at all
Project boundary contains blast radius by default Cross-project work (Shared VPC, peering) needs deliberate setup
New projects inherit security posture instantly Folder depth and projects-per-org have hard limits to design within
Clear ownership mirroring the org chart Re-orging the company means re-orging folders (project moves)
Foundation for landing zones and automation Easy to over-engineer into too many folder levels

When the advantages dominate: any multi-team org, any compliance/audit requirement, anywhere finance needs per-team cost, anything you intend to scale. When the cost feels heavy: a solo developer experimenting — but even then the habit of clean Project IDs and one folder costs nothing and pays off the day a second person joins. The disadvantages are one-time or learnable; the advantages compound with every project you add.

Hands-on lab

This lab builds a minimal but real hierarchy: confirm your Organization, create two folders (production, non-production), a project in each, link billing, and set your first Org Policy guardrail. It uses only gcloud, creates no paid resources, and ends with teardown. You need an Organization (Workspace/Cloud Identity) and the roles folderCreator, projectCreator, billing.admin, and orgpolicy.policyAdmin. On a Gmail-only account the project steps work but folder/Org steps don’t — which itself demonstrates the “no Organization” reality.

Step 1 — confirm your Organization and capture its ID.

# List organizations you can see; copy the ID (a long number)
gcloud organizations list
# Save it for reuse
export ORG_ID=000000000000   # replace with your real org ID

Output: a table with DISPLAY_NAME (your domain) and ID. Empty means no Organization — you’re on a personal account, and the folder steps won’t apply.

Step 2 — create the top-level folders.

gcloud resource-manager folders create \
  --display-name="production" --organization="$ORG_ID"
gcloud resource-manager folders create \
  --display-name="non-production" --organization="$ORG_ID"

# List them and capture the production folder ID
gcloud resource-manager folders list --organization="$ORG_ID"
export PROD_FOLDER=000000000000   # replace with the production folder's ID

Output: each create returns a resource name (folders/NNN); the list shows both folders with their IDs.

Step 3 — create a project under each folder.

# Project IDs must be globally unique — add a random suffix
SUFFIX=$RANDOM
gcloud projects create "kvr-web-prod-$SUFFIX" \
  --folder="$PROD_FOLDER" --name="KVR Web Prod"

# A non-prod project (replace NONPROD_FOLDER with that folder's ID)
gcloud projects create "kvr-web-dev-$SUFFIX" \
  --folder=000000000000 --name="KVR Web Dev"
export PROJECT_ID="kvr-web-prod-$SUFFIX"

Output: “Create in progress…” then completion. The project now has the folder as its parent — verify next.

Step 4 — confirm the project’s place in the tree.

gcloud projects describe "$PROJECT_ID" \
  --format="value(projectId, parent.type, parent.id)"

Output: your project ID, folder, and the production folder’s ID — proving it lives under the folder, not at the root.

Step 5 — link a billing account.

# Find your billing account ID
gcloud billing accounts list
# Link it to the project (replace with your billing account ID)
gcloud billing projects link "$PROJECT_ID" \
  --billing-account=XXXXXX-XXXXXX-XXXXXX

Output: billingEnabled: true. The project can now create billable resources (we won’t, to stay free).

Step 6 — set your first Org Policy guardrail on the production folder.

# Deny external IP addresses for everything under the production folder
gcloud resource-manager org-policies deny \
  compute.vmExternalIpAccess all \
  --folder="$PROD_FOLDER"

# Verify the policy is in place
gcloud resource-manager org-policies describe \
  compute.vmExternalIpAccess --folder="$PROD_FOLDER"

Output: the policy described with the constraint set to deny. Any VM in any project under production now can’t get an external IP — try it in a sandbox to watch the create fail.

Step 7 — teardown. Remove what you made so nothing lingers.

# Delete the projects (enters ~30-day soft-delete; restorable)
gcloud projects delete "$PROJECT_ID" --quiet
gcloud projects delete "kvr-web-dev-$SUFFIX" --quiet

# Remove the Org Policy
gcloud resource-manager org-policies delete \
  compute.vmExternalIpAccess --folder="$PROD_FOLDER"

# Delete the folders (must be empty first)
gcloud resource-manager folders delete "$PROD_FOLDER"
# ...and the non-production folder by its ID

Output: a confirmation per deletion. The projects go to soft-delete, not instant removal — the 30-day window in action.

The same thing in Terraform

In production you build the hierarchy as code so it’s reviewable and repeatable. The equivalent in Terraform, the way a real foundation defines it:

variable "org_id"      { type = string }
variable "billing_acct" { type = string }

# Top-level folders
resource "google_folder" "production" {
  display_name = "production"
  parent       = "organizations/${var.org_id}"
}

resource "google_folder" "non_production" {
  display_name = "non-production"
  parent       = "organizations/${var.org_id}"
}

# A project under the production folder
resource "google_project" "web_prod" {
  name            = "KVR Web Prod"
  project_id      = "kvr-web-prod-7421"          # globally unique, immutable
  folder_id       = google_folder.production.id   # parented to the folder
  billing_account = var.billing_acct
}

# Enable the APIs the project needs
resource "google_project_service" "web_prod_apis" {
  for_each = toset([
    "compute.googleapis.com",
    "storage.googleapis.com",
    "logging.googleapis.com",
  ])
  project = google_project.web_prod.project_id
  service = each.value
}

# Folder-scoped IAM: grant the web team on the whole production/web area
resource "google_folder_iam_member" "web_team_admin" {
  folder = google_folder.production.id
  role   = "roles/compute.instanceAdmin.v1"
  member = "group:gcp-web-eng@kloudvinretail.com"
}

# Org Policy guardrail on the production folder: no external IPs
resource "google_folder_organization_policy" "no_external_ip" {
  folder     = google_folder.production.id
  constraint = "compute.vmExternalIpAccess"
  list_policy {
    deny { all = true }
  }
}

That’s the whole pattern in miniature: folders parented to the org, a project parented to a folder with billing attached, APIs enabled per-project, folder-level IAM (inherited by every project beneath), and a folder-level Org Policy (constraining every project beneath). Reusable project-factory modules generalize the google_project + google_project_service block so every new project is born governed — see the folder, project, and org-policy Terraform modules for production versions.

Common mistakes & troubleshooting

These are the failures that actually happen, roughly in the order beginners hit them: symptom → root cause → confirm → fix.

# Symptom Root cause How to confirm Fix
1 “I have no Organization node” Signed up with personal @gmail.com, not Workspace/Cloud Identity gcloud organizations list returns empty Set up Cloud Identity/Workspace for a domain; the Org appears automatically
2 New project can’t create a VM: “API not enabled” Compute API not enabled in that project gcloud services list --enabled --project=ID gcloud services enable compute.googleapis.com --project=ID
3 Project ID rejected at creation ID taken globally, or invalid chars/length Try a unique suffix; check 6–30 lowercase/digit/hyphen Choose a unique, convention-following ID (it’s permanent)
4 A team has access to projects they shouldn’t A broad grant (e.g. roles/owner) at Org or a high folder Check ancestry IAM: gcloud ... get-iam-policy at each level Remove the high grant; re-grant narrowly on the correct folder/project
5 Org Policy “isn’t working” — child still does the thing Constraint set at wrong node, or merges with parent gcloud resource-manager org-policies describe ... --folder/project Set at the right scope; verify effective policy on the child
6 Can’t delete a folder Folder still contains projects/sub-folders gcloud resource-manager folders list --folder=ID Move or delete contents first, then delete the folder
7 Locked out — removed our own Org Admin The only Organization Admin grant was deleted Console may still allow if you hold the role elsewhere Use the super-admin / break-glass account to re-grant; always keep a break-glass admin
8 Deleted project, ID not reusable Project is in the ~30-day soft-delete window gcloud projects list --filter='lifecycleState:DELETE_REQUESTED' Wait out the window, or undelete and rename intent; don’t script instant reuse
9 Billing detached, resources stopped Billing unlinked at project level (or account closed) gcloud billing projects describe ID shows billingEnabled:false Re-link a valid billing account to the project
10 Orphan projects with no folder Projects created at Org root, never parented gcloud projects list then check each parent gcloud beta projects move ID --folder=FID into the right folder
11 Quota error creating many projects Hit the per-org project-creation quota Console → IAM & Admin → Quotas Request a quota increase; reuse/clean up unused projects
12 Effective access confusing — “who can do this?” Forgot inherited grants from ancestors Use IAM Policy Analyzer / ancestry walk Audit at Org, folder, and project; remember IAM is additive

Two deserve emphasis. #7 (lockout) is the scariest and most avoidable — never let one user be the only Organization Admin, and keep a separate break-glass super-admin. #10 (orphans) is the most common at scale — restrict projectCreator and require new projects to land in a folder, ideally via a project factory so floating-at-root is impossible.

Best practices

Security notes

The hierarchy is a security control — arguably GCP’s most foundational — so treat its design as a security decision, not org tidiness.

Least privilege rides on the tree’s shape. Because IAM is additive and inherited, every broad grant high up multiplies across everything below. Grant the least privileged role at the lowest necessary node. A roles/viewer at the Organization quietly grants read on every resource in the company — fine for an auditor group, catastrophic for an intern. Always ask “how far down does this reach?” The answer is “everything under the node you put it on.” Deepen this in GCP IAM fundamentals: roles, service accounts and policy and IAM deny policies, conditions and impersonation chains.

Guardrails belong at the top, deny-by-default. Set Org Policy at the Organization for what must never happen anywhere: public-access-prevention on storage, iam.disableServiceAccountKeyCreation (so leaked static keys become impossible — exactly the incident class that has bitten this blog), gcp.resourceLocations for data residency, and compute.vmExternalIpAccess to keep workloads off the public internet. Children inherit these as a floor — see Org Policy guardrails on the resource hierarchy.

The project boundary is your blast-radius wall. Keep prod and non-prod in separate projects and folders so a compromised dev credential can’t reach prod data. When you must connect them, do it deliberately via Shared VPC rather than collapsing the boundary; see Shared VPC multi-project network architecture. For exfiltration-grade isolation around sensitive data, layer VPC Service Controls on top, as in VPC Service Controls perimeters and exfiltration prevention.

Protect the admins and the audit trail. Keep Organization Admin and Org Policy Admin in small groups with a break-glass fallback, enable org-wide audit logging to a locked-down central logging project under common, and prefer Workload Identity Federation over long-lived SA keys for CI/CD — see Workload Identity Federation for keyless CI/CD.

Security control Where in the tree Why there
Public-access-prevention, no SA keys, region pinning Organization (Org Policy) Must hold everywhere; deny-by-default floor
Auditor read access Org or top folder (narrow role) Broad read, but least-privileged role only
Team working access Folder / project Lowest node that covers the team’s scope
Prod/non-prod isolation Separate folders + projects Blast-radius containment
Central audit log sink High node → common logging project Captures everything beneath
Keyless CI/CD identity Project (Workload Identity Federation) No static keys to leak

Cost & sizing

The hierarchy nodes are free — Organizations, folders, and projects cost nothing to create or hold. You pay only for the resources inside projects (VMs, storage, BigQuery, egress). So the cost question isn’t “what does the tree cost” — it’s “how does the tree help you control what the resources cost.”

The mechanism is billing roll-up. Every project links to a billing account, spend aggregates at the project, and by organizing projects into folders and tagging them with labels (team, env, cost-center) you get spend sliced by exactly the dimensions finance cares about — automatically, in the console and the BigQuery billing export. A flat sprawl can’t do this cleanly; a well-shaped tree does it for free. Go deeper in GCP billing and cost management: budgets, export and discounts.

Cost lever the hierarchy enables How it works Why it saves money
Per-folder / per-team cost view Spend rolls up the tree Finance attributes cost without spreadsheets
Budgets & alerts per project/folder Set a budget on the node Catch runaway spend before the invoice
Labels for cost slicing team:, env:, cost-center: on projects Slice the billing export any way you need
Region pinning via Org Policy gcp.resourceLocations constraint Avoid surprise cross-region egress charges
Quota guardrails Org Policy + quotas Prevent accidental over-provisioning
Decommission by project Delete the whole project Clean teardown stops all its costs at once

Rough figures: the nodes are ₹0 / $0. A small always-on e2-small VM in asia-south1 runs in the low hundreds of rupees per month — trivial alone, but 47 ungoverned projects each with a forgotten e2-medium is how surprise five-figure bills happen, and the hierarchy plus per-folder budgets is exactly what surfaces that waste. The free tier covers small experimentation (e2-micro, a few GB of storage). The discipline that controls cost at scale is structural — budgets and labels on a clean tree — not penny-pinching individual resources.

Interview & exam questions

These map to the Cloud Digital Leader, Associate Cloud Engineer, and Professional Cloud Architect exams, where the resource hierarchy is foundational and recurs across IAM, security, and billing questions.

Q1. What are the four levels of the GCP resource hierarchy, top to bottom? Organization, Folders, Projects, and Resources. The Organization is the root (one per Workspace/Cloud Identity domain), folders group projects, projects are the isolation and billing boundary, and resources are the actual deployed things inside a project.

Q2. How do IAM allow policies behave through the hierarchy? They inherit downward and combine additively (union). A grant at a parent applies to all descendants, and a child can only add grants, never subtract an inherited one. Effective access on a resource is the union of bindings from the resource, its project, all ancestor folders, and the Organization.

Q3. How is Org Policy inheritance different from IAM inheritance? Both flow down the tree, but Org Policy constraints combine most-restrictively by default — a parent’s restriction is a floor a child cannot loosen (unless the constraint is explicitly configured to merge or allow exceptions). IAM is additive; Org Policy is restrictive. That difference is the crux.

Q4. Why might someone have no Organization node, and what’s the consequence? They signed up with a personal Gmail account rather than Google Workspace or Cloud Identity. The consequence: projects float as orphans with no parent, so there’s no IAM inheritance, no Org Policy, and no centralized billing roll-up. Fix by provisioning Cloud Identity/Workspace for a domain.

Q5. What makes a project the most important node? It’s a hard isolation boundary (resources don’t cross it by default), it has a globally unique immutable Project ID, it enables its own APIs, holds its own IAM scope, and links to exactly one billing account — so it’s simultaneously the unit of isolation, the API surface, the IAM scope, and the billing unit.

Q6. A team needs access to 12 projects that share an environment and owner. What’s the right move? Put those projects under a common folder and grant the team’s group the least-privileged role on that folder. Inheritance covers all 12 (and any future project added to the folder) with a single grant — far better than 12 per-project grants.

Q7. What’s the difference between Project ID, Project Number, and Project Name? Project ID is the human-friendly, globally unique, immutable key used in commands and IAM; Project Number is the immutable numeric ID services use internally; Project Name is a mutable display label. Only the Name can change after creation.

Q8. Where should you set “no public storage buckets,” and why? At the Organization, as an Org Policy constraint (public-access-prevention). It must hold everywhere as a deny-by-default floor; setting it at the root means every folder and project inherits it and no child can create a public bucket.

Q9. You deleted a project but can’t reuse its ID immediately. Why? Deleted projects enter a ~30-day soft-delete (recovery) window before permanent purge; during that window the ID isn’t released for reuse. Don’t script delete-then-recreate-with-same-ID expecting instant reuse.

Q10. How does the hierarchy help with cost management? Resource spend rolls up the tree: it aggregates at the project, and organizing projects into folders plus labeling them (team, env, cost-center) yields automatic per-team/per-environment cost breakdowns in the console and BigQuery export, plus budgets/alerts per node.

Q11. What’s the danger of granting roles/owner at the Organization? Because IAM is additive and inherited, that grant lands on every resource in the entire company — the maximum blast radius. A single leaked or misused credential with org-level owner is catastrophic. Grant low and narrow; reserve high broad roles for tiny admin groups.

Q12. How would you connect two projects that need shared networking without collapsing isolation? Use Shared VPC: a host project shares its VPC subnets with service projects, so they share networking while remaining separate projects with their own IAM and billing. Don’t merge them into one project — that would destroy the blast-radius boundary.

Quick check

  1. In the company analogy, what real GCP node is “a department,” and what node is “a private office”?
  2. If a grant exists at the Organization and a different grant exists at a project, what does the user effectively have on a resource in that project?
  3. True or false: a child folder can loosen an Org Policy deny set by its parent for a standard constraint.
  4. You have a personal @gmail.com account. Which hierarchy node do you not have, and what three capabilities does that cost you?
  5. Name the three identifiers every project has, and say which one is mutable.

Answers

  1. A folder is a department; a project is a private office. (The Organization is the company; resources are the desks/equipment inside the office.)
  2. The union of both grants — IAM is additive and inherited, so the user has every role granted at the project and every role granted at the Organization (and any folder in between).
  3. False. For standard list/boolean constraints, a parent’s restriction is a floor; a child can be equal or more restrictive, not less, unless the constraint is explicitly configured to merge or allow exceptions.
  4. You have no Organization node. That costs you IAM inheritance, Org Policy guardrails, and centralized billing roll-up — your projects float as ungoverned orphans.
  5. Project ID, Project Number, and Project Name. Only the Project Name (display label) is mutable; the ID and Number are fixed at creation.

Glossary

Next steps

GCPResource HierarchyOrganizationFoldersProjectsIAMOrg PolicyBilling
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading