Production-ready UUID utility

UUID v4 in Go (Golang) – How to Generate and Use in APIs

Generate UUID v4 in Go with practical examples for APIs, background jobs, and production services.

Used by developers worldwide
Trusted for APIs, databases, and distributed systems
Millions of UUIDs generated daily
Generator
Interactive identifier tool
Live preview
Generated output
Explanation

Using UUID V4 in Go

This guide shows how to generate UUID v4 in Go (Golang) with practical examples for the common case developers care about most: random identifiers generated in application code. It shows the native API usage, the way teams use v4 in APIs and backend flows, and the trade-offs that start to matter once the ID also becomes a database key.

Examples

UUID V4 Example

Three sample UUID V4 values you can use in documentation, tests, and placeholders.

550e8400-e29b-41d4-a716-446655440000
16fd2706-8baf-433b-82eb-8c7fada847da
9b2c9f8e-1c4d-4f6a-9b3e-8d7c6b5a4f21
Code examples

Language-specific snippets

Use cases i

Popular UUID V4 use cases in Go

V4

API resource IDs in Gin and Fiber

For route params, response payloads, and externally visible records, UUID V4 makes sense when the application needs to own ID creation. Teams usually pick it here for simple generation across any service boundary, even though records are unique but not naturally sortable.

V4

Model and persistence identifiers

At the model layer, UUID V4 works well when records are created across services or workers and the database should not be the only source of identity. That is especially true for public IDs, request IDs, and cross-service references, where simple generation across any service boundary matters.

V4

Jobs, messages, and event payloads

In asynchronous Go processing, teams often put UUID V4 on messages and jobs so one unit of work keeps the same identity everywhere it appears. This pattern fits public IDs, request IDs, and cross-service references, especially because of fully random values.

V4

Service boundaries and internal references

When one entity is touched by several Go services, UUID V4 gives each layer the same durable reference instead of service-local IDs. In practice, that choice is popular where records are unique but not naturally sortable, but the operational benefit is simple generation across any service boundary.

FAQ

Helpful answers for developers

Why do teams reach for UUID V4 in real Go applications?

In practice, teams adopt UUID V4 when the system benefits from fully random values rather than from a generic one-size-fits-all UUID choice. That usually maps well to public IDs, request IDs, and cross-service references, especially in Gin or Fiber code where identifiers are assigned before persistence.

Where does UUID V4 pay off most inside Gin or Fiber?

It tends to pay off where identifiers leave the database layer and become part of the application contract. In Gin and Fiber, that usually means route params, model fields, serialized API responses, and internal references that benefit from simple generation across any service boundary.

Should background jobs in background workers use UUID V4?

That depends on what the queue pipeline needs. UUID V4 is useful in background workers jobs when the team wants fully random values carried consistently through retries, workers, and event consumers, and when that aligns with public IDs, request IDs, and cross-service references.

What is the most common mistake when using UUID V4 in Go?

The biggest mistake is treating every UUID version as if it solved the same problem. In Go, the healthier approach is to standardize generation in one place, keep one string format across the stack, and be clear that records are unique but not naturally sortable.

Related pages

Internal links

Go deep dive

UUID v4 in Go: when it fits, where it hurts, and why UUID v7 is part of the decision now

Most pages about UUID v4 in Go are too short to help with a real engineering decision. They show a tiny snippet, often with github.com/google/uuid, print one value, and stop. That covers syntax. It does not answer the questions Go teams actually run into in production. Should UUID v4 be the primary key in PostgreSQL? What happens to index locality? Is UUID v7 better for write-heavy services? Which Go libraries support v7 today? And if performance matters, what should you benchmark instead of just timing one function call?

Those are the questions worth answering if you are building APIs, queue workers, event processors, or internal services in Go. Go makes UUID generation straightforward with standard libraries. The harder part is choosing the right identifier strategy for the workload behind that code. Random UUIDs solve one set of problems very well. They also create predictable trade-offs in storage and indexing.

This page focuses on practical usage in Go, not abstract UUID theory. The goal is to help you decide when UUID v4 is a strong default, when UUID v7 is the better fit, and where a plain auto-increment key is still the cleanest answer.

If you want the base standards and package references alongside this guide, the most useful sources are the github.com/google/uuid package docs and the UUID specification that defines modern UUID versions including v7. The rest of this section translates those building blocks into Go-specific guidance.

Why Go teams use it

Why UUID v4 is still common in Go services

