# cloud-run-button: one-click deploys to Cloud Run from a README badge

> The Cloud Run Button takes a repository URL, builds the container through Docker, Jib or buildpacks, and creates a Cloud Run service in the deployer's own project, with app.json in the repository controlling the service name, environment variables and deployment options. It only works for a public repository.

**GoogleCloudPlatform/cloud-run-button** — Let anyone deploy your GitHub repos to Google Cloud Run with a single click

- Repository: https://github.com/GoogleCloudPlatform/cloud-run-button
- Website: https://cloud.run
- Stars: 553 · Forks: 98
- Language: Go
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/googlecloudplatform-cloud-run-button

## The deploy runs in the reader's project, not yours

If you have a public repository, you can add a button to your README.md and let anyone deploy your application to Google Cloud Run with a single click. The homepage is https://cloud.run.

The mechanic is the part that matters and it is easy to misread. The click does not deploy into a hosting project that you own and pay for. It opens a flow that runs in the account of whoever clicked, and the resulting service, container image and cost all land in that person's Google Cloud project. That is what makes the model work for a public repository: there is no shared quota, no shared bill and no shared abuse surface, because the deployer is spending their own money on their own service.

It also explains the restriction to public repositories. There is no way to hand a private repository to a stranger's click without exposing it, so the button only applies where the source is already visible to everyone.

The implementation is Go, the licence is Apache-2.0, the default branch is master, and the last push was on 2026-07-10. The repository has no GitHub releases, which fits a project whose deliverable is a hosted deployment flow rather than a library. The tree shows cmd/ for the command, hack/ and tests/ for the development tooling, a Dockerfile, and the cloudbuild.yaml, cloudbuild-redirector.yaml and integration.cloudbuild.yaml files that drive the build and integration test pipelines.

## Three build strategies, decided by what is in the repository

The build step is where most of the surprising behaviour lives, and the rule is based entirely on what the repository contains.

If the repo contains a Dockerfile, it will be built using the docker build command. If the repo uses Maven for the build and it contains the Jib plugin, then the container image will be built with Jib. Otherwise, CNCF Buildpacks, meaning the pack build command, will attempt to build the repo.

The fallback ordering matters. A Dockerfile wins if there is one, which means a repository that happens to carry a Dockerfile for its tests will use Docker even if the author would have preferred Jib. Otherwise the Jib path catches Maven projects that opted into the plugin. The buildpack path is the general case, and it is the one most likely to fail on an unusual project layout.

And there is an escape hatch. You can skip these built-in build methods using the build.skip field and use a prebuild or postbuild hook to build the container image yourself. That is the right answer for a project whose build needs something the three standard paths cannot express, and it moves the complexity from the platform's build logic into a script you control.

The Dockerfile in the repository root shows how the deployer itself is built, which is a different thing from how a user's repository is built.

```dockerfile
FROM golang:1.26-alpine AS build
RUN apk add --no-cache git
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' \
        -o /bin/a.out ./cmd/cloudshell_open
```

The go.mod names the module github.com/GoogleCloudPlatform/cloud-run-button and the dependencies are the Google Cloud client libraries plus the API and gRPC packages, with the Artifact Registry client and the compute metadata package, and a survey library and a spinner for the interactive prompts, which are the parts of the flow where a person is asked to choose things.

## The query parameters that pick the source

How the button knows what to build is a small set of query parameters, and the default behaviour is worth understanding because it affects how you link to it.

When no parameters are passed, the referer is used to detect the git repo and branch. That is how the plain badge in the README works: the page you arrived from tells the deploy flow which repository to clone.

To specify a git repo, add a git_repo=URL query parameter. To specify a git branch, add a revision=BRANCH_NAME query parameter. To run the build in a subdirectory of the repo, add a dir=SUBDIR query parameter.

