# golang/playground: running the Go Playground on your own machine

> This repository holds the source of the Go Playground, the web service behind go.dev/play, and it can be built and run locally as a Docker image that compiles and runs Go snippets in a sandbox. The copy on GitHub is a mirror, the canonical history lives at go.googlesource.com/playground, and the deployment path is tied to Google Cloud Build.

**golang/playground** — [mirror] The Go Playground

- Repository: https://github.com/golang/playground
- Stars: 809 · Forks: 205
- Language: Go
- License: BSD-3-Clause
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/golang-playground

## The source behind go.dev/play

The Go Playground is the web page where anyone can paste Go code and have it compiled and executed without installing anything. It runs at go.dev/play, and this repository holds its source.

Two details matter before you read any code here. First, this GitHub repository is described as a mirror. The README states that the git repository is https://go.googlesource.com/playground, and that changes should be submitted following the guidance at go.dev/doc/contribute. So the GitHub copy is a read friendly window onto the real history, and a pull request opened here is not the contribution path.

Second, the module path is golang.org/x/playground, which is the golang.org/x naming convention for experimental and sub-project repositories. The Go Reference badge in the README points at pkg.go.dev/golang.org/x/playground, so the module is importable and published even though the repository has no GitHub releases.

The service is not a single binary doing one thing. The file list shows a web frontend with an editor, a server, a separate sandbox, a snippet store, and supporting code for formatting, vetting and sharing: edit.go with edit.html, server.go, client.go, sandbox.go alongside a sandbox directory, snippetstore/, store.go, share.go, fmt.go, vet.go, metrics.go, logger.go, examples.go and txtar.go.

The audience is Go contributors, people who want to self host a small code running service, and anyone who wants to read how a language's official playground is built, since it doubles as a reference implementation of sandboxed execution.

## A web service in front of a separate sandbox process

The structure of the code shows a two part design, and understanding it explains most of the local setup steps.

The front end is the part a user touches. edit.go and edit.html are the editor page, fmt.go handles formatting the source you paste, vet.go runs the vet checks, and share.go and store.go deal with storing and sharing snippets. server.go is the HTTP service, and metrics.go and logger.go are the observability pieces, with the go.mod listing OpenCensus exporters for Prometheus and Stackdriver, Cloud Datastore and a memcache client.

The execution side is sandbox.go and the sandbox directory. The compilation itself happens in a separate process, and the Makefile shows how it is wired locally. The runlocal target creates a Docker network called sandnet, starts the playground container on it, and points the service at a second container with a --backend-url flag pointing to http://sandbox_dev.sandnet/run.

So the pattern is: the front end container receives the request and forwards the actual compile-and-run to a sandbox container that lives on a private Docker network. The two are decoupled, and the frontend does not need to know where the sandbox is beyond that URL.

The examples directory carries the sample programs a user sees on the playground page, in the txtar format the server understands, including http.txt, image.txt, multi.txt, sleep.txt, clear.txt, test.txt and min.gotip.txt. The txtar.go file implements that archive format, which is how a snippet plus its data files travel together in one request.

## Building and running the image on port 8080

The container build is a single docker command:

```bash
# build the image
docker build -t golang/playground .
```

The build is heavier than it looks. The Dockerfile does not download a Go toolchain and use it directly. It builds Go from a bootstrap version, because the playground deployment is triggered before the artifacts for the latest version of Go are published. The file defines GO_VERSION and GO_BOOTSTRAP_VERSION arguments, both defaulting to go1.22.6, and the comments explain that the bootstrap version must be one with published artifacts, such as the latest minor of the previous major Go release. The base image for that stage is debian:trixie, and the script fetches the toolchain from dl.google.com and verifies a sha256 file.

Once built, the container serves on port 8080:

```bash
docker run --name=play --rm -p 8080:8080 golang/playground &
# run some Go code
cat /path/to/code.go | go run client.go | curl -s --upload-file - localhost:8080/compile
```

