Skip to content

Lua: Evaluation

Tin Švagelj edited this page Apr 23, 2026 · 4 revisions

Using Lua Scripts in Conky

This guide covers how Conky loads and runs Lua scripts. It assumes basic familiarity with editing configuration files. If you're new to Lua itself, see Lua Basics for the language fundamentals. Lua also provides its own manual for comprehensive reference.

Lua is one of the simplest scripting languages. It's got some minor quirks (like 1-based array indexing), but it should be easy to understand for most digitally literate people.

1. Loading Lua Scripts

To integrate Lua scripts into Conky they have to be loaded using lua_load in the conky.conf file:

conky.config = {
  lua_load = "path/to/script.lua"
  -- other settings
}

The config file is usually placed in ~/.config/conky/conky.conf. On a fresh install it might need to be copied over from /etc/conky/conky.conf.

lua_load specifies the paths to the Lua scripts that Conky will execute. These paths can be relative if the script is placed in the same directory as conky.conf (e.g. lua_load = "./script.lua"), or an absolute path (e.g. lua_load = "/home/username/scripts/script.lua").

Multiple files may be loaded — use a semicolon (;) as the file path separator.

If Inotify is supported by the system (it is for most Linux distributions), these files should reload automatically when they're changed. This depends on the Conky build environment (of the package vendor).

Lua File Placement

Lua script files should be placed in a directory where Conky can access them. Most commonly, people place Conky scripts alongside the config file because that makes them easier to edit, copy and store on git.

If Conky is unable to load the file, double-check the file path. If it's correct, use system utilities like ls, chown and chmod to ensure the file can be read by Conky. For details on Linux file permissions check out this useful guide by Red Hat.

2. Lua Hooks

While lua_load loads Lua scripts, Conky allows executing functions from the scripts using hooks. Hooks are called as part of the update cycle of the window, as well as on startup/closing and for some events. All Lua hooks start with lua_ and can be found in the Conky documentation.

To connect a Lua function to a hook, specify the function name as the hook value:

conky.config = {
  lua_load = "script.lua",
  -- other settings
  lua_draw_hook_post = "main",
}

Important

The function name in the Lua file must be prefixed with conky_. So lua_draw_hook_post = "main" will call conky_main() in the script.

List of Common Lua Hooks

For drawing, the most important hooks are lua_draw_hook_* — these allow a Lua script to render content in the Conky window:

  • lua_draw_hook_pre: Runs the function before main content (specified in conky.text block) is drawn.
    • Intended for drawing background graphics that should appear below text.
  • lua_draw_hook_post: Runs the function after the Conky window is drawn.
    • Intended for drawing over everything else.

Warning

Drawing functionality can be disabled at compile time. If the installed Conky version doesn't have drawing capabilities, draw hooks will silently do nothing. Some distributions offer various flavors of the Conky package with different features enabled — make sure to pick the appropriate one. Check your Linux distribution's documentation for installation instructions.

Conky also provides some additional hooks for specific use cases:

  • lua_startup_hook: Runs once when Conky starts.
    • Intended for collecting immutable system data or preconfiguring things in Lua that might be expensive to do every update.
  • lua_shutdown_hook: Runs once when Conky exits.
    • Intended for cleanup of temporary files or resources that were created from the startup hook.
  • lua_mouse_hook: Captures mouse events within the Conky window. Covered in detail in Mouse Events.
    • Intended for adding interactivity to Conky.

These are all the supported hooks at the moment, but more might be added in future. See lua_ prefixed variables in the documentation to check if anything else has been added in the meantime, or create a feature request.

Caution

Some events (dragging windows, overlapping Conky instances) can trigger additional calls to draw hooks beyond the normal update cycle. This can cause issues if your script accumulates data on every call (e.g. pushing values into a history table). To guard against this, use a time-based interval to ensure data collection runs at most once per real second — see Time-Based Intervals.

3. Writing a Basic Lua Script

Let's go step by step through a simple Lua script and explain what each part does before presenting the final code.

3.1. Adding Required Libraries

At the top of the script, load the external libraries needed for drawing:

require("cairo")

This loads bindings from the Cairo library which is used for rendering in Conky.

Other bindings like rsvg and imlib2 add their own libraries that can be required from Lua. See Image Rendering for details on image rendering.

Note

During transition period, require("cairo_xlib") was used to import X11-specific functions, this is no longer needed. conky_surface() works for both X11 and Wayland and is provided by conky directly. See Creating the Drawing Surface.

3.2. Defining the Main Function

The lua_draw_hook_post = "main" setting expects a conky_main function to be defined in one of the lua_loaded files. Missing this will cause warnings/errors:

function conky_main()
  -- drawing code goes here
end

3.3. Creating the Drawing Surface

