Skip to content
Muhammet Şafak
tr
Languages 3 min read

How Far Can You Go with Go's Standard Library

A hands-on look at just how much mileage Go's rich standard library gives you, and a principled approach to deciding when to reach for an external dependency.


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.

Tags: #Go
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