Developer-experience study · firsthand execution · 26 July 2026

Deploy a website with Cloud Run

One Google Codelab. Nine steps. Two personas. Three isolated projects. Every command run exactly as printed.

The codelab under test codelabs.developers.google.com/codelabs/cloud-run-deploy

Disclaimer. This study is itself an experiment: using AI to evaluate a developer resource, with the AI doing the work at every level — running the codelab, analysing the results, and drafting both this deck and the accompanying article. Every command, timestamp, and error message here is real, reproducible, and published alongside the raw logs. Read what follows as a documented starting point that invites further testing — and with a healthy grain of salt.

View Overview ↗

Cloud Run codelab · DX study01/20

Two developers, same nine steps.

Both are competent. The difference is not ability — it is how much of Google Cloud they already carry in their head before step 1.

A

Sam

Persona A · new to Google Cloud

  • 6 years shipping product in Node and TypeScript
  • Deploys on Vercel and Render; knows Docker through docker-compose
  • Has never opened the Google Cloud console
  • Found this codelab searching “deploy a container to Google Cloud”

Mental model “A deploy is a git push.”

Wants something live, and to know what it will cost.

How they ran it Cloud Shell, exactly as the page instructs.

B

Alex

Persona B · experienced with Google Cloud

  • 9 years in platform and infrastructure
  • Runs Cloud Run and GKE in production; fluent in IAM, Cloud Build, Artifact Registry
  • Works locally; avoids Cloud Shell by preference
  • Opened this codelab to decide whether to hand it to new hires

Mental model Already holds every primitive the codelab introduces.

Wants to find where it breaks before their team does.

How they ran it local gcloud — the way they actually work.

These are analytical constructs used to structure the run, not researched user archetypes. Persona A was executed by a separate, smaller model under a written clean-room protocol; Persona B by the analyst firsthand. Both ran in separate projects, so neither could clear a step for the other.

Cloud Run codelab · DX study02/20

The codelab is accurate about everything except what happens when something goes wrong.

And something goes wrong for both personas — at the same step, for the same reason, with two different error messages. The newcomer got the less informative one.

1

A new project cannot reliably run step 4. The error names a permission the account already has.

2

The cleanup step reports success while leaving 356 MB billing in Artifact Registry.

3

The codelab is written for Cloud Shell and silently punishes anyone working locally.

Cloud Run codelab · DX study03/20

Both finished. One took five times longer and absorbed eleven times more.

Persona APersona Bratio
Time to complete30m 26s6m 04s5.0×
Steps completed9 / 99 / 9
Blocks hit14
Needed outside helpyesno
Concepts to absorb56511.2×

Why did Persona B hit four times more blocks and still finish five times faster?

1

Every block was already in their head. A hardcoded Cloud Shell path, an empty environment variable, a width-dependent awk — Alex has debugged all three shapes before. Recognition, not discovery.

2

They never had to leave the terminal. No searching, no reading, no deciding whether the tutorial or their setup was wrong. Measured recoveries: 19s, 34s, 43s.

3

A block only stops you if you can't name it. Sam hit one block and stopped dead, because the error named a permission they had no way to evaluate.

Block count measures how often the codelab breaks. It does not measure difficulty. What separates these two columns is not how often they got stuck — it is whether being stuck meant anything.

Cloud Run codelab · DX study04/20

Persona B never has to understand anything. Persona A never gets a clean step.

WALLTRAPGRINDCLEAN0s100s200s300s400s04812TIME COST (seconds, measured)COGNITIVE LOAD (new concepts)123456789123456789
Persona APersona B numbers are codelab steps · thresholds: 120s, 4 concepts
Cloud Run codelab · DX study05/20

The friendliest page is the steepest cliff.

Step 1 asks the reader to do nothing at all. It is cleared in 25 seconds — and it delivers 12 undefined concepts, the largest single block in the codelab.

Knative. Cloud Build. Container Registry. Cloud Shell. gcr.io. Scale-to-zero. Containerization. Project-owner role. The stated prerequisite is “general familiarity with Docker” and nothing else.

Persona A carries all twelve into every step that follows.

Persona B reads it in 12 seconds and holds none of it as new.

Codelab step 1, Before you begin
Step 1 as captured, 26 July 2026. Zero actions requested; twelve concepts introduced.
Cloud Run codelab · DX study06/20

The codelab asks for one thing and assumes fifty-one more.

What the codelab says you need

“General familiarity with Docker.”

That is the complete prerequisites section. Nothing else is asked for.

What it actually uses without explaining

