As a new Phoenix user, I was happy to discover that Phoenix doesn’t render strings but something rather like Erlang iodata. That lets me use a more builder-style approach for creating chunks of HTML pages - but without having to use elaborate infrastructure. Seems to be working nicely so far.
Nice, although one thing to note is that although eex accepts ‘nil’, it should not really ever be used. Returning an empty list of  is always a better approach than returning nil as it then allows it to be embedded further without worry. I consider nil’s returned from a function that could ever possibly end up going to a template as a bug.
Other than that your article looks like a fairly accurate high level view.
A nil in elixir is just an atom, if you put an atom in an iolist then it is no longer an iolist and can crash. By always returning  (which, consequently, is Erlang’s nil, Elixir borked that hard and I really hope Elixir 2.0 fixes that) then you can embed those calls in iolists without worry.
:undefined for non-initialized state, I still use that in Elixir as well, but nil is often returned in places that are not just non-initialized but convey information, like ‘nothing’, which is what  also states, which is especially useful in a lot of situations. If anything an ‘undefined’ keyword should be added that just maps to :undefined, and nil maps to .
 is not Erlang’s nil. That notation is used only in the abstract syntax tree and in Erlang code nil has exactly the same as nil in Elixir.
Plus  has the notion of cardinality, which nil is devoid of. Given Elixir has both collections and base types, I believe it is important to represent nothingness without a notion of cardinality built-in.
At least at the VM level, ordering level, type encoding, and everything else in the vm, the empty list is called ‘nil’ in the BEAM, and many things are optimized for it in terms of space and speed, more so than any atom.