GUID

What is a GUID?

GUID stands for Globally Unique Identifier - it’s essentially a 128-bit number that’s designed to be unique across space and time. You’ll also hear them called UUIDs (Universally Unique Identifiers), which is the same thing with slightly different naming.

In .NET, we use the Guid struct to work with these identifiers, and they look something like this:

6ba7b810-9dad-11d1-80b4-00c04fd430c8

That’s 32 hexadecimal digits displayed in five groups separated by hyphens. Not exactly human-readable, but that’s not really the point!

Why Use GUIDs?

GUIDs solve a fundamental problem in distributed systems: how do you create unique identifiers without coordinating with a central authority?

The Traditional Problem

Imagine you’re building an API that needs to create unique IDs for resources. You might start with simple auto-incrementing integers:

public class Product
{
    public int Id { get; set; } // 1, 2, 3, 4...
    public string Name { get; set; }
}

This works fine until you need to:

  • Merge data from multiple databases
  • Create records offline that sync later
  • Scale across multiple servers
  • Import data from external systems

Suddenly, you’ve got ID collisions everywhere!

The GUID Solution

GUIDs are generated using algorithms that make collisions virtually impossible (we’re talking about astronomical odds here). This means you can generate them anywhere, anytime, without worrying about duplicates.

public class Product
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public string Name { get; set; }
}

Working with GUIDs in C#

Creating GUIDs

The most common way to create a new GUID:

Guid newId = Guid.NewGuid();
Console.WriteLine(newId); // e.g., 6ba7b810-9dad-11d1-80b4-00c04fd430c8

Parsing GUIDs

Converting strings to GUIDs:

// If you're confident the string is valid
Guid parsed = Guid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8");

// If you want to handle invalid strings gracefully
if (Guid.TryParse("some-string", out Guid result))
{
    Console.WriteLine($"Valid GUID: {result}");
}
else
{
    Console.WriteLine("Invalid GUID format");
}

Empty GUIDs

Sometimes you need to check for an “empty” GUID:

Guid empty = Guid.Empty; // 00000000-0000-0000-0000-000000000000

if (someId == Guid.Empty)
{
    // Handle empty GUID scenario
}

GUIDs in APIs

In REST APIs, GUIDs make excellent resource identifiers:

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult GetProduct(Guid id)
    {
        // id is automatically parsed from the route
        var product = _productService.GetById(id);
        
        if (product == null)
            return NotFound();
            
        return Ok(product);
    }
}

Your URLs end up looking like:

GET /api/products/6ba7b810-9dad-11d1-80b4-00c04fd430c8

Database Considerations

Entity Framework Core

EF Core handles GUIDs beautifully:

public class Product
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

// In your DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>(entity =>
    {
        entity.HasKey(e => e.Id);
        entity.Property(e => e.Id)
              .HasDefaultValueSql("gen_random_uuid()"); // PostgreSQL
              // .HasDefaultValueSql("NEWID()"); // SQL Server
    });
}

Performance Notes

GUIDs aren’t free from a performance perspective:

  • They’re larger than integers (16 bytes vs 4 bytes)
  • Random GUIDs can cause index fragmentation in some databases
  • Sequential GUIDs (Guid.CreateVersion7() in .NET 9+) can help with this

For most applications, the benefits outweigh the costs, but it’s worth being aware of the trade-offs.

When NOT to Use GUIDs

GUIDs aren’t always the right choice:

  • User-facing IDs: They’re not human-readable or memorable
  • High-performance scenarios: Where every byte counts
  • Simple, single-database applications: Auto-incrementing integers might be simpler
  • Ordered data: GUIDs don’t have inherent ordering (unless using sequential variants)

Best Practices

  1. Generate GUIDs close to creation time - don’t pre-generate them unless you have to
  2. Use Guid.Empty for null checks rather than nullable Guids where possible
  3. Consider sequential GUIDs for database performance in write-heavy scenarios
  4. Always validate GUID strings when accepting them from external sources
  5. Use GUIDs consistently - mixing GUID and integer IDs in the same system gets messy

Wrap Up

GUIDs are one of those things that seem overly complex when you first encounter them, but once you understand their purpose, they become incredibly useful. They’re particularly valuable in modern distributed systems where you need to generate unique identifiers without central coordination.

In the context of building APIs, they provide a robust way to identify resources that scales well and avoids many of the pitfalls of simpler ID schemes. Just remember - they’re a tool in your toolbox, not a silver bullet for every identification need!