Storing Data

Introduction
Before Minetest 0.4.16, storing data could be done in different ways: Minetest 0.4.16 is a major step forward in that it provides APIs to store information which formerly had to be done using custom code or by abusing existing APIs such as the inventory to store player attributes. This article will give some pointers as to what can be used for what purpose.
 * Node metadata
 * Custom file management
 * Using a (pure) Lua database client library or embedded database
 * Abusing the player or node meta data's inventory to store information

Various Layers for (Meta) Data Storage
The new organization provided by Minetest for storing information is now as follows: If the above mechanisms do not fit your use case, you can always consider:
 * Node metadata is to be used to store extra information for nodes in the world. This mechanism is positional and for nodes
 * Inventory is to be used to store inventory. Older mods still abuse this mechanism for other purposes of course but should migrate to different means of storing data that does not belong in the inventory. This mechanism is for keeping track of chest, player and other inventories
 * Mod metadata a.k.a. mod storage can be used to store information specific to a mod, such as mod state, configuration data (especially when this can be set at runtime) or even in order to externalize tables from the Lua code. This mechanism is mod level and should be kept local to the mod
 * Player attributes should be used to store information specific to the player such as custom mod user preferences, non-core engine player state to be persisted (e.g. hunger, XP, mana) and other player specific data you may wish to store. This mechanism is player level and can be used to migrate away from storing player state/ information in inventories
 * Custom file management. There is nothing wrong with this of course. It's just that when the engine manages things for you, you do not have to worry about the file management yourself and you can use standardized APIs instead of rolling your own
 * Using a Lua database client or embedded database e.g. FlatDB (https://github.com/uleelx/FlatDB), redis-lua (https://github.com/nrk/redis-lua) or a non pure Lua database binding e.g. Lua SQLite if you feel adventurous

Migrating Away from Inventory Based Metadata Storage
This is probably the most important right now due to "inventory abuse", and as such the first example provided here. Consider hbhunger which was built before 0.4.16 and was forced to store state in the player inventory (so please do not consider this example as a critique). In minetest.register_on_joinplayer it had to do:

Where  is called, there is yet more calls to modify the inventory:

And to set the hunger it had  to modify the inventory with new hunger values:

Obviously the initialization where the inventory has to be prepared for usage can be simplified greatly in the new situation by just calling  in its minetest.register_on_joinplayer:

Then  can do:

And  can do something like:

As can be seen, calls to initialize, store and retrieve inventories, item stacks and associated complexities are simplified in more understandable attribute getters and setters.

Migrating Away from Custom Mod Storage
Another example which is more focused on mod settings could be the random_messages mod. This mod comes with a configuration file and one has to copy this file in the world folder. This is a prime example where one could benefit from using a mod storage. The function to read the messages from the world folder is such that:

All I/O can be replaced by a single call to retrieve the mod storage at the top of the init.lua (this is a must!) and then populating the messages table:

If the file in e.g. worlds/yourworld/mod_storage/random_messages was formatted properly you would already be done loading the random messages. What's even better is that you can now add chat commands to manage the messages table and e.g. store the table via mod storage's  when the chat command is run or the server is shutdown. This way you can very easily add messages at runtime without having to restart the server while making sure these messages are persisted across server restarts.