# shortuuid: 128 bits of randomness compressed into 22 URL-safe characters

> A dependency free Python library that wraps the standard uuid module, re-encodes the result in a base57 alphabet with the confusable characters removed, and ships a Django field.

**skorokithakis/shortuuid** — A generator library for concise, unambiguous and URL-safe UUIDs.

- Repository: https://github.com/skorokithakis/shortuuid
- Website: http://www.stavros.io/
- Stars: 2,197 · Forks: 119
- Language: Python
- License: BSD-3-Clause
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/skorokithakis-shortuuid

## One function and twenty two characters

The whole library is one import and one call:

```python
>>> import shortuuid
>>> shortuuid.uuid()
'vytxeTZskVKR7C7WgdSP3d'
```

What happens underneath is a translation, not a new random source. A UUID is generated with Python's built in `uuid` module and then encoded into base57 using letters and digits, with characters that look alike removed. The README lists the confusable set explicitly as lowercase l, digit 1, uppercase I, uppercase O and digit 0.

The resulting alphabet is the whole design in one line:

```python
>>> shortuuid.get_alphabet()
'23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
```

Fifty seven characters, which is why a 128 bit UUID becomes a 22 character string. That length is not arbitrary: the README states that the default alphabet matches the regex `[2-9A-HJ-NP-Za-km-z]{22}`, so if you validate short UUIDs with a pattern, that is the pattern that corresponds to stock behaviour.

GitHub reports 2,198 stars, 119 forks and zero open issues. The package requires Python 3.6 or newer and has no runtime dependencies.

## The alphabet is global state you can replace

`set_alphabet()` changes the character set used for new IDs, which is the feature that lets you trade entropy for readability or match an existing system's format:

```python
>>> shortuuid.set_alphabet("aaaaabcdefgh1230123")
>>> shortuuid.uuid()
'0agee20aa1hehebcagddhedddc0d2chhab3b'
>>> shortuuid.get_alphabet()
'0123abcdefgh'
```

Note what happened to the input. Nine distinct characters were given, duplicates were dropped, and the result was sorted, which the README explains as a measure to keep IDs consistent across implementations. Sorting means the alphabet is canonical regardless of how you typed it, so a second process deriving the same set gets the same mapping.

If you need the order you supplied rather than a sorted one, pass `dont_sort_alphabet=True`, which the README ties to compatibility with other ShortUUID implementations:

```python
>>> shortuuid.set_alphabet("aaaaabcdefgh1230123", dont_sort_alphabet=True)
>>> shortuuid.get_alphabet()
'abcdefgh1230'
```

For per thread or per instance alphabets, use the `ShortUUID` class instead of the module level functions. This matters in a web application, because the module level alphabet is shared process wide.

## Encoding is reversible, and truncation is where uniqueness goes

Because the encoding is a base conversion rather than a hash, it can be undone. `encode()` takes a `uuid.UUID` and returns the short string, and `decode()` goes the other way:

```python
>>> import uuid
>>> u = uuid.uuid4()
>>> s = shortuuid.encode(u)
'MLpZDiEXM4VsUryR9oE8uc'
>>> shortuuid.decode(s) == u
True
```

The README also documents the decode of a truncated string, which is worth reading because it shows exactly what truncation costs:

```python
>>> short = s[:7]
>>> h = shortuuid.decode(short)
UUID('00000000-0000-0000-0000-009a5b27f8b9')
```

Seven characters decode back to a UUID whose leading sixteen bytes are all zero. That is the expected behaviour, and the README's guidance follows directly: if 22 characters is too long, truncate the string, and accept that IDs are no longer universally unique, with collision probability still very low. The library will not stop you, and it does not pretend the guarantee survived.

There is also a random string generator that does not go through UUID at all, `ShortUUID().random(length=22)`, which the README notes uses `os.urandom()` internally. Use that when you want a short random token rather than a shortened UUID.

## The MSB ordering change is the one upgrade trap

Versions before 1.0.0 generated UUIDs with the most significant byte last, which the README describes as reversed. That was fixed, and the consequence for existing data is spelled out: stored short UUID strings from the old scheme must be passed with `legacy=True` to `decode()`, and the result is round tripped through the new encoder to bring the rows forward.

```python
>>> new_uuid_str = encode(decode(old_uuid_str, legacy=True))
```