UUID v4 remains popular in Go because it solves a clean, practical problem: generate an ID in application code without asking the database for one. That matters in handlers, workers, and services that want an identifier before the first write happens. A request can get an ID at the edge. A background job can log, trace, and publish messages with one stable value. A service can create an object ID before it persists anything.

That pattern fits Go well. Many Go applications are small networked services with explicit boundaries between HTTP handlers, queues, storage, and downstream calls. A database-generated integer is fine if the database is the first place the object exists. A UUID v4 is more flexible when the object needs a stable identity before that point.

There is also a product-level reason teams choose UUID v4. Public integer IDs are easy to enumerate. That does not automatically make them insecure, but it does expose sequence and rough object counts. Random UUIDs avoid that by default. If your API returns customer-facing resource identifiers, a UUID v4 can be a clean way to keep those IDs opaque.

The point is not that UUID v4 is universally better. The point is that it gives Go services independence from central sequencing. That is its real value.

When not to use it

When UUID v4 is the wrong default in Go

The most common mistake is treating UUID v4 as automatically modern and therefore automatically correct. In many systems it is a good choice. In others it is needless overhead. If your Go application is a single database-backed service, inserts are heavy, and you do not need the ID before persistence, a sequential integer key may be better. It is smaller, more index-friendly, and easier for the database to maintain efficiently.

You should also be cautious if your hottest tables care a lot about insertion order and clustered index locality. Random UUIDs spread writes across the key space. That is not a problem for every table. It is a real problem for some of them. If your main write path is sensitive to page splits, cache churn, or large secondary indexes, UUID v4 deserves more scrutiny.

Another weak use case is ordering. UUID v4 carries no time ordering. If your logs, operational workflows, or tables benefit from roughly increasing IDs, v4 does not help. This is the point where UUID v7 enters the conversation. A lot of new Go systems do not need to choose between random UUIDs and integers. They need to choose between UUID v4 and a time-ordered UUID.

How UUID v7 works

How UUID v7 works, including the timestamp structure

UUID v7 keeps the same 128-bit UUID shape, but it changes what the leading bits mean. Instead of being fully random like v4, UUID v7 starts with a Unix timestamp in milliseconds. The high-order portion of the value reflects creation time, and the remaining bits include the version marker, variant marker, and randomness. The practical result is simple: new UUID v7 values sort roughly by creation time instead of scattering randomly across the key space.

That timestamp-first layout is the reason v7 gets attention from database-minded teams. It preserves the decentralised generation model that makes UUIDs useful, but it behaves more like an ordered key when inserted into an index. You still avoid a central sequence. You also get better write locality than a purely random identifier.

For Go developers, the most useful way to think about UUID v7 is this: it is still a UUID, still globally usable across services, and still safe to generate in application code, but it is designed with modern storage behavior in mind. It is not just “v4 with a different name.” The timestamp structure changes how the value behaves in sorted data structures and database indexes.

That matters in APIs and workers because identifiers do more than identify records. They influence write patterns, index growth, and operational visibility. A time-ordered UUID lets you keep UUID semantics while reducing one of the biggest practical downsides of UUID v4.

v7 vs v4

UUID v7 vs UUID v4 in Go: the performance difference is mostly about storage behavior

When developers search for UUID v7 vs v4 performance, they often expect the answer to be about CPU time for generation. In most Go applications, that is not the main issue. Both versions are usually cheap to generate compared with database I/O, network calls, JSON encoding, and application logic. The more important difference appears after the ID reaches the database.

UUID v4 is random. New values land across the index rather than near the end. UUID v7 is time-ordered. New values are much more likely to cluster near recently inserted rows. On a write-heavy table, that difference can reduce index fragmentation and make insert patterns friendlier to the database engine.

So the useful comparison is not “which one is faster to call in Go?” The useful comparison is “which one leads to healthier database behavior under our workload?” For a small service with modest traffic, UUID v4 may be completely fine. For a larger service with constant inserts and several indexes, UUID v7 often has a stronger operational profile.

That does not mean v7 wins every time. If your main requirement is opaque public IDs and your write volume is moderate, UUID v4 is still a valid choice. But if you are starting a new Go service and you already know the main tables will be write-heavy, v7 deserves serious consideration before you standardize on v4 out of habit.

Database indexing

Database indexing benefits of UUID v7 compared with UUID v4

This is where the v7 argument becomes concrete. Databases can store both UUID v4 and UUID v7. The difference is how inserts behave over time. A random UUID v4 primary key pushes writes across the index range. A time-ordered UUID v7 tends to push new rows closer to the latest part of the index. That usually improves locality.