KnativeCloud BuildContainer Registrygcr.io Artifact RegistryCloud Shellproject IDbilling account regionzoneimage tagrevisionconcurrency service accountIAM rolescale to zerounauthenticated invocations Cloud Storage bucketenabling an APIPodsservice URL +31 more

51 of 56 concepts are used with no explanation. One is actually defined (project ID). Four are partly explained.

A codelab may fairly assume prerequisites — but only the ones it declares. Under its own stated contract every term above is in scope. For Sam each is a lookup or a guess; for Alex each is free. Counted from the page before either run, so the count cannot have been shaped by knowing what broke. A hyperlink to another doc was not counted as an explanation.

Cloud Run codelab · DX study07/20

Both personas failed the same command. Only one was told why.

PERSONA A · Cloud Shell

transcript replay — not a screen recording
  1. 0:02no permission named
  2. 0:02no resource named
  3. 0:03no troubleshooter link
  4. 1:48declared BLOCKED, stopped

PERSONA B · local gcloud

transcript replay — not a screen recording
  1. 0:02names the exact permission
  2. 0:02names the principal
  3. 0:03names the resource + link
  4. 1:44self-recovered

Identical underlying condition. The newcomer, in the environment the codelab prescribes, received strictly less information than the expert who needed it least.

Cloud Run codelab · DX study08/20

The obvious conclusion was wrong. A controlled probe caught it.

“The codelab omits an IAM step” is what this study nearly published. The tell: the failing service account already held roles/editor, which already grants the permission the error named.

  1. 18:46:52third independent project created
  2. 18:47:35attempt 1 — FAILED, iam.serviceAccounts.get denied
  3. no IAM changes whatsoever
  4. 18:52:20attempt 2 — SUCCESS, 24s build
  5. 18:52:51service account still holds exactly roles/editor

Two projects reproduced it on different permissionsstorage.objects.get and iam.serviceAccounts.get. A missing role fails identically every time. Eventual consistency does not.

Cloud Run codelab · DX study09/20

The error tells you to fix IAM. The fix is to wait.

Persona A

Takes it at face value. Cannot fix IAM, or does not know how. Concludes the codelab is broken, or that they lack access.

Plausible abandonment point

Persona B

Knows how to grant roles. Grants three. Next attempt succeeds. Draws a false causal conclusion and writes it into a runbook.

Silent, and it scales

This study's analyst made exactly the second error, and caught it only because a pre-existing roles/editor binding happened to be visible in the output.

Cloud Run codelab · DX study10/20

Clean up reports success and leaves 356 MB billing.

Annotated codelab cleanup step
Step 9 as published. 1 image deletes work. 2 a note concedes leftover source. 3 this one-liner fails in Cloud Shell. 4 service delete works.
Audit after all four cleanup commands
Cloud Run servicedeleted
Container image tagsdeleted
Artifact Registry repo356.162 MB
Orphaned source tarball1.5 MB
Enabled APIs29
Projectnever mentioned

Repository updateTime is after both deletions — this is not stale metadata. Deleting the tags did not reclaim the layers.

Cloud Run codelab · DX study11/20

The cleanup command fails in the environment the codelab tells you to use.

Persona B, wide local terminal: worked, deleted two objects. Persona A, Cloud Shell: failed 11 times, deleted nothing.

1 {print $4}' | while read line; do gsutil rm $line; done", "k": "cmd"}, {"t": 0.8, "s": "CommandException: The rm command (without -I) expects at least one URL.", "k": "err"}, {"t": 1.1, "s": "CommandException: The rm command (without -I) expects at least one URL.", "k": "err"}, {"t": 1.4, "s": "CommandException: The rm command (without -I) expects at least one URL.", "k": "err"}, {"t": 1.7, "s": " ... repeated 11 times, once per build. Zero objects deleted.", "k": "note"}]'>
transcript replay — not a screen recording
  1. 0:00run exactly as printed
  2. 0:01gsutil receives an empty string
  3. 0:02one failure per build, 11 total
  4. codelab narrative implies this cannot fail

Cause, found by Persona A using the codelab's own commented-out diagnostic line: in Cloud Shell's narrow pane gcloud builds list renders one line per field, not per build. awk '{print $4}' reads column 4 of a table that isn't there. The command is terminal-width dependent.

Cloud Run codelab · DX study12/20

What the newcomer believed they were leaving behind.

“some small ongoing Cloud Storage charge (a handful of MB of tarballs from two builds) is the only likely leftover”

Persona A log, written before any audit
actual

356 MB Artifact Registry

1.5 MB unreachable orphan

29 APIs still enabled

1 project, never mentioned

