A NIF library contains native implementation of some functions of an Erlang module. Each NIF must have an implementation in Erlang that is invoked if the function is called before the NIF library is successfully loaded. A typical such stub implementation is to throw an exception. Use this functionality with extreme care. A native function is executed as a direct extension of the native code of the VM. Execution is not made in a safe environment.

The VM cannot provide the same services as provided when executing Erlang code, such as pre-emptive scheduling or memory protection. If the native function does not behave well, the whole VM will misbehave. A native function that crash will crash the whole VM. An erroneously implemented native function can cause a VM internal state inconsistency, which can cause a crash of the VM, or miscellaneous misbehaviors of the VM at any point after the call to the native function. VM, and can cause miscellaneous strange behaviors.

Such strange behaviors include, but are not limited to, extreme memory usage, and bad load balancing between schedulers. NIF library automatically when the module is loaded. A NIF does not have to be exported, it can be local to the module. However, unused local stub functions will be optimized away by the compiler, causing loading of the NIF library to fail. Once loaded, a NIF library is persistent.

It will not be unloaded until the module code version that it belongs to is purged. All interaction between NIF code and the Erlang runtime system is performed by calling NIF API functions. The lifetime of a term is controlled by the lifetime of its environment object. All API functions that read or write terms has the environment that the term belongs to as the first function argument. All other functions that operate on a binary leave the data as read-only. However, it does not have to occur in the same NIF call. Read-only binaries do not have to be released.

Binaries are sequences of whole bytes. Bitstrings with an arbitrary bit length have no support yet. It can be stored and passed between processes, but the only real end usage is to pass it back as an argument to a NIF. All resource objects are created as instances of some resource type. This makes resources from different modules to be distinguishable. Resource types are uniquely identified by a supplied name string and the name of the implementing module. The following is a template example of how to create and return a resource object.

Erlang, the code can choose to either keep its own native pointer to the allocated struct and release it later, or release it immediately and rely only on the garbage collector to deallocate the resource object eventually when it collects the term. Another use of resource objects is to create binary terms with user-defined memory management. The destructor of the resource is called when the binary is garbage collected, at which time the binary data can be released. Resource types support upgrade in runtime by allowing a loaded NIF library to take over an already existing resource type and by that « inherit » all existing objects of that type. The destructor of the new library is thereafter called for the inherited objects and the library with the old destructor function can be safely unloaded. Existing resource objects, of a module that is upgraded, must either be deleted or taken over by the new NIF library. The new module instance can, however, choose to load the exact same NIF library as the old code if it wants to.