Modding API

Note: This page is outdated. See for up-to-date documentation.

Description of the Lua modding api in Minetest 0.4. (currently experimental)

This page requires more content. If you have any clue about the modding API, feel free to fill in the gaps (or the huge sinkholes, as it is currently).

Introduction and reasonings

From now on, all content in Minetest will be implemented as mods, and C++ holds its position as the engine language.

There is a very important speciality about the Minetest Lua modding API: All mods are run server-side. This means players can connect using the same client to any server and see whole new worlds, without worrying about downloading malicious or incompatible mods.

It also makes a simple modding API, because the modder doesn’t need to handle both sides of the networked system. It is not as flexible, but it is easy. This makes it unique.

It is by no means finished, there are bugs, the API lacks many things, the modding interface will still evolve for some time and documentation is lacking, but it is usable already.

Please do not bitch about client-side modding; if you want to make different kind of stuff to be available for displaying on the client, the open source nature of Minetest has gone nowhere. Code some good C++ to make doing whatever you want in your mods possible to do (and make it reasonably generic to be able to benefit other modders as well) and link the patch to me. -celeron55


The language used is Lua. If you don't know it, just plain google it, and also check out this book and webpage:

Lua essentials for those having programmed in C/C++

Loading of mods

Server loads all mods from its mod path at startup. Mods cannot be loaded at other points of time or unloaded while running.

Client does not touch mods or know anything about them.

Location of mods

A mod is a directory under one of the mod search paths, for example data/mods/examplemod

-- Mod load path
-- -------------
-- Generic:
-- $path_data/mods/
-- $path_userdata/usermods/
-- $mapdir/worldmods/
-- On a run-in-place version (eg. the distributed windows version):
-- minetest-0.4.x/data/mods/
-- minetest-0.4.x/usermods/
-- minetest-0.4.x/world/worldmods/
-- On an installed version on linux:
-- /usr/share/minetest/mods/
-- ~/.minetest/usermods
-- ~/.minetest/world/worldmods

The directory structure of the default mods:

└── mods
    ├── bucket
    │   ├── depends.txt
    │   ├── init.lua
    │   └── textures
    │       ├── bucket_lava.png
    │       ├── bucket.png
    │       └── bucket_water.png
    ├── default
    │   ├── init.lua
    │   └── textures
    │       ├── apple_iron.png
    │       ├── apple.png
    │       ├── book.png
    │       ├── ...
    │       ├── tree_top.png
    │       ├── water.png
    │       └── wood.png
    ├── experimental
    │   ├── depends.txt
    │   └── init.lua
    └── give_initial_stuff
        ├── depends.txt
        └── init.lua


This contains all the textures required by the mod. Everything in this directory is transferred to the client and loaded as images.


For example, if a mod depends on the mods “default” and “somemod” to be loaded for operating correctly:



This contains the Lua code. It is loaded and run at server startup in the same namespace and scope as the previous mods. It is supposed to register all definitions and callbacks and possibly create some variables for holding internal state.

Because examples are fun, here is the init.lua of the mod “bucket”:

-- bucket (Minetest 0.4 mod)
-- A bucket, which can pick up water and lava

minetest.register_alias("bucket", "bucket:bucket_empty")
minetest.register_alias("bucket_water", "bucket:bucket_water")
minetest.register_alias("bucket_lava", "bucket:bucket_lava")

	output = 'bucket:bucket_empty 1',
	recipe = {
		{'default:steel_ingot', '', 'default:steel_ingot'},
		{'', 'default:steel_ingot', ''},

bucket = {}
bucket.liquids = {}

-- Register a new liquid
--   source = name of the source node
--   flowing = name of the flowing node
--   itemname = name of the new bucket item (or nil if liquid is not takeable)
--   inventory_image = texture of the new bucket item (ignored if itemname == nil)
-- This function can be called from any mod (that depends on bucket).
function bucket.register_liquid(source, flowing, itemname, inventory_image)
	bucket.liquids[source] = {
		source = source,
		flowing = flowing,
		itemname = itemname,
	bucket.liquids[flowing] = bucket.liquids[source]

	if itemname ~= nil then
		minetest.register_craftitem(itemname, {
			inventory_image = inventory_image,
			stack_max = 1,
			liquids_pointable = true,
			on_use = function(itemstack, user, pointed_thing)
				-- Must be pointing to node
				if pointed_thing.type ~= "node" then
				-- Check if pointing to a liquid
				n = minetest.env:get_node(pointed_thing.under)
				if bucket.liquids[] == nil then
					-- Not a liquid
					minetest.env:add_node(pointed_thing.above, {name=source})
				elseif ~= source then
					-- It's a liquid
					minetest.env:add_node(pointed_thing.under, {name=source})
				return {name="bucket:bucket_empty"}

minetest.register_craftitem("bucket:bucket_empty", {
	inventory_image = "bucket.png",
	stack_max = 1,
	liquids_pointable = true,
	on_use = function(itemstack, user, pointed_thing)
		-- Must be pointing to node
		if pointed_thing.type ~= "node" then
		-- Check if pointing to a liquid source
		n = minetest.env:get_node(pointed_thing.under)
		liquiddef = bucket.liquids[]
		if liquiddef ~= nil and liquiddef.source == and liquiddef.itemname ~= nil then
			minetest.env:add_node(pointed_thing.under, {name="air"})
			return {name=liquiddef.itemname}



	type = "fuel",
	recipe = "default:bucket_lava",
	burntime = 60,

Some quick terminology

Node = a fixed-positioned cube in the world. Minecraft calls these blocks.

Object = something in the world that is not attached to any particular node or position, can move and act on its own. Examples include mobs, dropped items, falling sand or gravel, primed TNT. Players are also objects.

Entity = an object (see above) that is written in Lua.

Tool item = a type of item that is non-stackable, wears out and improves mining speed or deals more damage. Examples: Pickaxes, axes, shovels, swords.

Node item = a type of item that can be placed as a node (see above). These include dirt, stone, cobble, etc., but also things like torches and signs.

Material item = another name for “Node item”

Craft item = a type of item that can (depending on the item) be eaten, be used in crafting recipes or cooked in a furnace, be placed as objects or be used on things in the world. Examples are (caught) rats, cooked rats, lumps of coal/iron/clay, buckets, and so on.

Node metadata = extra data that is attached to a node. Chests and furnaces use this to store their inventories, and signs use this to store what is written on them.

Environment = A global object that (amongst other things) provides access to all nodes, (active) objects and players.

ABM = An “active block modifier”, these are registered for certain node types and get called regularly (possibly randomized) whenever a player is near such a node. Here, “near” means on the order of 50 meters away, or nearer. For example, an ABM can be used to convert dirt to grass under appropriate conditions.


External API reference

API reference

A quick-and-dirty but mostly up-to-date reference can be found in default/init.lua.

To be added on this page

  • definitions of the {lots of stuff} things and prototype_table
  • definition of recipe={…}
  • definition of the node representation {name=, param1=, param2=}
  • definition of pointed_thing {type=“nothing”}, {type=“node”, under=, above=}, {type=“object”, ref=}
  • definition of itemstring/stackstring (same thing) (eg. 'NodeItem “stone” 3')
  • definition of item {type=“NodeItem”, name=string}, {type=“CraftItem”, name=string}, {type=“ToolItem”, name=string, wear=num}
code/lua_api.txt · Last modified: 2013/01/14 22:47 (external edit)
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki