A ULID is 128 bits: a 48-bit Unix timestamp in milliseconds followed by 80 random bits, written as 26 characters of Crockford’s Base32 — ten for the time and sixteen for the randomness. Because the time comes first and the alphabet is in ASCII order, sorting ULIDs as plain strings sorts them by creation time. That is the reason to choose one over a random UUID: new keys land at the end of a B-tree index instead of scattering across it. Decoding runs the other way, so the first ten characters of any ULID give the millisecond it was made — 01ARYZ6S41TSV4RRFFQ69G5FAV, the example from the reference implementation, dates from 22:36:16.385 UTC on 30 July 2016.
Two ULIDs made in the same millisecond share their first ten characters, and their random parts sort in no particular order. Monotonic mode, which the specification describes and which is on by default here, fixes that by taking the previous random part and adding one, so a batch made within a single millisecond still sorts in the order it was generated. The cost is that consecutive IDs can be predicted from each other, so turn it off when a ULID doubles as an unguessable token. If the random part is already at its maximum, the specification says generation must fail rather than wrap round, and it does. The random bits come from crypto.getRandomValues, never Math.random.
Decoding follows the specification, including the parts that are easy to get wrong. It is case-insensitive, but I, L, O and U are rejected rather than read as 1, 1 and 0. Crockford’s Base32 permits those aliases; the ULID specification defines only the alphabet, which leaves them out, and the reference implementation’s validator refuses them, so accepting them would pass strings that libraries will not parse. The error gives the position and the character that was probably meant. Twenty-six Base32 characters could hold 130 bits, so the first must be 0 to 7, and anything above 7ZZZZZZZZZZZZZZZZZZZZZZZZZ is refused. The UUID form is the same 128 bits as hex. It fits a PostgreSQL uuid column but is not an RFC 9562 UUID, because its version and variant digits are ordinary ULID bits. A UUID can be pasted in too: for version 7, whose first 48 bits are also Unix milliseconds, the decoded time is real.