Skip to content
Muhammet Şafak
tr
Languages 3 min read

How Far Can You Go with Go's Standard Library

How much mileage Go's rich standard library actually gives you, and a principled way to decide when to reach for an external dependency.

Cover — an indigo bearing block engraved Standard Library, threaded onto a steel shaft on a dark surface with a coupling behind it

One of the first things people notice when they start learning Go is that the standard library is unusually rich. HTTP server, JSON processing, cryptography, file system, templating, testing infrastructure — all of it available without a single third-party package.

Coming from the PHP world, this feels like a culture shock. In PHP, you can barely do anything the “modern” way without installing third-party packages first. Working without Composer is theoretically possible, but practically nobody does it. In Go, the standard library is genuinely a production-grade choice in its own right.

What the Standard Library Covers

Let’s take a quick look at what you can do with Go imports that never include github.com:

HTTP service: The net/http package covers both client and server. For a simple service, you don’t need a router library at all:

package main

import (
    "encoding/json"
    "net/http"
)

type Response struct {
    Message string `json:"message"`
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(Response{Message: "ok"})
}

func main() {
    http.HandleFunc("/health", healthHandler)
    http.ListenAndServe(":8080", nil)
}

This code is sufficient for the health-check endpoint of a production service. No extra dependencies.

JSON processing: encoding/json handles both serialization and deserialization. For large datasets or custom transformation scenarios I sometimes look elsewhere, but for standard use cases encoding/json is more than enough.

Database access: database/sql defines the interface; drivers implement it. You pull the driver package from outside, but an ORM is never required. Running raw SQL through the standard library feels completely natural.

Templating: The html/template package has XSS (Cross-Site Scripting) protection built in. For server-side HTML generation, you simply don’t need anything else.

Testing infrastructure: The testing package ships with table-driven tests, benchmarks, and fuzz testing. Go’s testing culture is largely built on top of this one package.

Where You Hit the Limits

The standard library does not cover everything, and that is a deliberate design decision. The places where I most often hit the ceiling:

Routing. The default router in net/http does not support path parameters (like :id). Go 1.22 partially addressed this by introducing a new pattern syntax:

// Go 1.22+
http.HandleFunc("GET /users/{id}", getUserHandler)

But for complex routing scenarios — especially when you need middleware chains and route grouping — I reach for packages like chi or gorilla/mux.

ORM. Writing raw SQL with database/sql gets repetitive after a while. A lightweight library like sqlx preserves the standard interface while making struct scanning much easier. The number of situations where I can get by without a heavy ORM is far greater than I expected.

Validation. There is no validation library in the standard library. go-playground/validator has effectively become the de facto standard for this need.

Logging. The log/slog package arrived in Go 1.21, and the standard library is now sufficient for structured logging. In earlier versions, zap or zerolog were practically mandatory.

The Value of Fewer Dependencies

The Go community’s “vendor everything” philosophy and its minimal-dependency culture are two sides of the same coin. Fewer dependencies means shorter build times, a smaller security-vulnerability surface, and less maintenance overhead from keeping dependencies up to date.

Before I add a package, I ask myself: can I cover this with the standard library or a few helper functions? The answer is yes more often than not. When the answer is no, I add the package — but that is a deliberate decision, not a default.

In PHP I never think about writing without Composer; the ecosystem is built that way. In Go, the standard library is not just a starting point — it is a genuine, long-lasting option. That difference has reshaped how I think about dependencies in general.

The research behind this post

Service & load Measurement

I measured PHP and Go on the same OAuth2 API: no gap at 10,000 writes, a real one at 50,000 reads

The same API verifies an OAuth2 token on every request and then writes to or reads from PostgreSQL. On four cores, how much CPU do PHP-FPM, FrankenPHP worker mode and Go need for 10,000 writes and 50,000 reads a second?

Finding

At 10,000 writes a second all three candidates hit the target in five runs out of five, and none had a p99 above 2.5 ms: at this load the language is not a capacity line item. At 50,000 reads a second only Go held the target on four cores (p99 6.45 ms); PHP-FPM stopped at 23,528 and FrankenPHP at 22,859. CPU per read request is 64 microseconds for Go, 117 for FrankenPHP and 168 for PHP-FPM. Sized by instance, 50,000 reads take 3.4 cores in Go and 8.2–8.8 cores for the two PHP candidates. FrankenPHP's CPU saving does not turn into capacity: at saturation it leaves about one of its four cores idle.

measured today

Medium confidence

Experiments on this topic

A frozen JSON envelope in place of language-specific serialization; it became BabelQueue, a polyglot queue standard.

What it does today

The frozen JSON envelope has four languages — PHP, Python, Go, Node.js — reading the same bytes, with no sidecar and no broker plugin. Teams running a polyglot queue can pick up the spec and the SDKs today.

Open source JSON Redis RabbitMQ +4 more
March 2026 — June 2026

A provider-agnostic Go CLI that has a model review my diff without the diff leaving the machine; it became CommitBrief.

What it does today

Reviews code locally, with the diff never leaving the machine; the `Provider` interface lets Anthropic, OpenAI, Gemini and Ollama plug into one contract. Signed binaries are published — anyone who does not want to hand their diff to a cloud provider can install it.

Open source Go Cobra go-git +4 more
January 2026 — April 2026
Tags: #Go
Expertise: Go Developer
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

Related Posts

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind