A lightweight runtime loader that lets you write Eluna scripts in Fennel — a Lisp dialect that compiles to Lua.
Drop .fnl files into your server and they compile + run automatically. Supports player/creature events, gossip, and Eluna API helpers out of the box.
I built this just to see if I could. No gameplay reason, no feature request — I just wanted to know: can you embed a Lisp language into Eluna and make it work? Turns out, yes. And it’s surprisingly clean.
👉 See CONTRIBUTING.md for how to get involved.
- Loads the Fennel compiler (
fennel.lua) into Eluna - Exposes Eluna API functions to Fennel scripts
- Dynamically loads all
.fnlfiles from a folder - Supports hot-reloading via
.reload elunaor.reload fennel - Lets you write WoW server logic in Lisp
- Drop
fennel_loader.luaandfennel.luainto your Eluna script folder. - Create a subfolder called
fnl/ - Add your Fennel scripts there. Example:
npc_hello.fnl - Reload Eluna:
.reload eluna - (Optional) If your loader registers a player-login hook, logging in will auto-run all
.fnlfiles.
| File/Folder | Description |
|---|---|
fennel_loader.lua |
Main loader that bootstraps Fennel into Eluna |
fennel.lua |
The Fennel compiler (Lua-only version) |
fnl/ |
Folder for all your Fennel scripts |
This script makes NPC #75 greet the player and give them a Hearthstone.
(do
(local creature-say (. _ENV "creature-say"))
(local player-say (. _ENV "player-say"))
(local player-give-item (. _ENV "player-give-item"))
(local register-gossip-event (. _ENV "register-gossip-event"))
(fn on-hello [event player creature]
(creature-say creature "Hello, traveler!")
(player-say player "Thanks for greeting me!")
(player-give-item player 6948 1)) ;; Hearthstone
(register-gossip-event 75 1 on-hello))
- Loads
fennel.luaand keeps its API table (noinstall()call needed) - For each
.fnlfile:- Reads source
compileString→ Lualoadthe compiled Lua with a custom_ENVthat includes Eluna helpers- Executes the chunk
This lets .fnl scripts call Eluna exactly like Lua does.
This is the most common Fennel error when starting out. It means you wrote something like:
(fn on-hello[event player creature] ...) ;; ❌ no space before [
✅ Fix: Always put a space before opening brackets:
(fn on-hello [event player creature] ...) ;; ✅ correct
This means your Fennel script is trying to call a function that wasn’t injected into the environment.
✅ Fix: Make sure your loader exposes Eluna functions like this:
env["register-gossip-event"] = function(entry, event, fn)
RegisterCreatureGossipEvent(entry, event, fn)
end
And in Fennel, bind them using:
(local register-gossip-event (. _ENV "register-gossip-event"))
Check that your .fnl file is inside the correct folder:
wotlk-server-lua/fnl/
✅ Fix: Run .reload eluna or .reload fennel in-game to trigger the loader.
Make sure you’re using the correct NPC entry ID in your script:
(register-gossip-event 75 1 on-hello)
✅ Fix: Replace 75 with the actual entry ID of your NPC in the database.
Try adding a debug print to your Fennel script:
(local print (. _ENV "print"))
(print "Fennel script loaded!")
If you see the message in your server console, the script is running.
This project was built out of curiosity — but if you find it useful, feel free to modify, extend, or adapt it however you like.
If you run into issues, have ideas for improvements, or want to add examples (like branching dialogs or quest logic), I’d love to see them. Pull requests, bug reports, and suggestions are all welcome.
Let’s see what Fennel can do in Azeroth.
MIT — same license used by Fennel. Feel free to use, modify, or build on it.