RE:NODE
Browse hosting

Minecraft15 min read

LuckPerms on a Minecraft server: groups, nodes and contexts

How to set up LuckPerms groups, inheritance, per-world contexts and the web editor on a Paper server, with the permission nodes you will actually need.

0 readers

Operator status is a switch with one position: everything, including the ability to stop the server and edit the world. LuckPerms is how you stop using it. Upload the jar, de-op everybody, build three or four groups, and from then on access is a list you can read, change while the server is running, and hand to a moderator without also handing them /stop. The install takes five minutes. What takes a weekend to work out on your own is the rest of it: how inheritance and weight interact, what a permission node actually is, how contexts let one group behave differently in the creative world, and how to find out why a permission you are certain you granted is being denied. That is what this post is for.

Install LuckPerms and choose its storage#

LuckPerms is one plugin with builds for several platforms, and they are not interchangeable. A Paper or Spigot server wants the Bukkit build; a Velocity or BungeeCord proxy wants its own. Take the jar from luckperms.net, put it in plugins/, and restart the server properly. Do not use /reload for this or for any other plugin install - it half-loads things and produces errors that look like bugs in the plugin.

RE:NODE's Minecraft line runs Paper with the matching Java version already installed, so the Bukkit build is the one you want. Plugins are uploaded by you, through the file manager or over SFTP - there is no plugin installer and no curated plugin list, which also means nothing is blocked. Drag the jar into plugins/ in the file manager, restart from the console, and watch the startup lines.

The first start creates plugins/LuckPerms/config.yml and a database. By default that database is H2, a single file inside the plugin folder, and for one server it is a perfectly good answer. The choice matters when you have more than one server, or when you want to read the data from outside.

storage-methodWhat it isUse it when
h2Default. One file in the plugin folderSingle server, no reason to change
sqliteAnother single-file databaseSame as above
mysql, mariadb, postgresqlRemote SQL serverSeveral servers sharing one permission set
mongodbRemote document databaseSame, if that is what you already run
yaml, json, hocon, tomlFlat files you can open and editYou want the data in git, and accept it is slower

The flat-file modes are tempting because you can read them. They are also the ones people corrupt, by editing users/<uuid>.yml while the server is running and then losing the edit at the next write. If you want a readable copy, keep the database and run /lp export backup instead, which writes a compressed snapshot of every group, user and track into the plugin folder; /lp import backup puts it back. That is worth doing before any large permission change.

/lp info prints the storage method, the messaging service and the plugin version. It is the first command to run when something looks wrong, and the one to paste when you ask for help.

Groups, weight and inheritance#

LuckPerms has exactly one mandatory group, default. Every player is in it unless you move them, and it cannot be deleted. Everything else you build yourself.

code
$ lp creategroup builder$ lp creategroup moderator$ lp creategroup admin$ lp group builder setweight 10$ lp group moderator setweight 50$ lp group admin setweight 100$ lp group moderator parent add builder$ lp group admin parent add moderator

Two mechanisms are doing the work there, and mixing them up is the single most common source of confusion.

Parents are inheritance. parent add gives a group everything its parent has. Under the covers it is stored as a permission node, group.builder, which is why you will see that node in exports and why granting group.vip to a player is the same thing as putting them in the VIP group. Inheritance is transitive, so admin in the example above also has everything builder has.

Weight is tie-breaking. When two groups a player holds both define the same node with different values, the group with the higher weight wins. Weight also decides which prefix is displayed, and the order groups appear in /lp listgroups. Weight does nothing on its own: a heavy group with no nodes grants nothing.

The resolution order, once you have more than a couple of groups, is worth knowing exactly:

  1. Nodes set directly on the user beat anything inherited from a group.
  2. Among groups, the higher weight wins.
  3. Between two values at the same level, a false beats a true - a negation is a deliberate statement and LuckPerms treats it that way.
  4. A wildcard is less specific than an exact node, so essentials.home set to false still applies to someone who has essentials.*.

That last rule is how you build a group that has almost everything: give it the wildcard, then negate the handful of nodes you do not want.

code
$ lp group moderator permission set essentials.* true$ lp group moderator permission set essentials.gamemode false$ lp group moderator permission set essentials.give false

Be careful with a bare *. LuckPerms will resolve it against every permission every plugin has registered, which includes nodes you have never read and nodes that arrive with the next plugin update. Reserve it for a group with one member who is you, and even then prefer listing the plugin wildcards you mean.

The commands you will actually type#

The command is /lp, and /luckperms, /perm, /perms and /permission all work. In the panel console there is no leading slash, because the console is the server's standard input rather than a chat box - the same rule as every other command, covered in the Minecraft server command cheat sheet.

CommandWhat it does
lp creategroup <name>Makes a group
lp listgroupsEvery group, with weight and parents
lp group <g> permission set <node> [true/false]Grants or negates a node
lp group <g> permission unset <node>Removes the node entirely
lp group <g> permission infoLists the group's own nodes
lp group <g> parent add <parent>Inheritance
lp group <g> setweight <n>Tie-break priority
lp group <g> listmembersWho is in it, users and groups
lp user <name> infoGroups, primary group, prefix, meta
lp user <name> parent add <g>Adds a group to a player
lp user <name> parent set <g>Replaces their groups with this one
lp user <name> permission check <node>Result plus where it came from
lp user <name> clearStrips every node and parent back to default
lp search <node>Every user and group holding that node
lp editorOpens the web editor
lp verbose on <filter>Records live permission checks
lp export <file> / lp import <file>Snapshot and restore

Note the difference between unset and set false. unset removes your statement and lets inheritance decide; set false is an active denial that overrides lower-weighted groups. When you want a group to simply not have something, unset is nearly always what you meant.

There is no need to restart or reload after any of these. LuckPerms applies changes immediately, and a player's permissions are recalculated on the spot. Plugins that cache a permission check at login - a few still do - are the exception, and a relog fixes those.

Permission nodes and where to find them#

A node is a lowercase, dot-separated string that a plugin invented. essentials.home is not a standard: it exists because EssentialsX declared it. This is why there is no master list, and why the honest answer to "what is the node for X" is "read the plugin's documentation, or open its jar".

Every Bukkit plugin ships a plugin.yml inside its jar that declares its commands and its permissions with their defaults. Open the jar with any archive tool - the panel's file manager will unpack an archive in place, so you can do it without downloading anything - and read plugin.yml. That file is the authoritative list for that exact version, which documentation often is not.

Nodes you will meet on almost every server:

NodePluginWhat it allows
essentials.home, essentials.sethomeEssentialsXThe home system
essentials.sethome.multiple.vipEssentialsXMore homes, tied to a config entry
essentials.tpa, essentials.tpacceptEssentialsXPlayer teleport requests
essentials.kit.toolsEssentialsXOne named kit
worldedit.*WorldEditAll of WorldEdit. Give it to nobody casually
worldguard.region.claimWorldGuardClaiming a region
coreprotect.inspect, coreprotect.lookupCoreProtectRead the block log
coreprotect.rollbackCoreProtectUndo it. Moderators only
luckperms.editorLuckPermsOpen the web editor
minecraft.command.gamemodePaperThe vanilla /gamemode command

That last row is the pattern for vanilla commands on a Bukkit-derived server: minecraft.command.<name>. minecraft.command.tp, minecraft.command.give, minecraft.command.time and the rest all exist, which means you can hand out /time set day without handing out anything else.

