and the release notes with all the technical details you'd like to know: http://erlang.org/download/otp_src_21.0.readme
A few of the things I noticed:
> Two new guards BIFs operating on maps have been added: map_get/2 and is_map_key/2. They do the same as maps:get/2 and maps:is_key/2, respectively, except that they are allowed to be used in guards.
This is great and further enhances usefulness of both the maps, and the guards, which is always a good thing.
> There is a new syntax in 'try/catch' for retrieving the stacktrace without calling 'erlang:get_stacktrace/0'. See the reference manual for a description of the new syntax. The 'erlang:get_stacktrace/0' BIF is now deprecated.
You can now get the stacktrace when matching exceptions in the `catch` section of `try`, like `error:Exception:Stacktrace -> handler_code()`.
> A new logging API is added to Erlang/OTP, see the logger(3) manual page, and section Logging in the Kernel User's Guide.
I felt for a long time that configuring logging on the BEAM was a kind of dark art, and never really understood what goes where between SASL, error_logger, lager, and other tools. Now it got properly unified, from what I read, which should make it much easier to configure and use proper logging. That's great!
As a bonus, Elixir already supports the new logger[1], apparently.
Other than that there seem to be a lot of optimizations, in the compiler, in the emulator, in the IO system, and in signal handling. Also a lot of bugfixes, and some smaller conveniences like an iterator for maps.
All in all nothing as exciting as the introduction of maps (unless I'm missing something), but a pretty solid release anyway.