All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
3.0.0-rc.2 — 2026-05-28
Refinements over rc.1, focused on input validation. No changes to the public API surface introduced in rc.1.
Added
- New
Nanoid.Alphabetmodule that centralises input validation:convert_alphabet/1returns{:ok, grapheme_tuple} | :error,validate_size/1returns{:ok, pos_integer} | :error. Both are pure and never raise — the caller decides how to react.
Fixed
- Alphabet length is now checked by grapheme count instead of
byte_size/1. A single multi-byte grapheme such as"ä"previously slipped past thebyte_size(alphabet) > 1guard and crashed with aFunctionClauseError. It now raises a descriptiveArgumentErrorviagenerate_with/1(or falls back to the default via the deprecatedgenerate/2). Nanoid.SecureandNanoid.NonSecurenow report identical, descriptiveArgumentErrormessages for an alphabet with fewer than two symbols (previouslyFunctionClauseErrorinSecurevsArgumentErrorinNonSecure).- An invalid
:size(non-positive or non-integer) now raises a descriptiveArgumentErrorinstead of aFunctionClauseError.
Changed
:sizeand:alphabetvalidation in both generators is routed throughNanoid.Alphabet; the secure and non-secure paths now share the same checks and error messages.- Added
@specs to the private generator helpers and removed a redundantEnum.reverse/1in the secure generator's accumulator.
3.0.0-rc.1 — 2026-05-22
Release candidate for the upcoming 3.0.0 release. API is considered stable; please report any issues before the final release.
Added
- New keyword-based API:
Nanoid.generate_with/1andNanoid.generate_non_secure_with/1(plus the underlyingNanoid.Secure.generate_with/1andNanoid.NonSecure.generate_with/1). Pass:sizeand/or:alphabetas options. The function requires at least an (empty) options list; usegenerate/0/generate_non_secure/0for the no-options shortcut. - Unicode-safe alphabets: multi-byte graphemes (
"äöü", emoji, combining marks) are now handled correctly. The alphabet is converted to a tuple of graphemes once per call and indexed viaelem/2, dropping the per-symbol grapheme traversal thatString.at/2performed previously. Nanoid.Configuration.default_alphabet_tuple/0exposes the precomputed grapheme tuple for the default alphabet.CHANGELOG.mdadded and linked from the Hex package.
Changed
- Breaking: Minimum Elixir version bumped from
~> 1.12to~> 1.15. - Breaking: The library no longer ships a
config/config.exs. Defaults remain unchanged and can still be overridden via the consuming application's config — see the README. Nanoid.Configuration.default_alphabet_length/0is now computed from the precomputed grapheme list rather than viaString.length/1.ex_docdev dependency bumped to~> 0.34; the redundant directearmarkdependency was removed.
Deprecated
- The positional-argument functions
Nanoid.generate/1,2,Nanoid.generate_non_secure/1,2,Nanoid.Secure.generate/1,2andNanoid.NonSecure.generate/1,2— use thegenerate_with/1/generate_non_secure_with/1variants. The deprecated functions still work and preserve their previous "fall back to defaults on invalid input" behaviour so existing call sites are not broken at runtime. - The arity-0 functions (
Nanoid.generate/0,Nanoid.generate_non_secure/0and their submodule counterparts) are not deprecated: they remain the quick-access shortcut for the all-defaults case.
Removed
- Dead unreachable clauses in
Nanoid.Secure(do_generate/5fallback,generator/3fallback,calculate_mask/1fallback,calculate_step/3fallback,random_bytes/1fallback) and inNanoid.NonSecure(generator/2fallback). - Direct
earmarkdependency. config/config.exsfrom the library itself.
Fixed
@specforNanoid.generate_non_secure/2corrected frombinary() | any()(effectivelyany()) tobinary() | list().- Travis CI badge removed from the README; license link updated to point at the actual
LICENSEfile.
2.1.0
Previous release; see git history for details.