One caveat undercuts all of this if you skip it. In Bukkit, an operator is granted every permission whose declared default is op, and that happens below LuckPerms. A negation you carefully set will not apply to an opped player. De-op everyone, including yourself, and grant luckperms.* plus what you need to an admin group instead. Three config keys in plugins/LuckPerms/config.yml govern the edges of this: enable-ops controls whether the vanilla op system is honoured at all, commands-allow-op decides whether an op may run LuckPerms commands, and auto-op (off by default) makes LuckPerms grant and revoke op status itself based on the luckperms.autoop permission. On a server with a proper group tree, enable-ops: false is the tidy end state - but set your own group up first, or you will lock yourself out and have to fix it from the console.

Contexts: per-world and per-server permissions#

A context is a condition attached to a node. LuckPerms ships two, world and server, and plugins can add more.

code
$ lp group builder permission set worldedit.* true world=creative$ lp group default permission set essentials.tpa false server=survival$ lp user Steve parent add vip server=lobby

world is the name of the world folder, so world, world_nether, world_the_end or whatever your multi-world plugin created. It works out of the box.

server does not, and this catches everyone. Contexts on server are matched against the server: value in config.yml, which defaults to global. Until you change it on each server - server: survival on one, server: lobby on another - every server= context you write will simply never match. Set it before you write a single context, and remember it has nothing to do with the server's name in the MOTD.

Four more config keys decide how global data interacts with contextual data:

  • include-global - whether nodes with no context apply everywhere. Leave it true unless you want every permission to be explicitly scoped.
  • include-global-world - the same question for world contexts.
  • apply-global-groups and apply-global-world-groups - the same two questions for group membership rather than individual nodes.

The reason to touch them is a network where a rank is meant to exist on one server only. With the defaults, a player put in vip with no context is VIP everywhere; that is usually what you want, and the exceptions are better handled by adding the group with a server= context than by changing the global switches.

The web editor#

/lp editor is the feature that makes LuckPerms pleasant. It uploads your current permission data to a temporary paste and gives you a link to a web page where groups, nodes, parents, weights and meta are laid out as a table you can edit, filter, copy and paste between groups. When you are done, the editor either pushes the change straight back to the server, or gives you a /lp applyedits <code> line to paste into chat or the console. Either way nothing changes until you apply it, so the editor is also a safe way to look.

Two practical notes. The editor needs the server to reach bytebin.lucko.me over HTTPS; if outbound requests are blocked, /lp editor fails and the command line is your only option. And the applyedits code is a diff, not a snapshot, so applying an old code after other changes will do something you did not intend. Apply it, or discard it, in the same sitting.

For a bulk change that the editor is bad at - renaming a group everywhere, deleting a node from every user - there is /lp bulkupdate, which runs from the console only and asks for confirmation because it edits every row in the database. Take an export first.

Prefixes, tracks and temporary ranks#

LuckPerms stores a prefix and suffix per group, with a priority number, and does not print them anywhere by itself. This surprises people. The chat format belongs to a chat plugin - EssentialsX Chat, or any plugin that reads Vault or PlaceholderAPI - and LuckPerms supplies the value.

code
$ lp group vip meta setprefix 50 "&6[VIP] &r"$ lp group admin meta setprefix 100 "&c[Admin] &r"$ lp user Steve meta set nickcolour "&b"

The number is the priority: when a player is in several groups, the highest priority prefix is shown. It is deliberately separate from group weight, so you can have a heavy group with no visible tag. For placeholders, %luckperms_prefix%, %luckperms_suffix% and %luckperms_primary_group_name% are available wherever PlaceholderAPI is, which covers most chat, scoreboard and tab-list plugins.

A track is an ordered ladder of groups, and it exists so that promotion is one command instead of two.

code
$ lp createtrack ranks$ lp track ranks append default$ lp track ranks append member$ lp track ranks append trusted$ lp user Steve promote ranks

promote moves the player to the next group on the track and removes the previous one; demote goes back. This is the right shape for a trust ladder, and it is much harder to get wrong than remembering to remove the old group by hand.

Temporary permissions and groups are the other half of good hygiene. A trial moderator should expire on their own:

code
$ lp user Steve parent addtemp moderator 14d$ lp group builder permission settemp worldedit.* true 7d

