# 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://www.muhammetsafak.com.tr/en/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:](/en/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 [table-driven tests](/en/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.

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