Skip to content

Quickstart

This page walks through the core workflow of TypeID: generating identifiers, inspecting them, and understanding how they fit into a real system.

It is intentionally short. The goal is to get you productive quickly, not to explain every detail.


Installation

Install the package using your preferred tool.

With pip:

pip install typeid-python

With uv:

uv add typeid-python

If you plan to use YAML schemas later, install the optional extra:

pip install "typeid-python[yaml]"

JSON schemas work without any extras.

Creating a TypeID

A TypeID is created by providing a prefix that describes what the identifier represents.

from typeid import TypeID

tid = TypeID("user")

value = str(tid)

assert value.startswith("user_")
assert len(value.split("_", 1)[1]) > 0

This produces a string similar to:

user_01h45ytscbebyvny4gc8cr8ma2

The prefix is meaningful to humans. The suffix is globally unique and time-sortable.

Prefixes are optional. If you omit it, you get a prefix-less identifier:

from typeid import TypeID

tid = TypeID(None)

assert not tid.prefix

This can be useful when the type is implied by context or stored elsewhere.

Pre-defined prefixes

Sometimes it's useful to have pre-defined prefix.

from dataclasses import dataclass, field
from typing import Literal
from typeid import TypeID, typeid_factory

UserID = TypeID[Literal["user"]]
gen_user_id = typeid_factory("user")


@dataclass()
class UserDTO:
    user_id: UserID = field(default_factory=gen_user_id)
    full_name: str = "A J"
    age: int = 18


user = UserDTO()
assert str(user.user_id).startswith("user_")

Parsing and validation

TypeIDs can be parsed back from strings.

from typeid import TypeID

prefix = "user"
suffix = "01h45ytscbebyvny4gc8cr8ma2"
tid = TypeID.from_string(f"{prefix}_{suffix}")

assert tid.prefix == "user" and tid.suffix == suffix

If the string is invalid, parsing fails explicitly. Invalid identifiers are never silently accepted.

When dealing with untrusted input, you will usually want to rely on the explain functionality instead of raising exceptions. This is covered later.

UUID compatibility

Every TypeID is backed by a UUID.

You can always extract the UUID:

tid.uuid

And you can always reconstruct a TypeID from a UUID:

from uuid6 import uuid7
from typeid import TypeID

u = uuid7()
tid = TypeID.from_uuid(suffix=u, prefix="user")
assert str(tid).startswith("user_")

This is the intended storage model:

Store UUIDs in the database. Expose TypeIDs at the application boundary.

You get the benefits of UUIDs at rest and the benefits of TypeIDs everywhere else.

Using the CLI

TypeID also ships with a command-line interface.

If you installed the CLI extra:

pip install "typeid-python[cli]"

You can generate identifiers directly:

typeid new -p user

You can inspect existing identifiers:

typeid decode user_01h45ytscbebyvny4gc8cr8ma2

And you can convert between UUIDs and TypeIDs:

typeid encode <uuid> --prefix user

Explaining an identifier

The most distinctive feature of this implementation is the ability to explain identifiers.

typeid explain user_01h45ytscbebyvny4gc8cr8ma2

This command inspects the identifier and reports:

  • whether it is valid
  • what prefix it uses
  • which UUID it represents
  • when it was created

This works even without any configuration and never crashes on invalid input.

If you want to understand why TypeID works the way it does, read Concepts.

If you want to understand what explain can do, read Explain.

If you want integration details or API reference material, those sections are available as well.

At this point, you already know enough to start using TypeID in a real project.