# 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.

- Published: 2025-07-06
- Category: Languages
- Tags: Go
- Reading time: 3 min read
- Source: https://muhammetsafak.com/blog/how-far-can-you-go-with-gos-standard-library/
- Language: en-US
- Author: Muhammet Şafak

---
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:](/blog/writing-http-services-in-go-is-the-standard-library-enough/)** The `net/http` package covers both client and server. For a simple service, you don't need a router library at all:

```go
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 subtests (the building block of [table-driven tests](/blog/table-driven-tests-in-go/)), 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
// 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.

> **Tan:** A dependency’s cost is paid not on the day it is added but when its first security patch or version bump arrives. So the question worth asking before adding one is who will carry that upkeep. The standard library often shrinks that question to almost nothing.

## 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.
