---
name: "menu.lua"
section: "8"
platform: "freebsd"
package: "base"
version: "16.0-CURRENT-20261027-61c70dc16a79"
release: "FreeBSD 16.0-CURRENT (2026-10-27)"
platforms: ["freebsd"]
url: "https://new.carta.tech/menu.lua"
---

# menu.lua(8)

bootloader dynamic menu module

## NAME

**menu.lua** – bootloader dynamic menu module

## DESCRIPTION

**menu.lua** contains the main functionality required to build a dynamic menu system. It also contains definitions for the built-in menus, some of which are influenced by [loader(8)](/loader/8.md) environment variables.

Before hooking into the functionality provided by **menu.lua**, it must be included with a statement such as the following:

```
local menu = require("menu")
```

### MENU DEFINITIONS

Menus are represented in **menu.lua** as a table. That table **must** contain an *entries* key.

If the value of the *entries* key is itself a table, then each value in this table defines a single entry in this menu. See MENU ITEM DEFINITIONS for the structure of each entry.

*entries* may also be a function. This function must return a table, each value of which defines a single entry in this menu. See MENU ITEM DEFINITIONS.

### MENU ITEM DEFINITIONS

The following keys may be defined for a menu item:

- **entry\_type**

  The type of this menu entry. See MENU ITEM TYPES.

- **carousel\_id**

  A unique string id for this carousel. A carousel is a menu entry that rotates through a selection of items. Used for storage of the carousel's current setting.

- **visible**

  A lambda that returns true if this menu item should be visible and false if it should not be visible.

- **items**

  A table (or a lambda that returns a table) of the possible choices for this carousel.

- **name**

  A string (or a lambda that returns a string) containing the current name of this item.

- **func**

  The function executed when this entry is selected. Every type except for **core.MENU\_SEPARATOR** may have a **func**.

- **submenu**

  The submenu menu definition to draw when this entry is selected.

- **alias**

  A table of case-sensitive aliases for this menu entry. All menu entries that can be selected may have any number of **alias** entries.

**entry\_type** is the only required key for every entry type. **name** is required for all entry types except for **core.MENU\_SEPARATOR**.

### MENU ITEM TYPES

The menu item type constants are defined in [core.lua(8)](/core.lua/8.md). The following types are available:

- **core.MENU\_RETURN**

  Return to the parent menu. If the current menu is the default menu, **menu.lua** will exit the menu and begin the autoboot sequence (if applicable). This type of menu entry may execute **func**, when selected, and has a **name**.

- **core.MENU\_ENTRY**

  A normal menu entry that executes **func** when selected, and has a **name**.

- **core.MENU\_SEPARATOR**

  A menu entry that serves as a separator. It may have a **name**.

- **core.MENU\_SUBMENU**

  A menu entry that opens **submenu** when selected. It may have a **name**.

- **core.MENU\_CAROUSEL\_ENTRY**

  A menu entry that rotates through **items** like a carousel. **func** is executed when selected, and the callback is passed the choice index, name of the current choice, and the table of choices.

### EXPORTED MENUS

The following menus are exported by **menu.lua**:

- **menu.default**

  The default menu to draw. Set to **menu.welcome** by default.

- **menu.welcome**

  The welcome menu. Contains single and multi user boot options, as well as entries to access other menus.

- **menu.boot\_options**

  The "Boot Options" menu.

- **menu.boot\_environments**

  The "Boot Environments" menu. This menu is only visible if the system is booted on a ZFS partition and more than one boot environment was detected at boot.

## EXAMPLES

To replace the default boot menu with a simple boot menu:

```
local core = require("core")
local menu = require("menu")
menu.default = {
	entries = {
		{
			entry_type = core.MENU_ENTRY,
			name = "Boot",
			func = core.boot,
		},
		{
			entry_type = core.MENU_CAROUSEL_ENTRY,
			carousel_id = "unique_boot_entry_name",
			items = {"NO", "YES"},
			name = function(_, choice, _)
				return "Option: " .. choice
			end,
			func = function(_, _, _)
				loader.setenv("some_envvar", "some_value")
			end,
		},
	},
}
```

To add another option to the welcome menu:

```
local core = require("core")
local menu = require("menu")
local my_entry = {
	entry_type = core.MENU_ENTRY,
	name = "Fancy Boot",
	func = core.boot,
},
local stock_entries = menu.welcome.entries
function menu.welcome.entries()
	local ents = stock_entries()
	ents[#ents + 1] = my_entry
	return ents
end
```

To create a vendor submenu or other vendor menu option, override **menu.welcome.all\_entires.vendor** like so:

```
local core = require("core")
local menu = require("menu")
-- Fill in with vendor specific entries
local vendor_options = {
	entries = {
	...
	},
}
local welcome_entries = menu.welcome.all_entries
welcome_entries.vendor = {
        entry_type = core.MENU_SUBMENU,
        name = color.highlight("V") .. "endor Options",
        submenu = vendor_options,
        alias = {"v", "V"},
	visible = function()
		return true
	end,
}
```

In the above example, **vendor\_options** is a local variable that defines the vendor submenu.

To add an additional option, change the **menu.boot\_options.entries** array. The following illustrates this concept:

```
-- This is a silly example that rotates local_option through the values
-- 0 to 4.  local_option would still need to be used elsewhere.
local local_option = 0
-- The `entries` of a menu may either be a table or a function.  In this
-- example we're augmenting a menu that just has a static table, but if we
-- wanted to be more robust then we would need to instead check the type
-- of `stock_options` here to determine our next move.
--
-- If `entries` is a table, then the stock menu system won't be changing it
-- so we can just add our menu option as we do below.
--
-- If `entries` is a function, then we would need to provide a new function to
-- replace `entries` that does a core.deepCopyTable() of the result and adds
-- the below item to it.  The deep copy is necessary to avoid duplicating our
-- new menu item and allowing the menu to alter its behavior however it pleases.
local stock_options = menu.boot_options.entries
stock_options[#stock_options + 1] = {
	entry_type = core.MENU_ENTRY,
	name = function()
		return color.highlight('L') ..
		    "ocal Option     : " .. local_option
	end,
	func = function()
		local_option = (local_option + 1) % 5
	end,
	alias= {"l", "L"}
}
```

## SEE ALSO

[loader.conf(5)](/loader.conf/5.md), [core.lua(8)](/core.lua/8.md), [loader(8)](/loader/8.md)

## HISTORY

The **menu.lua** file first appeared in FreeBSD 12.0.

## AUTHORS

The **menu.lua** file was originally written by Pedro Souza ⟨*pedrosouza@FreeBSD.org*⟩. Later work and this manual page was done by Kyle Evans ⟨*kevans@FreeBSD.org*⟩.