So the badge in the README is deliberately minimal, and the flexibility is in the link target. If your application lives in a subdirectory of a monorepo, the dir parameter is how you say so. If you want people to deploy a specific branch rather than the default one, that is what revision is for, and pinning to a tag or a branch is a better habit than letting a deploy pick up whatever the default branch happens to be that day.

The example in the project documentation shows the full form of the link, with the git_repo parameter pointing at the repository URL and the deploy endpoint at deploy.cloud.run.

```text
    [![Run on Google Cloud](https://deploy.cloud.run/button.svg)](https://deploy.cloud.run)
```

The main README instruction is to copy and paste that markdown into your own README, and the project also links a hello, world Go application you can try the flow against before adding the badge to anything real.

## app.json is the deployment contract

The configuration for a deployment lives in a file called app.json at the root of the repository, and it is the counterpart of the button.

If you include an app.json at the root of your repository, it allows you to customize the experience such as defining an alternative service name, or prompting for additional environment variables. A fully populated app.json file looks like this.

```json
{
    "name": "foo-app",
    "env": {
        "BACKGROUND_COLOR": {
            "description": "specify a css color",
            "value": "#fefefe",
            "required": false
        },
        "TITLE": {
            "description": "title for your site"
        },
        "APP_SECRET": {
            "generator": "secret"
        },
        "ORDERED_ENV": {
            "description": "control the order env variables are prompted",
            "order": 100
        }
    },
    "options": {
        "allow-unauthenticated": false,
        "memory": "512Mi",
        "cpu": "1",
        "port": 80,
        "http2": false,
        "concurrency": 80,
        "max-instances": 10
    },
    "build": {
        "skip": false,
        "buildpacks": {
            "builder": "some/builderimage"
        }
    }
}
```

The reference for the fields is detailed enough to use without guessing. The name field is optional with a default of the repo name, or the sub-directory name if specified, and it is the name of the Cloud Run service and the built container image, not validated for naming restrictions. The env field prompts the user for environment variables, where description is a short explanation that should be short enough to fit into a line, value is a string default, required defaults to true, generator currently supports only secret, and order controls the order in which variables are prompted, with the unspecified ones prompted last.

The options field covers the service itself: allow-unauthenticated defaults to true, memory and cpu are per instance, port is for applications that do not respect the PORT environment variable Cloud Run provides, http2 selects the connection protocol, concurrency is concurrent requests per instance, and max-instances is the autoscaling limit with a maximum of 1000.

## Hooks, and the environment the commands run in

The hooks section is the extension point, and it is where the flow can be adapted without giving up the button.

The four hooks are prebuild, postbuild, precreate and postcreate, each with a commands array of strings, and each runs in a separate bash shell with the environment variables configured for the application.

Those environment variables are named in the documentation: GOOGLE_CLOUD_PROJECT for the Google Cloud project, GOOGLE_CLOUD_REGION for the selected region, K_SERVICE for the Cloud Run service name, IMAGE_URL for the container image URL and APP_DIR for the application directory. Command outputs are shown as they are executed.

The ordering gives each hook a distinct job. prebuild runs before the built-in build methods, and the documentation says to use the IMAGE_URL environment variable to determine the container image name you need to build, which is the crucial detail: a prebuild hook that builds the image has to know what to call it, and IMAGE_URL is where that name comes from. postbuild runs after the built-in build methods, and it uses IMAGE_URL for the same reason. precreate runs before the service has been created. postcreate runs after the service has been created, and the SERVICE_URL environment variable provides the URL of the deployed Cloud Run service.

The build section interacts with the hooks as well. The skip field, defaulting to false, skips the built-in build methods, which are docker build, Maven Jib and buildpacks, but still allows the prebuild and postbuild hooks to be run in order to build the container image manually. The buildpacks field can point at a different builder image, defaulting to gcr.io/buildpacks/builder:v1, and additional buildpack configuration can be specified using a project.toml file.

