The biggest downside (imo) of the Stripe approach is that you either have to store them as strings, which isn't great, or strip/prepend in your API layer.
So I made a new thing called UPID. It's most similar to ULID, as it includes a time-component (but with lower precision) and also encodes to a base32 alphabet. But it also includes a 20-bit prefix (allowing four characters). So it can be stored as a UUID or anywhere a 128-bit blob goes, and it always knows what its prefix is because it's baked in.
I've made implementations for Python, Rust and TypeScript, as well as a Postgres extension (with a upid datatype). Mentioned it a few weeks ago in a HN discussion and people seemed pretty interested so thought I'd post it as a submission.
In Rust it looks like this:
use upid::Upid;
Upid::new("post"); // post_2acqyme2ygscyguveuhj5a
There are more examples in the repositories.Repo (Python, Rust, Postgres): https://github.com/carderne/upid
TypeScript: https://github.com/carderne/upid-ts
Demo site: https://upid.rdrn.me/