The second line is the part worth internalising. The client program posts a file to the compile endpoint with curl, uploading the source from standard input, and the service answers with the compiled output. The Makefile has a make docker target that passes the build argument explicitly, resolving the latest Go version through the cmd/latestgo helper:

```bash
docker build --build-arg GO_VERSION=$(LATEST_GO) -t golang/playground .
```

If you want the development tip of Go rather than the latest release, set GOTIP=true in the environment, which is passed as -e GOTIP=true when using docker run.

## gotip, the previous release and the fake time patch

The playground is published in more than one flavour, and the repository keeps them apart through separate App Engine configuration files: app.yaml for the main deployment, app.goprev.yaml for the previous Go release, and app.gotip.yaml for the development build.

The GOTIP=true environment variable is the switch that selects the development version. The same mechanism appears on the deployment side, where deploy/deploy_gotip.json is used instead of deploy/deploy.json when submitting a build for the tip of Go. The Makefile also documents a scheduled job for that variant, with a warning that deploy/gotip_schedule.yaml must be managed manually with gcloud rather than through the trigger import targets.

Two files in the tree hint at how the sandbox handles time. There is an enable-fake-time.patch and a fake_fs.lst, and the Dockerfile comment mentions building a faketime standard library alongside Go itself. The mechanism appears to be that the standard library is patched so that time-related calls behave predictably inside the sandbox, which is the sort of thing you need when a submitted program could otherwise sleep forever or read the wall clock in ways that make results inconsistent.

The example file min.gotip.txt is the minimal program used to check that a tip build works, alongside examples/test.txt. If you are running the tip locally, comparing against the release build is the quickest way to see whether a behaviour difference comes from your code or from the compiler version.

## Deployment through Cloud Build and the timeout you have to raise

The production deployment path is Google Cloud Build, and releases are triggered automatically when new Go repository tags are pushed to GitHub, or when master is pushed on the playground repository. The trigger definitions live in deploy/go_trigger.yaml, deploy/playground_trigger.yaml and deploy/deploy.json, with the configuration mirrored in the GCP UI. The README warns that changes to the trigger configuration can be made in the YAML files or in the GCP UI, and that the two should be kept in sync using the push-cloudbuild-triggers and pull-cloudbuild-triggers make targets.

Submitting a build is one command:

```bash
gcloud --project=golang-org builds submit --config deploy/deploy.json .
```

The Cloud Build configuration always builds and deploys with the latest supported release of Go, and deploy/deploy_gotip.json is the variant used for the development build.

There is one operational gotcha that the README calls out directly. Building the playground Docker container takes more than the default 10 minute limit of Cloud Build, so the timeout has to be increased first, and app/cloud_build_timeout is a global configuration value:

```bash
gcloud config set app/cloud_build_timeout 1200  # 20 mins
```

Alternatively you can skip Cloud Build, build locally and push the image yourself, then deploy with an explicit image URL:

```bash
make docker
docker tag golang/playground:latest gcr.io/golang-org/playground:latest
docker push gcr.io/golang-org/playground:latest
gcloud --project=golang-org --account=you@google.com app deploy app.yaml --image-url=gcr.io/golang-org/playground:latest
```

Once the image is in place, the ordinary deploy follows:

```bash
gcloud --project=golang-org --account=you@google.com app deploy app.yaml
```

The snippet store is a separate deployment with its own configuration file, deploy/deploy_snippetstore.json, submitted through a deploy-snippetstore make target.

## Where the playground approach stops working

Several limits are visible in the repository itself.

The service is bound to Google Cloud. Deployment runs through Cloud Build and App Engine, the configuration references the golang-org project, the datastore and memcache clients are baked in, and the metrics exporters target Prometheus and Stackdriver. Self hosting the container on your own machine works, but reproducing the production environment means reproducing a good deal of Google Cloud around it.

Building the image is also slow by design, since it compiles a Go toolchain from a bootstrap source rather than pulling a binary. That cost is the price of being able to build a Go release before its artifacts are published, and it is the reason the Cloud Build timeout needs raising.