Better locality can mean fewer page splits, less churn in B-tree structures, and more predictable cache behavior. The exact effect depends on the engine, schema, and workload, but the direction is easy to understand. Ordered values are generally easier on indexes than random values.

For PostgreSQL and MySQL-backed Go applications, this matters most on large, hot tables. The difference may be negligible on a low-volume table with a few thousand rows. It becomes much more visible when the same table sees sustained writes, multiple secondary indexes, and frequent lookups.

There is also a second-order benefit: if your primary key is less chaotic, secondary structures that include that key often behave more predictably too. The main takeaway is not that UUID v7 is magically free. The takeaway is that UUID v7 reduces one of the biggest database costs associated with UUID v4.

If you still want UUID v4 for external APIs, there is also a hybrid option. Some Go systems use an internal ordered key for database efficiency and a UUID for public references. That pattern is sometimes the best compromise when storage and external contracts have different needs.

Go library support

Go libraries supporting UUID v7

One reason many Go teams still default to UUID v4 is library familiarity. The most common package examples on the internet use github.com/google/uuid for v4 generation, parsing, and formatting. That makes v4 the path of least resistance in many codebases.

UUID v7 support is more package-dependent. Not every UUID package that handles v4 also exposes a ready-made v7 generator. If your service needs v7, check library support explicitly instead of assuming that “UUID support” automatically includes modern ordered variants.

The practical rule for Go is simple:

  • Use a mature, well-documented package if you only need UUID v4 and standard parse or format operations.
  • Choose a package with explicit UUID v7 support if ordered UUIDs are part of the design.
  • Do not hide the version choice behind vague helper names such as NewID() unless the project standard is clearly documented.

This is worth making explicit in a Go codebase because UUIDs tend to spread quickly. Once the ID format is used in handlers, models, events, and database rows, changing versions later becomes more expensive. Decide early whether the project wants random UUIDs, time-ordered UUIDs, or a mix with clear boundaries.

Benchmarks

What to benchmark in Go if UUID performance matters

Benchmarks matter here, but many teams benchmark the wrong thing. A micro-benchmark that calls a UUID generation function in a tight loop can still be useful. It tells you allocation count, throughput, and whether one package is doing unnecessary work. But that benchmark alone rarely decides whether v4 or v7 is the better identifier strategy.

If you care about real performance in a Go service, benchmark the parts that actually move the needle:

  • Generation throughput and allocations for the library you plan to use
  • Insert rate into the target database with the same schema and indexes you use in production
  • Primary key index growth under sustained writes
  • Read performance for the lookup patterns your service relies on
  • Storage cost when UUIDs are stored as text versus a compact native or binary form

That last point is easy to miss. Many discussions compare only v4 and v7 while ignoring how the value is stored. In practice, storage format can be nearly as important as UUID version. A poorly chosen column type can erase some of the operational gains you expected.

For developer SEO, this matters because engineers searching for benchmarks are usually not looking for theory. They want to know what to measure in a realistic setup. The honest answer is that generation cost is usually not the bottleneck. Index behavior and database write locality are more likely to dominate.

If you publish internal or public benchmark results, keep them credible. Include the Go version, UUID package, database version, schema, index layout, row count, and machine profile. Numbers without context are hard to trust and easy to misuse.

UUID vs auto increment

UUID v4 versus auto-increment IDs in Go applications

This comparison still matters because it keeps the trade-off grounded. An auto-increment integer is compact, ordered, and easy for relational databases to index efficiently. If your object does not need an identity before the insert, and the database is the only authority creating rows, an integer key is usually the simplest internal design.

UUID v4 gives you different benefits: application-side generation, opaque public identifiers, and no dependence on a central sequence. Those are real benefits. They are not free. The storage engine pays part of the cost later through larger, less ordered indexes.

Strong Go systems often separate those concerns. They keep an internal ordered key for the database and expose a UUID externally, or they adopt UUID v7 when they want one ID format that still behaves better in the index. The right answer depends on whether database efficiency, public API design, and distributed creation all need to be solved by the same field.

Bottom line

UUID v4 in Go is easy to adopt, but UUID v7 is often the better comparison for modern systems

UUID v4 is still a solid choice in Go when you need application-generated IDs, public identifiers that do not expose sequence, and a format that moves cleanly across services and workers. It is simple, familiar, and widely supported.

The harder question is whether random UUIDs are the right fit for your data layer. If database indexing, write locality, and long-term operational cost matter, UUID v7 deserves attention before you standardize on v4. For many new Go services, the real choice is not “UUID or not.” It is “which UUID version matches the way this system writes data?”

Contact

Send a message and it will be delivered to our Telegram channel.