The link is the artifact
You hit a deadlock in a goroutine. You paste the stack trace and fifty lines of code into a ticket. The maintainer replies asking for the missing imports and the definition of Config. You spend an hour stripping boilerplate and rewriting the reproduction case. Next time, you paste a single link. The maintainer clicks, hits run, and sees the deadlock in three seconds. The Go Playground turns code into a conversation.
The Playground is a web-based compiler and runtime hosted by the Go team. It runs your code in a sandboxed environment that blocks network access and file system writes. It captures standard output and returns it to the browser. The URL encodes the source code, so sharing a link shares the exact program. This removes environment differences from the equation. The tool also powers the interactive examples on pkg.go.dev. When you see a "Run" button next to documentation, that button uses the same mechanism.
How the sandbox works
The Playground runs on a remote server. Your browser sends the source code to the server. The server compiles the code in memory and runs the binary in a restricted container. The container captures stdout and stderr. The server returns the output to the browser. If the program panics, the Playground shows the panic trace. If the program runs too long, the server kills it after a timeout.
The URL contains the base64-encoded source. This means the code lives in the link. You can bookmark a bug. You can email a solution. The link is the artifact. The Playground also supports a "Save" button that creates a permanent link on the server. Use Save for examples you want to reference later. The short URL is stable and shareable.
Minimal example
Here's the smallest program that produces output.
package main
import "fmt"
func main() {
// fmt.Println writes to stdout. The playground captures this stream and displays it below the editor.
fmt.Println("Sandbox active")
}
The program defines a main package and a main function. This is the entry point. The fmt package provides printing functions. The playground captures the output and shows it in the results pane. If you remove the print statement, the program runs but produces no output. The playground shows a blank results pane. This is expected behavior.
Walk through the execution
The browser sends the source to the server. The server compiles the code. Compilation happens in memory. No files are written to disk. The compiler checks for errors. If you forget to import a package, the compiler rejects the program with undefined: pkg. If you import a package but don't use it, the compiler rejects the program with imported and not used. These errors appear in the output pane.
Once compilation succeeds, the server runs the binary. The runtime initializes the package. It calls main. The program executes. The container blocks network calls. The container blocks file writes. The container captures output. When the program exits, the server returns the output. If the program panics, the server returns the panic trace. If the program hangs, the server kills it after a few seconds and shows signal: killed.
Documentation examples
Documentation examples follow a strict naming convention so the tooling can extract, run, and verify them automatically. The convention uses functions named Example followed by the function or type being demonstrated. The package name must end in _test. The Output: comment tells the test runner what to expect. If the actual output doesn't match, the test fails. This keeps documentation accurate.
Here's a standard example function.
package mypkg_test
import "fmt"
// ExampleHello demonstrates the Hello function with a custom name.
func ExampleHello() {
// Call the function and print the result to match the expected output.
fmt.Println(Hello("Go"))
// Output: Hello, Go
}
func Hello(name string) string {
return fmt.Sprintf("Hello, %s", name)
}
The function ExampleHello demonstrates Hello. The package mypkg_test indicates this is a test package. The Output: comment specifies the expected output. The go test command runs this function and checks the output. If the output changes, the test fails. This prevents documentation drift.
If the output order varies, use Unordered:. The runner checks that all lines appear, regardless of order.
package mypkg_test
import "fmt"
// ExampleMapPrint shows that map iteration order is not guaranteed.
func ExampleMapPrint() {
m := map[string]int{"a": 1, "b": 2}
for k, v := range m {
fmt.Printf("%s: %d\n", k, v)
}
// Output:
// Unordered:
// a: 1
// b: 2
}
The Unordered: marker tells the runner to ignore line order. The runner verifies that both lines appear. This is useful for maps and concurrent output. The playground respects these markers when you run the code. The "Run" button executes the example and checks the output. If the check fails, the playground highlights the mismatch.
Output comments are contracts. If the output changes, the test fails.
Pitfalls and limitations
The Playground enforces strict limits. These limits protect the server and ensure fair usage. They also catch common mistakes.
Network access is blocked. Attempting to fetch a URL causes the program to hang or fail. The compiler won't catch this. The runtime will block. If you need to demonstrate HTTP code, mock the server or use httptest. The net/http package works for creating servers, but you cannot connect to external sites. The playground output will show a timeout or a connection error.
File system access is restricted. os.Open fails with a permission error. ioutil.WriteFile fails. Use strings.NewReader or bytes.Buffer to simulate I/O. This forces you to write code that works with interfaces rather than concrete files. It's a good discipline.
The playground enforces a hard timeout. Infinite loops result in a killed process. The output shows signal: killed. This prevents runaway code from consuming resources. If your code hangs, check for deadlocks or missing channel closes. The worst goroutine bug is the one that never logs.
Randomness is seeded for reproducibility. The playground seeds the random number generator. Hardcoded Output: comments work reliably. If you change the seed, the output changes. This is intentional. Examples should be deterministic.
Build tags matter. The playground runs on Linux. If your code uses //go:build windows, it won't run. This is a common trap for cross-platform code. The playground defaults to GOOS=linux. Use //go:build ignore to skip files that shouldn't run in the playground.
Convention aside: gofmt is mandatory. The playground applies gofmt before running. Your code might look different after you hit run. This is intentional. The community agrees on one formatting style. Don't fight the formatter. Let the tool decide indentation and spacing. Most editors run gofmt on save. Trust the tool.
Decision matrix
Use the Playground when you need to share a reproducible snippet without worrying about the recipient's environment. Use the Playground when you want to verify a small algorithm or syntax question instantly. Use the Playground when you are writing documentation examples that need to run on pkg.go.dev. Use local development when you need network access, file system operations, or a full build pipeline. Use local development when you are building a large application with multiple packages and dependencies. Use a CI runner when you need to validate the code against multiple Go versions or run integration tests.
The Playground is a shared workspace. Keep it clean.