Durations are written as 30m, 12h, 7d, 2w, 3mo, 1y, and can be combined (1d12h). LuckPerms removes the node when it expires, with no restart and no reminder needed. Use this for every grant that has an end date, because the alternative is a permanent moderator nobody remembers appointing - the exact failure that whitelists, roles and permissions is about.

One permission set across a network#

If you run a proxy, the point of shared storage is that a rank bought in the lobby exists in survival. Three things have to line up.

read and writeVelocity proxyLuckPerms here tooLobbyserver=lobbySurvivalserver=survivalShared databasegroups and users
One permission database behind a small network
  1. The same storage. Set storage-method to a remote database and give every server, including the proxy, the same credentials.
  2. A messaging service. Shared storage alone means each server only notices a change when it next polls, on sync-minutes. Setting messaging-service - sql reuses the database, pluginmsg sends the notification through the proxy, redis needs a Redis server - makes changes propagate in under a second. /lp networksync forces it by hand.
  3. A `server:` value per server. Without it, contexts do not work, as above.

LuckPerms on the proxy matters more than people expect: the proxy is where a player's group is known before any backend sees them, which is what proxy-side commands and per-server whitelists depend on. The wiring for the network itself is in building a Minecraft network with Velocity; the permissions part is just the three items above.

When a permission is not working#

Work through this in order. It is almost always one of the first three.

  • Is the player op? Then Bukkit is granting the node before LuckPerms is consulted, and your negation is invisible. /deop them and test again.
  • Is there a negation you forgot? /lp search essentials.fly lists every group and user holding that node, with its value. This finds the false you set on default six months ago.
  • Is the node spelled exactly right? Nodes are not validated. essentials.homes will be stored happily and grant nothing.
  • Is a context blocking it? Check server: in config.yml on that specific server, and check the world name against the folder name.
  • Does the group actually reach the player? /lp user <name> info prints their groups and primary group. If the group is missing, the parent was added to the wrong group.
  • Is the plugin caching? A relog costs nothing and rules it out.

When none of that explains it, turn on verbose mode, which records every permission check the server makes and what the answer was:

code
$ lp verbose on Steve$ lp verbose paste

The paste is a filterable log of checks: node, result, and the plugin that asked. It answers the question the other tools cannot, which is what node the plugin is checking. Very often it is not the node the documentation names - a command was renamed, or the plugin checks a parent node first. /lp verbose off when you are done, because recording every check on a busy server is not free.

FAQ#

Do I still need to op anyone?

No, and you should not. Give an admin group luckperms.*, the plugin wildcards it needs and minecraft.command.* if you want vanilla commands, then de-op everybody. Keep one op account you never play on, for the day you break your own permissions - or use the panel console, which is not a player and is not subject to permissions at all.

Where does LuckPerms store player data, and what if someone changes their name?

Users are stored by UUID, so a name change carries their permissions with it. LuckPerms keeps a name-to-UUID cache so commands accept names, and it updates on login. For a player who has never joined, use their UUID directly in the command.

Can I edit the files by hand instead of using commands?

Only on the flat-file storage methods, only with the server stopped, and it is a bad habit. The database is the source of truth while the server is running, so a hand edit is overwritten at the next save. Use the web editor for bulk work and /lp export for backups.

Why does my prefix not show up in chat?

Because LuckPerms does not write chat messages. You need a plugin that formats chat and reads the prefix, either through Vault or through the %luckperms_prefix% placeholder. Set the prefix priority as well as the value - two groups with the same priority give an arbitrary winner.

Does LuckPerms cost performance?

Not meaningfully. Permission checks are resolved from memory, and the database is touched on login, on change, and on the sync timer. The cost that does show up is the * wildcard on a server with forty plugins, because it has to be resolved against every registered permission. If you are chasing lag, the culprit is somewhere else - start with why TPS drops and what to do.


Comments

Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.

0/2000