NIFs have the downside of potentially bringing down the VM don't they? It's definitely true that the glue code can be a pain and may involve warping the foreign code into having a piece that plays along nicely with what erlang expects. I messed around with making erlang code and python code communicate using erl_interface and the code to handle messages pretty much devolved into "have a running middleman process that invokes erl_interface utilities in python via a cffi wrapper, then finally call your actual python code." Some library may exist or could be written to help with that, but it's a lot when you just wanna invoke some function elsewhere. I also have not tried using port drivers, the experience may be a bit different there.
Yeah, NIFs are dynamically linked into the running VM, and generally speaking, if you load a binary library, you can do whatever, including crashing the VM.
BEAM has 4 ways to closely integrate with native code: NIFs, linked in ports, OS process ports (fork/ecommunicate over a pipe), and foreign nodes (C Nodes). You can also integrate through normal networking or pipes too. Everything has plusses and minusses.
Yeah, a NIF can bring down the entire OS process but I've used quite a bit of Rust NIFs with Elixir and never once had a crash. With Rust you can make sure nothing ever goes down, minus stuff that's completely out of your control of course (like a driver crash).