The build field in the example file also shows a builder value of some/builderimage, which is a placeholder in the sample rather than a working image, so treat the example as a shape and not a configuration to copy.

## Where the one-click flow stops working

There are three limits, and the first one is a consequence of the design rather than a gap in it.

The first is that the deployed thing is one container on Cloud Run. There is no database, no queue, no persistent volume and no multi-service topology in this flow. A repository whose application needs a relational database will deploy and then fail at runtime, and no amount of app.json changes that. The options field lets you set memory, cpu, port, concurrency and autoscaling limits, which is a container's worth of configuration and not a stack's.

The second is that the build must succeed unattended. The three built-in strategies cover a Dockerfile, a Maven project with Jib, and anything buildpacks can handle. A project with an unusual build, a code generation step, or a dependency the builder image does not have, needs the build.skip path and its own prebuild script. That is more work than it sounds, because the script now runs inside the platform's environment.

The third is the audience. The flow asks a person questions in a browser, which is exactly right for the reader of a public README and exactly wrong for a team deploying its own service. For internal use, a CI pipeline driving Cloud Run deployment directly is a better fit, and app.json does not help there because there is no person to prompt.

On the alternative, the honest comparison is with the gcloud CLI and the Cloud Build and Cloud Run APIs, which give a team a reproducible, scriptable deployment with the same underlying primitives. The button exists to serve the case where the deployer is a stranger who will never read a document, and for that case a CLI is not a substitute, because a stranger will not run a CLI.

The licence is Apache-2.0, and the module path in go.mod is github.com/GoogleCloudPlatform/cloud-run-button with the Go version at 1.26.2.

## Conclusion

Adopt cloud-run-button if you publish a public repository and want readers to deploy it to Cloud Run themselves in a click, since it removes the whole build and deploy setup from the reader's side. Do not adopt it for a private repository or for a service that needs infrastructure beyond one container. Before you add the badge, check that the repository builds with a Dockerfile, a Jib plugin or a buildpack, and note the last push was on 2026-07-10 with no GitHub releases to track.

## FAQ

### How do I add the Cloud Run Button to my repository?

Copy and paste the markdown into your README. The button links to deploy.cloud.run, and the deployment runs in the Google Cloud project of whoever clicks it, so it is intended for a public repository.

### How does the Cloud Run Button decide how to build my repository?

If the repo contains a Dockerfile it is built with docker build, if it uses Maven and contains the Jib plugin the image is built with Jib, and otherwise CNCF buildpacks attempt the build. You can skip all three with build.skip and build the image yourself in a prebuild hook.

### What can I configure with app.json in a Cloud Run Button repository?

The name of the service and image, environment variables to prompt for with their descriptions, defaults, required flags, secret generators and prompt order, deployment options such as allow-unauthenticated, memory, cpu, port, http2, concurrency and max-instances, the build configuration, and prebuild, postbuild, precreate and postcreate hooks.

### Which git parameters does the Cloud Run Button accept?

git_repo=URL to specify a repository, revision=BRANCH_NAME to specify a branch, and dir=SUBDIR to build from a subdirectory of the repository. With no parameters the referer is used to detect the repo and branch.

### Which environment variables are available to the app.json hooks?

The hooks run in separate bash shells with GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_REGION, K_SERVICE, IMAGE_URL and APP_DIR set, and postcreate additionally has SERVICE_URL giving the URL of the deployed service.

## Sources

- [GoogleCloudPlatform/cloud-run-button on GitHub](https://github.com/GoogleCloudPlatform/cloud-run-button)
- [Issues](https://github.com/GoogleCloudPlatform/cloud-run-button/issues)
- [License: Apache-2.0](https://github.com/GoogleCloudPlatform/cloud-run-button/blob/master/LICENSE)
- [Project website](https://cloud.run)
- [README](https://github.com/GoogleCloudPlatform/cloud-run-button/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/googlecloudplatform-cloud-run-button