All drawing in Cairo happens on a surface. conky_surface() returns the current Cairo surface for the active display output, or nil if no graphical surface is available:

local surface = conky_surface()
if not surface then return end
local cr = cairo_create(surface)

The surface returned by conky_surface() is only valid for the current draw cycle. Call it each time your draw hook is invoked — do not cache it across frames.

cr is the drawing context used for all rendering.

Tip

It's common to give the drawing context a short name like cr or ctx because it appears in almost every drawing call. The examples in this wiki use cr throughout.

Note

Older scripts created the surface manually using X11-specific functions:

require("cairo_xlib")
local surface = cairo_xlib_surface_create(
    conky_window.display, conky_window.drawable,
    conky_window.visual, conky_window.width, conky_window.height)

This still works on X11 but is deprecated. The conky_window.display, conky_window.drawable, and conky_window.visual fields are X11-specific and will be removed in a future release.

3.4. Using Conky Variables in Lua

conky_parse() evaluates Conky variables from Lua. It processes the same syntax used in conky.text and returns the fully evaluated result as a string.

Simple variable access:

local cpu_usage = conky_parse("${cpu}")
local memory_used = conky_parse("${memperc}")
local disk_space = conky_parse("${fs_used /home}")

conky_parse() isn't limited to single variables — it can evaluate the full Conky text syntax, including conditionals, multiple variables, and formatting:

-- Conditional evaluation
local net_status = conky_parse("${if_up wlan0}Online${else}Offline${endif}")

-- Combining multiple variables into a formatted string
local summary = conky_parse("${cpu}% @ ${freq_g}GHz")

-- Conditionals with nested variable substitution
local charge = conky_parse(
    "${if_match ${battery_percent} > 20}OK${else}Low${endif}"
)

Use tonumber() to convert the result when you need numeric values for calculations. See Dynamic Content in the drawing guide for practical examples.

3.5. Cleaning Up Resources

The drawing context created with cairo_create() must be destroyed at the end of each draw hook. Not doing so will cause Conky to consume more and more memory over time (a memory leak):

cairo_destroy(cr)

Note

The surface from conky_surface() is managed by Conky — do not call cairo_surface_destroy() on it. Only destroy the cairo_t context you created. Older scripts that create their own surface via cairo_xlib_surface_create() do need to destroy it.


Now that each part is explained, here is the complete script:

-- ~/.config/conky/script.lua

require("cairo")

function conky_main()
    local surface = conky_surface()
    if not surface then return end
    local cr = cairo_create(surface)

    local updates = tonumber(conky_parse("${updates}"))
    if updates > 5 then
        print("conky_main counted >5 updates to its window")
    end

    cairo_destroy(cr)
end

This script checks the update count and prints debug information to the console after 5 updates. From here, see Drawing with Cairo for how to render text, shapes, and data-driven widgets.

4. Order of Evaluation

As Lua is called by Conky, it's important to detail how precisely it gets executed. Normally, Lua runtime has a single entry point script and just runs the code from that script. In Conky this is also pretty much the case (except for hooks), and the entry point is ~/.config/conky/conky.conf file, or some other config file provided to Conky with -c command line argument:

conky -c "./my custom.config"

When Conky starts, it will do some work in the background to create a window and set up the Lua context. Before anything else happens, Conky will load and run the config file in order to get conky.config and conky.text variable values.

As the config file is technically a Lua script, it can contain code and variables. This means that both conky.config and conky.text can contain variables instead of discrete values.

This allows things like constructing the final conky.config by joining multiple Lua tables together, and concatenating strings into the final conky.text. These variables are read only once after Conky is done evaluating the entry script, so changing their values later will have no effect on Conky's output/rendering.

As the main configuration file is a script, other scripts can be required at the top of it.

After the main config file is evaluated, Conky will process the conky.config value, and evaluate all files listed in lua_load.

Finally, if specified, the function named in lua_startup_hook will get called (with the added conky_ prefix).

After that, Conky enters the draw loop where it continuously calls draw hooks and draws the contents of previously stored conky.text.

When it receives a signal to close, the function from lua_shutdown_hook is called. This function shouldn't be relied on to always run, as it will not be called if Conky crashes or is abruptly terminated by the system. It can be used to clean up resources or store some non-critical data however.

When passing data from one run to the next, the startup hook should always check whether data that was supposed to be provided by the shutdown hook is available.

5. LUA_PATH Contents

At startup, Conky appends the following paths to LUA_PATH:

  • XDG config directory (~/.config/conky/?.lua)
  • Script parent directory (e.g. ./script/parent/directory/?.lua)

That means require will be able to locate any scripts that are next to the used config file, as well as all scripts stored in the Conky XDG config directory.

Clone this wiki locally