There are binaries and strings. Binaries is what are used as efficient "strings" most often these days. Binaries allow matching, even building bitstrings (binary strings not ending on an 8 bit boundary). Even more interesting, strings and binaries can be combined in iolists, which is an arbitrarily nested or combined list of binaries or other lists. Those can be used for efficient IO and IO drivers know how to emit or consume those.
For additional details I recommend https://adoptingerlang.org/docs/development/hard_to_get_righ... which also mentions how unicode is handled. It turned out quite a bit easier because of how Erlang represents strings.