The test layout has a gap worth noting. The Makefile separates test_go, which runs go test against the code, from test_gvisor, which starts a sandbox container. A comment states that test_gvisor is not included in test yet, because it requires running a separate server first, and the runlocal target in the sandbox directory provides that. So the default make test does not exercise the sandbox path, which is where the interesting behaviour lives.

The sandbox is the real question for anyone considering reuse. The name suggests a constrained environment, and there is a separate sandbox directory with its own Docker network and backend URL, but the README does not document the isolation guarantees, the resource limits applied to user programs, or the network policy inside the sandbox. Anyone planning to run untrusted code through this service needs to read that code rather than assume the guarantees.

## Licence, maintenance and what the mirror means for contributors

The code is under a BSD-style licence, and the repository includes both a LICENSE file and a PATENTS file, which is the pattern the Go project uses. The Dockerfile header states the copyright is held by The Go Authors and that use is governed by the BSD-style licence in the LICENSE file.

The module metadata shows Go 1.26.0 in go.mod, and the dependency list includes golang.org/x/build for the toolchain pieces, golang.org/x/tools with the deprecated godoc module, x/mod, the App Engine packages, and the Google API client. The build system pins a bootstrap Go version of go1.22.6 in the Dockerfile arguments, which is the minimum the toolchain needs in order to build a newer release.

On maintenance, the repository is not archived and the last push was on 2026-10-12, with no GitHub releases at all, since releases are cut as Go tags and deployed by the trigger pipeline rather than published as GitHub release artefacts.

For contributors, the README is explicit: submit changes following https://go.dev/doc/contribute, and note that the git repository is https://go.googlesource.com/playground. The codereview.cfg file in the tree is the Gerrit review configuration, which is the mechanism that project uses. Working in the mirror is fine for reading, but a change that matters has to go through that review system, and a fork of the mirror on GitHub is not the way to submit one.

## Conclusion

Adopt this repository if you want to run the Go Playground yourself, for an internal documentation site, an offline training environment, or to inspect how a sandboxed compile service is put together. Do not adopt it as a general code execution backend for untrusted programs without reading the sandbox implementation, and do not expect the GitHub copy to be the place to contribute, since the canonical repository is at go.googlesource.com/playground. Before you start, build the image with docker build -t golang/playground ., raise the Cloud Build timeout if you plan to deploy to App Engine, and check whether you need the gotip variant, which is selected with the GOTIP=true environment variable.

## FAQ

### How do I build and run the Go Playground locally?

Build the image with docker build -t golang/playground . and then start it with docker run --name=play --rm -p 8080:8080 golang/playground. You can post code to it with cat /path/to/code.go | go run client.go | curl -s --upload-file - localhost:8080/compile.

### How do I run the gotip version of the Go Playground?

Set GOTIP=true in the environment, passing it as -e GOTIP=true when using docker run. On the deployment side the same variant is selected by submitting deploy/deploy_gotip.json instead of deploy/deploy.json.

### Why does the Cloud Build deployment time out when building the playground image?

The container build compiles a Go toolchain from a bootstrap version rather than downloading a published one, which takes longer than the default 10 minute Cloud Build limit. The README says to raise the global timeout first with gcloud config set app/cloud_build_timeout 1200.

### Where should I send a change to the Go Playground source?

The README points to https://go.dev/doc/contribute for the process, and states that the git repository is https://go.googlesource.com/playground. The GitHub copy is a mirror, and the codereview.cfg file in the tree is the review configuration for that setup.

### What licence applies to the Go Playground source?

The repository is BSD-3-Clause licensed, with a LICENSE file and a PATENTS file at the top level, and the Dockerfile header states the copyright is held by The Go Authors under that BSD-style licence.

## Sources

- [golang/playground on GitHub](https://github.com/golang/playground)
- [Issues](https://github.com/golang/playground/issues)
- [License: BSD-3-Clause](https://github.com/golang/playground/blob/master/LICENSE)
- [README](https://github.com/golang/playground/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/golang-playground