Wrong by roughly two orders of magnitude, in the direction that costs money. A confident, incorrect mental model scores zero on both measurement axes — and is arguably the worst outcome in the study.

Cloud Run codelab · DX study13/20

One missing variable, one deeply misleading error.

${GOOGLE_CLOUD_PROJECT} is injected by Cloud Shell. On a local machine it is empty. The shell does not warn.

// as printed in the codelab
gcloud run deploy --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 --platform managed

// what the shell actually sends
gcloud run deploy --image=gcr.io//monolith:1.0.0 --platform managed

// what Google Cloud says back
Permission "artifactregistry.repositories.downloadArtifacts" denied on resource
"projects/monolith/locations/us/repositories/gcr.io" (or it may not exist)

The collapsed path parses monolith as the project name. The error blames your account for a project you never created, never mentions the variable, and hedges with “or it may not exist.” There is no path from this message to the cause.

Cloud Run codelab · DX study14/20

Documentation drift, visible on the page.

Annotated codelab step 5
Step 5 as published, captured 26 July 2026 from a page dated 20 March 2026.
Page showsReality
1 ${GOOGLE_CLOUD_PROJECT}Cloud Shell only
2 5 regions listed44, alphabetical, no default
3 “Pod status”Cloud Run has no Pods
4 output dated 2019
5 **Note:**markdown renders literally

The page says “select the region closest to you.” The prompt offers 44 alphabetical entries with no default, no latency hint and no geolocation. Concept-count scores this zero load — “region” was already introduced — which is precisely the metric's blind spot.

Cloud Run codelab · DX study15/20

What the codelab gets right.

  • Zero-downtime deploy genuinely works. 9 seconds, HTTP 200 throughout, three revisions retained. A real platform strength, taught honestly.
  • gcloud run deploy self-heals. The Cloud Run API is never enabled by any instruction — the deploy command detects and enables it, rescuing both personas silently.
  • The time estimate is honest. Advertised 39 min; Persona A took 30m adjusted, 40m raw. Most tutorials' estimates are fiction.
  • A 2019 React app built clean on Node 26. No legacy-OpenSSL failure, which was a plausible risk.
  • Concurrency and revisions are taught well — fastest step for both personas, a differentiated capability in one flag.
Fancy Store running via Cloud Shell Web Preview
Step 3 Web Preview, captured live. The codelab delivers a working app — this part is not in doubt.
Cloud Run codelab · DX study16/20

Nine recommendations. Five are trivial text edits.

#RecommendationOwnerEffort
R1Auto-retry or explain transient permission failures on new projectsCloud Build / gcloudMedium
R2Bring Cloud Shell error verbosity to parity with local gcloudCloud ShellMedium
R3Replace awk-scraping cleanup with --format="value(…)"CodelabTrivial
R4Add Artifact Registry deletion; state the true end stateCodelabTrivial
R5Recommend project deletion as terminal cleanupCodelabTrivial
R6Use $(gcloud config get-value project)CodelabTrivial
R7Fix or remove setup.sh's local branchSample repoLow
R8Mark a default region, or order by latencygcloudMedium
R9Re-capture 2019-era examples; remove Pod statusCodelabLow

The two requiring real product work — R1 and R2 — are also the two that decide whether a newcomer finishes or abandons.

Cloud Run codelab · DX study17/20

What this study does not establish.

  • Persona A is a smaller model, not a human. Better than one operator narrating both sides. Not a substitute for a study with human participants. Its timings are measurements of a model following a protocol.
  • Sample of one run per persona. Two projects, one account, one afternoon, no Organization. Enterprise IAM would change several findings.
  • The propagation window was not bisected. “3–5 minutes” is bounded by observation, not measured.
  • One pre-registered hypothesis was wrong. This study predicted gcr.io and --platform managed would be stale. Both still work. Recorded as a miss.
  • No screen recordings exist. Recording required photographing a browser window on a macOS Space the tooling could not reach without Accessibility permission. The replays in this deck are built from real captured output and real measured timings, and are labelled as replays — not presented as recordings, and not re-enacted after the fact.
  • An entire screenshot set was discarded. 10 of 11 Persona A captures photographed the wrong tab and were quarantined, not published. Documented rather than quietly dropped.
Cloud Run codelab · DX study18/20
Cloud Run codelab · DX study19/20

The codelab does not need to be rewritten. It needs to be honest about failure.

Every step works when nothing goes wrong. Both personas reached a live, public, zero-downtime deployment. The gap is entirely in what the product says when it breaks — and in what the reader is left believing they still owe.

5

trivial text edits remove most of the friction

2

product changes decide whether a newcomer finishes

356MB

still billing after “clean up” succeeds