URL-Safe UUIDs: Compressing 36 Characters Into 22

    February 26, 2024
    9 min read
    Technical explainer
    Tutorial
    uuid
    performance
    best-practices

    UUIDs are everywhere — but their default string format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) takes up 36 characters, which can be verbose in URLs, QR codes, and user-facing identifiers.

    So… what if we could make them shorter — say, 22 characters — while keeping them globally unique?

    Good news: we can.

    Let’s explore how to safely compress UUIDs using Base64 URL-safe encoding, and when (and how) you should use them.


    📏 Why Are UUIDs 36 Characters Long?

    The canonical UUID string format looks like this:

    code
    550e8400-e29b-41d4-a716-446655440000
    • It contains 32 hex characters
    • Plus 4 hyphens
    • Total: 36 characters

    Internally, a UUID is actually 128 bits (or 16 bytes). The string version is just one possible representation.


    🎯 Our Goal: 22 Characters

    Using Base64 encoding, we can take that 16-byte binary and convert it to a much more compact form.

    • Base64 encodes 3 bytes into 4 characters
    • 16 bytes → 22 characters + 2 padding =

    We’ll use Base64 URL-safe mode (with - and _ instead of + and /).

    By stripping the padding, we get a compact, safe, and unique 22-character string.


    🧪 Encoding Example in Python

    python
    import uuid
    import base64
    
    def uuid_to_short(uuid_obj):
        return base64.urlsafe_b64encode(uuid_obj.bytes).rstrip(b'=').decode('ascii')
    
    def short_to_uuid(short_str):
        padded = short_str + '=='
        return uuid.UUID(bytes=base64.urlsafe_b64decode(padded))
    
    # Example usage
    u = uuid.uuid4()
    short = uuid_to_short(u)
    print("UUID:", u)
    print("Short:", short)
    
    # Reverse it
    original = short_to_uuid(short)
    print("Recovered UUID:", original)

    📦 Go (Golang) Example

    go
    package main
    
    import (
        "encoding/base64"
        "fmt"
        "github.com/google/uuid"
        "strings"
    )
    
    func main() {
        u := uuid.New()
        encoded := base64.URLEncoding.EncodeToString(u[:])
        short := strings.TrimRight(encoded, "=")
        fmt.Println("Short UUID:", short)
    
        // Decode back
        padded := short + strings.Repeat("=", (4 - len(short)%4) % 4)
        decoded, _ := base64.URLEncoding.DecodeString(padded)
        recovered, _ := uuid.FromBytes(decoded)
        fmt.Println("Recovered UUID:", recovered)
    }

    🧑‍💻 JavaScript (Node.js) Example

    js
    const { v4: uuidv4, parse, stringify } = require('uuid');
    
    function uuidToShort(u) {
        const bytes = parse(u);
        const base64 = Buffer.from(bytes).toString('base64url');
        return base64;
    }
    
    function shortToUuid(s) {
        const padded = s.padEnd(24, '=');
        const bytes = Buffer.from(padded, 'base64url');
        return stringify(bytes);
    }
    
    const u = uuidv4();
    const short = uuidToShort(u);
    const recovered = shortToUuid(short);
    
    console.log("UUID:", u);
    console.log("Short:", short);
    console.log("Recovered:", recovered);

    🧠 Why This Works

    • UUIDs are exactly 128 bits
    • Base64 encoding is deterministic and reversible
    • The URL-safe variant replaces + with - and / with _
    • Padding == can be dropped safely and restored when decoding

    This means we can safely convert UUIDs to shorter, more portable strings.


    🛡️ Is It Still Unique?

    Yes!

    • No entropy is lost — you’re encoding the full 16-byte UUID
    • It’s just a different representation, like hex() vs .bytes
    • UUID collisions remain astronomically unlikely (~1 in 2^122)

    🔐 Security and Safety Considerations

    • These short UUIDs are not encrypted or obfuscated
    • Anyone can decode them back to the full UUID
    • Do not embed sensitive data (use JWTs or signed tokens for that)

    If you need cryptographic integrity, consider:

    • JWTs with claims
    • Signed UUIDs (e.g. HMAC(uuid))
    • UUIDv5 with secret namespace

    📘 Use Cases

    • Short URLs (example.com/r/22charid)
    • URL-safe file names
    • Embed in QR codes or slugs
    • Compact API keys or tokens
    • Visual UIs where UUIDs are user-facing

    🚫 Don’t Do This

    • Don’t truncate UUIDs manually (e.g. uuid[:8]) — it destroys uniqueness
    • Don’t use regular Base64 with + and / in URLs — not safe!
    • Don’t forget to add padding back when decoding (some libs fail silently)

    🧪 Benchmarking Storage and Display

    FormatLengthURL-safeReadable
    UUIDv4 (canonical)36
    UUID (hex only)32
    Base64 (URL-safe)22
    Base58 (optional)~22

    🔄 Round Trip Consistency

    Always test:

    text
    UUID → compressed → decompressed → UUID

    If you end up with a different UUID at the end, your encoding logic is broken. Stick to well-tested libraries and watch for issues with padding, bytes vs strings, or endianness.


    Final Thoughts

    If you want shorter UUIDs without losing any uniqueness, Base64 URL-safe encoding is a fantastic solution.

    You get:

    • Compact 22-character identifiers
    • Perfect reversibility
    • Full UUID compatibility
    • Safe usage in URLs, HTML, filenames, and API paths

    So go ahead — compress those UUIDs. Your URLs (and your users) will thank you.

    📦 36 → 22: Done right.

    Generate Your Own UUIDs

    Ready to put this knowledge into practice? Try our UUID generators:

    Generate a Single UUID

    Create a UUID with our fast, secure generator

    Bulk UUID Generator

    Need multiple UUIDs? Generate them in bulk

    Summary

    This article explains how to transform standard UUIDs into compact, URL-safe formats using Base64 encoding. Includes code examples, best practices, and guidance for safely shortening UUIDs without compromising uniqueness.

    TLDR;

    Standard UUIDs are 36 characters long — but can be safely encoded into 22-character URL-safe strings using Base64.

    Key takeaways:

    • Convert UUIDs to 16-byte binary and encode using Base64 URL-safe mode
    • Strip padding (=) to get a consistent 22-character representation
    • Decoding must account for padding restoration

    Great for short URLs, compact tokens, and readable links — with no loss of uniqueness or integrity.

    Cookie Consent

    We use cookies to enhance your experience on our website. By accepting, you agree to the use of cookies in accordance with our Privacy Policy.