The README is direct that the option will be removed in future, so this is a migration to schedule rather than a setting to keep. The v1.0.0 release notes for 2020-03-06 lead with a breaking release warning and point at this same section.

Two other documentation details are worth knowing before you rely on the README. One example in the usage section shows a name based call whose printed output repeats the call itself rather than a generated ID, so treat that specific doctest as an editing slip rather than as expected output. And the install instructions still mention `easy_install` and `python setup.py install`, while the project now builds with Poetry, so the pip route is the current one.

## A Django field, a CLI, and a repository mid migration

Two integrations ship with the package. The Django field is `ShortUUIDField`, which generates random short UUIDs by default and takes `length`, `alphabet`, `dont_sort_alphabet` and `prefix`:

```python
from shortuuid.django_fields import ShortUUIDField

class MyModel(models.Model):
    # A primary key ID of length 16 and a short alphabet.
    id = ShortUUIDField(
        length=16,
        max_length=40,
        prefix="id_",
        alphabet="abcdefg1234",
        dont_sort_alphabet=False,
        primary_key=True,
    )

    # A short UUID of length 22 and the default alphabet.
    api_key = ShortUUIDField()
```

It is described as a `CharField` with `length`, `alphabet` and `default` removed and everything else intact, including `index`, `help_text` and `max_length`. A short alphabet applied to a primary key is the case worth thinking about, because the field length and the alphabet size together determine collision behaviour, and this library will happily generate a low entropy key if you configure it that way.

There is also a command line entry point, declared in the project metadata as `shortuuid = shortuuid.cli:cli`, so `shortuuid` on its own prints one ID.

The build configuration has moved on since those install instructions were written. The project uses `pyproject.toml` with `poetry-core` as the build backend and the package version is 1.0.13, while the most recent GitHub release is v1.0.0 from 2020-03-06. Older `setup.cfg`, `MANIFEST.in`, `tox.ini`, a Travis configuration and a gitchangelog configuration are all still in the tree. The repository was last pushed on 2026-06-20, with no open issues, so work is current even though the tagged release history stopped in 2020.

## Conclusion

shortuuid does one thing and does it in a way you can audit in a minute: it takes a UUID from the standard library and re-encodes it, so the entropy is exactly what `uuid` already gave you and nothing is added. Two things decide whether it suits you. If you need to shorten IDs further, the README's advice is to truncate and accept a lower uniqueness guarantee, which is a real trade rather than a free win. And if you are upgrading from before 1.0.0, the MSB ordering changed, so stored strings need `decode(..., legacy=True)` and a rewrite. The package requires Python 3.6 or newer, has no runtime dependencies, and is installed as `shortuuid`.

## FAQ

### How to generate a short UUID?

Import the library and call uuid(). In shortuuid that is import shortuuid followed by shortuuid.uuid(), which returns a 22 character string such as vytxeTZskVKR7C7WgdSP3d. The default alphabet matches the regex [2-9A-HJ-NP-Za-km-z]{22}. If you need it in a terminal, the package installs a shortuuid command that prints one.

### Why is UUID bad for primary key?

The usual complaint is that a 36 character UUID is large, unordered and index unfriendly compared with an incrementing integer. shortuuid addresses the size half of that by re-encoding a UUID into 22 URL-safe characters, and it can be used as a Django primary key through ShortUUIDField with a length and alphabet argument. Note that a short alphabet and a short length together reduce the collision margin, so configure them deliberately.

### What is UUID and why is it used?

A UUID is a 128 bit identifier that can be generated without coordination between systems, which is why it is used as a primary key or request identifier when an auto increment would leak volume or require a central sequence. shortuuid does not replace that scheme: it takes a UUID produced by Python's uuid module and re-encodes it in base57, so the underlying uniqueness guarantee is still the one UUID gives you.

## Sources

- [License: BSD-3-Clause](https://github.com/skorokithakis/shortuuid/blob/master/LICENSE)
- [Project website](http://www.stavros.io/)
- [README](https://github.com/skorokithakis/shortuuid/blob/master/README.md)
- [Releases](https://github.com/skorokithakis/shortuuid/releases)
- [skorokithakis/shortuuid on GitHub](https://github.com/skorokithakis/shortuuid)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/skorokithakis-shortuuid
