Paper Plugin Guide
File mode0

Start here

IntelliJ survival guide

The handful of IntelliJ features that make writing plugins much easier.

Beginner28 min read

IntelliJ IDEA has hundreds of features, but you only need about a dozen to write plugins comfortably. This page teaches those: finding your way around the window, letting IntelliJ finish your code, fixing red errors with one key, reading Paper's own documentation, and running your test server. Learn these and the editor starts doing half the typing for you.

A tour of the window

Open any plugin project (FileOpen, then pick the project's folder, the one that contains build.gradle.kts). The first time, IntelliJ may ask whether you trust the project; choose Trust Project, because Gradle needs to run to set it up. Wait for the progress bar at the bottom right to finish.

The IntelliJ window with a plugin project open: the project tree on the left, the editor in the middle, the run toolbar at the top and tool windows along the edges.

These are the parts you will use, and the keys that open them. Each tool window opens and closes with the same shortcut, and you can also click its icon on the window's edge.

PartWhereOpen withWhat it is for
Project treeLeftAlt+1All the folders and files of your project. Double-click a file to open it.
EditorMiddleEsc jumps back to itWhere you write code. Each open file gets a tab at the top.
Run toolbarTop rightShift+F10 runsPick a run configuration (Run Paper Server, Build Plugin Jar) and press Run, Debug or Stop.
Run windowBottomAlt+4The output of what you ran: for your test server, its console.
Gradle windowRight (elephant icon)click the iconEvery Gradle task, and the button to reload the project.
TerminalBottomAlt+F12A PowerShell terminal, already in your project folder.
ProblemsBottomAlt+6A list of every error and warning in the open file and the project.
The project tree. Your code lives under src/main/java, and plugin.yml under src/main/resources.

For the rest of this page, open the practice project: download it, unzip it, and open the folder in IntelliJ. It is a small plugin with one listener, so you can try every shortcut on real plugin code. Here is the listener you will work on:

GiftListener.javaCompiles on Paper 26.3Compile Lab
Where this file livesintellij-tips-practicesrcmainjavacomexampleintellijtipspracticeGiftListener.java

The package com.example.intellijtipspractice is the folder path com/example/intellijtipspractice inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.

  • intellij-tips-practice/
    • src/main/
      • java/com/example/intellijtipspractice/Package com.example.intellijtipspractice
        • GiftListener.javayou are hereListener: reacts to events
        • PracticePlugin.javaMain class: Paper starts here (named as main in plugin.yml)
      • resources/Files copied into the jar as they are
        • plugin.ymlTells Paper the plugin's name, version and main class
    • build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
    • gradle.propertiesVersion numbers used by the build
    • gradlew.batRuns Gradle on Windows without installing it
    • settings.gradle.ktsThe project's name

Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.

1package com.example.intellijtipspractice;2 3import org.bukkit.entity.Player;4import org.bukkit.event.EventHandler;5import org.bukkit.event.Listener;6import org.bukkit.event.player.PlayerJoinEvent;7 8public final class GiftListener implements Listener {9 10    @EventHandler11    public void onJoin(PlayerJoinEvent event) {12        Player player = event.getPlayer();13        player.sendRichMessage("<green>Welcome! <gray>A gift is waiting for you.");14    }15}
  1. An import tells Java which library a name such as Player comes from. IntelliJ writes these lines for you, as you will see below.
  2. This class listens for events.
  3. Runs when a player joins. You will add to this method in this page's exercise.
  4. Sends a colored chat message to the player.

Autocomplete: let IntelliJ type for you

Autocomplete (IntelliJ calls it code completion) is the feature you will use most. As you type, IntelliJ shows a list of everything that fits at that spot. Pick an entry with the arrow keys and press Enter or Tab, and IntelliJ writes the full name, correctly spelled.

Type a dot to discover what something can do

This is the trick that makes the Paper API learnable. In onJoin, start a new line under the sendRichMessage line and type player. (with the dot). IntelliJ lists everything a Player can do: getHealth, setGameMode, teleport, giveExpLevels, hundreds of methods (the named actions an object can do). Keep typing to filter the list: player.give shows only the methods with "give" in them.

After typing player.give, IntelliJ lists the matching methods with their parameters on the left and what they return on the right.

Each entry shows the method's name, the values it needs in brackets, and on the right what it gives back. You do not need to memorize the Paper API. You need to know which object to ask (the player, the event, the server), then type a dot and read.

  • Ctrl+Space opens the list on purpose, for example when you closed it or want suggestions before typing anything.
  • Ctrl+P, with the cursor inside a method's brackets, shows which values (parameters) that method expects, and highlights the one you are typing now.
  • Ctrl+Q on a selected entry shows its documentation, so you can read what a method does before you pick it.

Autocomplete works for event names too. Type PlayerJoin in a method's brackets and IntelliJ offers PlayerJoinEvent, and when you pick it, it also adds the import line at the top of the file for you.

Red squiggles and Alt+Enter

IntelliJ checks your code while you type. When something is wrong, it underlines it:

  • Red: an error. The plugin will not compile until you fix it.
  • Yellow or gray: a warning or a suggestion. The code compiles, but something could be better, such as a variable you never use.
  • Strikethrough (a line through a name): the method or class is deprecated, meaning there is a newer way and the old one may disappear. In Paper 26.3 you will see this on old tutorial code such as ChatColor. Use the modern way that this guide teaches.

Hover the underlined code to read the problem in a tooltip, or press F2 to jump to the next error in the file.

Hovering a red name shows the error: Cannot resolve symbol 'Sound'. The tooltip also offers a fix.

The magic key: Alt+Enter

Put the cursor on anything underlined and press Alt+Enter. IntelliJ shows a short list of quick fixes and, most of the time, the first one is exactly what you need. The three you will use constantly:

The problemWhat Alt+Enter offers
A class name is red because it is not imported, like SoundImport class. It adds the import line at the top. If several classes have that name, it asks which one.
You called a method that does not exist yet, like sendWelcome(player)Create method. It writes an empty method with the right parameter for you to fill in.
A value has the wrong type, like a decimal number where a whole number is neededCast or change the variable's type. Read the options; the right fix depends on what you meant.
Alt+Enter on a red class name. Pick Import class and IntelliJ writes the import line for you.

Here is the most common red error of all. This code uses Sound without importing it:

GiftListener.java (missing import)Has a mistake
1player.giveExpLevels(5);2player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f);

IntelliJ underlines Sound in red right away. If you build anyway, the compiler stops with this message:

Build output
> Task :compileJava FAILEDC:\Users\jacec\IdeaProjects\intellij-tips-practice\src\main\java\com\example\intellijtipspractice\GiftListener.java:15: error: cannot find symbol        player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f);                                 ^  symbol:   variable Sound  location: class GiftListener1 errorFAILURE: Build failed with an exception.

"Cannot find symbol" means "I do not know this name". Either it is misspelled or it is not imported. Press Alt+Enter on Sound, choose Import class, and pick org.bukkit.Sound.

The best documentation for Paper is Paper's own code, and IntelliJ lets you jump straight into it.

KeysWhat it doesWhen to use it
Ctrl+click (or Ctrl+B)Go to where a name is defined. On sendRichMessage it opens the Paper source file with that method and its description."What exactly does this method do, and what else is next to it?"
Ctrl+QQuick documentation in a popup, without leaving your file. Hovering a name for a moment shows the same."What does this method return? Can it be null?"
Ctrl+Alt+LeftGo back to where you were before you jumped.After a Ctrl+click adventure.
Shift Shift (press twice)Search Everywhere: find any class, file, setting or action by name."Open PlayerJoinEvent." "Where is plugin.yml?"
Ctrl+Shift+FFind in Files: search for text in every file of the project."Where do I send the message that contains 'gift'?"
Ctrl+ERecent files.Jumping between the two or three files you are working on.
Ctrl+F12File structure: a list of the methods in the current file.Big classes with many event handlers.

When you Ctrl+click a Paper class, IntelliJ may first show a "decompiled" version, rebuilt from the compiled bytecode without any descriptions. If you see a banner at the top with Download Sources, click it: IntelliJ fetches the real Paper source code, with every description (called Javadoc) that the Paper developers wrote. Those descriptions are often the best explanation of a method anywhere.

Refactoring and tidying

Refactoring means changing how code is organized without changing what it does: renaming things, moving them, cleaning them up. IntelliJ does it safely, everywhere at once.

KeysWhat it does
Shift+F6Rename a variable, method, class or file, and update every place that uses it. Never rename by hand: you will miss one.
Ctrl+Alt+LReformat code: fixes indentation and spacing in the whole file. Press it whenever code looks messy.
Ctrl+Alt+OOptimize imports: removes imports you no longer use and sorts the rest.
Ctrl+OOverride methods: lists methods you can add from the parent class. In your main class, this is how you add onDisable without typing it.
Ctrl+D / Ctrl+YDuplicate the current line / delete the current line. Handy for adding a second sendRichMessage line.
Ctrl+Z / Ctrl+Shift+ZUndo / redo. IntelliJ remembers a lot of history, so experiment freely.

Gradle inside IntelliJ

IntelliJ reads your Gradle files to learn where the Paper API is and which Java to use. When you change a build file (build.gradle.kts, settings.gradle.kts or gradle.properties), IntelliJ does not reread it on its own. A small floating button with the Gradle elephant appears in the editor: click it, or press Ctrl+Shift+O, to load the Gradle changes.

After editing a build file, the floating Load Gradle Changes button appears. Click it (or press Ctrl+Shift+O).

The Gradle tool window (the elephant icon on the right) lists every task the project knows. The two you care about are Tasks > build > build (builds the jar) and Tasks > Run Paper > runServer (starts the test server). Double-click a task to run it. The reload button at the top of this window (two circling arrows) does the same as Ctrl+Shift+O.

The Gradle tool window with the build and runServer tasks, and the reload button at the top.

When Gradle sync goes wrong

If every Paper name is suddenly red (JavaPlugin, Player, everything), IntelliJ has lost track of the Paper API. Work through these in order, and stop as soon as it is fixed:

  1. Reload the Gradle project (Ctrl+Shift+O, or the reload button in the Gradle window) and read the Build window at the bottom. A real error there, such as a typo in build.gradle.kts or no internet connection, is the actual cause.
  2. Check you opened the right folder: the one with build.gradle.kts in it, not its parent.
  3. Check the Gradle JVM: FileSettingsBuild, Execution, DeploymentBuild ToolsGradle, and set Gradle JVM to your Java 25.
  4. As a last resort: FileInvalidate Caches..., tick nothing extra, and click Invalidate and Restart. IntelliJ throws away its memory of the project and rebuilds it. It takes a while, which is why it is the last step, not the first.

Run configurations: run and debug your server

A run configuration is a saved "what to run" choice. The guide's projects (and the paper-templates on Jace's PC) come with two, in the drop-down at the top right of the window:

  • Run Paper Server runs the Gradle task runServer. It downloads Paper 26.3 the first time, builds your plugin, and starts a real server in the project's run folder with your plugin already installed. Join it from Minecraft 26.3 at localhost.
  • Build Plugin Jar runs the Gradle task build. The jar lands in build\libs, ready to copy to another server.
The run toolbar: pick Run Paper Server in the drop-down, then press the green Run arrow, or the bug icon to debug.

Next to the drop-down are three buttons: the green arrow Run (Shift+F10), the bug Debug (Shift+F9) and the red square Stop (Ctrl+F2).

While the server runs, the Run window at the bottom is its console. You can type server commands there (without the slash), such as op Steve or plugins, and press Enter.

The Run window shows the test server's console. Type commands into it, such as op Steve or stop.

Debug starts the same server, but lets you pause your plugin at any line. Click in the gray margin left of a line number to set a red dot, a breakpoint, then join the server. When that line is about to run, the server pauses and IntelliJ shows every variable's value at that moment. It is the best way to understand why code does something unexpected. Debugging like a pro teaches it step by step.

Paused at a breakpoint in onJoin. The Debug window shows the event and player variables and their values.

Shortcut cheat sheet

All shortcuts are for Windows with IntelliJ's default keymap. If you forget one, press Ctrl+Shift+A (Find Action) and type what you want to do, such as Reload All Gradle Projects or Invalidate Caches; the shortcut is shown next to each result.

KeysAction
Ctrl+SpaceAutocomplete
Ctrl+PShow the parameters a method expects
Alt+EnterQuick fix (import, create method, fix types)
F2Jump to the next error
Ctrl+click / Ctrl+BGo to definition (read the API source)
Ctrl+QQuick documentation
Ctrl+Alt+LeftGo back
Shift ShiftSearch Everywhere
Ctrl+Shift+FFind in Files
Ctrl+ERecent files
Ctrl+F12File structure
Shift+F6Rename everywhere
Ctrl+Alt+LReformat code
Ctrl+Alt+OOptimize imports
Ctrl+OOverride methods (add onDisable)
Ctrl+D / Ctrl+YDuplicate line / delete line
Ctrl+Shift+OLoad Gradle changes
Shift+F10 / Shift+F9Run / Debug the selected run configuration
Ctrl+F2Stop
Alt+1 / Alt+4 / Alt+6 / Alt+F12Project tree / Run window / Problems / Terminal
Ctrl+Alt+SSettings
Ctrl+Shift+AFind Action (search for any command)

Common beginner traps

Editing files outside src/main

Your plugin is made only from what is inside src/main. Two other folders look tempting but are generated:

  • build is Gradle's output. Anything you change there is overwritten by the next build.
  • run is the test server. Its plugins folder holds a copy of your plugin's files. If your plugin saves a config.yml, the server's copy lives in run\plugins\YourPlugin\config.yml. Editing the one in src/main/resources later does not change that copy, because a plugin only writes its default config when none exists yet. Delete the server's copy to get the new default.

Wrong JDK selected

If IntelliJ complains about the Java version ("release version 25 not supported", or modern Java code underlined in red although it builds fine with Gradle), check two settings:

  • FileProject StructureProject: SDK should be a Java 25 JDK (IntelliJ calls a JDK an SDK, software development kit). If 25 is not in the list, choose Add SDK > JDK and pick the Temurin 25 folder.
  • FileSettingsBuild, Execution, DeploymentBuild ToolsGradle: Gradle JVM should be Java 25 too.
File, Project Structure, Project: the SDK should be a Java 25 JDK.

Files not saved

IntelliJ saves automatically: when you run something, switch to another program, or after a short pause. So you rarely need Ctrl+S. The trap is the other direction: if you edit a project file in another program (Notepad, File Explorer), IntelliJ may still show the old version for a moment. Edit project files in IntelliJ only, and if you did change something outside, use FileReload All from Disk.

plugin.yml in the wrong folder

The server only finds plugin.yml if it ends up at the top of the jar, and it only gets there from src/main/resources:

  • intellij-tips-practice/
    • plugin.ymlWRONG: the project folder itself is not packed into the jar
    • src/
      • main/
        • java/
          • com/example/intellijtipspractice/
            • plugin.ymlWRONG: this folder is for Java code only
            • PracticePlugin.java
            • GiftListener.java
        • resources/
          • plugin.ymlRIGHT: everything here is copied to the top of the jar

With plugin.yml anywhere else, the server refuses to load the jar with an error that it does not contain a plugin.yml. To be sure, right-click src/main/resources in the project tree and create the file there with NewFile.

Opening the wrong folder

If you open a folder that contains several projects (for example all of paper-templates, or your whole IdeaProjects), IntelliJ does not find a build.gradle.kts at the top, so nothing gets set up and all the code stays red. Close it with FileClose Project and open the single project folder instead.

Try it

A gift on join, typed with autocomplete

In the practice project's GiftListener, make joining players receive 5 experience levels, hear the experience orb sound, and see a gold message "You received 5 experience levels!". The rule: type as little as possible. Use autocomplete for every name, and Alt+Enter for the import. Then run Run Paper Server, join at localhost and check it.

Hint 1

Start a new line under the sendRichMessage line and type player.give. Which method gives levels, not raw experience points?

Hint 2

For the sound, type player.playS and pick the version of playSound that takes an entity (the player), a Sound and two numbers. Press Ctrl+P inside the brackets to see what each value means. Then type Sound.ENTITY_EXP for the sound.

Hint 3

The two numbers are the volume and the pitch. 1.0f means normal for both; the f marks a decimal number of the type float.

Show the solution

Three new lines in onJoin and one new import, which Alt+Enter adds for you:

GiftListener.javaCompiles on Paper 26.3Compile Lab
Where this file livesintellij-tips-exercisesrcmainjavacomexampleintellijtipsexerciseGiftListener.java

The package com.example.intellijtipsexercise is the folder path com/example/intellijtipsexercise inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.

  • intellij-tips-exercise/
    • src/main/
      • java/com/example/intellijtipsexercise/Package com.example.intellijtipsexercise
        • GiftListener.javayou are hereListener: reacts to events
        • PracticePlugin.javaMain class: Paper starts here (named as main in plugin.yml)
      • resources/Files copied into the jar as they are
        • plugin.ymlTells Paper the plugin's name, version and main class
    • build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
    • gradle.propertiesVersion numbers used by the build
    • gradlew.batRuns Gradle on Windows without installing it
    • settings.gradle.ktsThe project's name

Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.

1package com.example.intellijtipsexercise;2 3import org.bukkit.Sound;4import org.bukkit.entity.Player;5import org.bukkit.event.EventHandler;6import org.bukkit.event.Listener;7import org.bukkit.event.player.PlayerJoinEvent;8 9public final class GiftListener implements Listener {10 11    @EventHandler12    public void onJoin(PlayerJoinEvent event) {13        Player player = event.getPlayer();14        player.sendRichMessage("<green>Welcome! <gray>A gift is waiting for you.");15        player.giveExpLevels(5);16        player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f);17        player.sendRichMessage("<gold>You received 5 experience levels!");18    }19}
  1. Added by Alt+Enter, Import class. Make sure it is org.bukkit.Sound.
  2. Adds 5 whole levels to the green bar. giveExp would add 5 experience points instead, which is barely visible.
  3. Plays the sound at the player's position: who or where, which sound, volume, pitch.
  4. The confirmation message, in gold.
Steve joined the game
Welcome! A gift is waiting for you.
You received 5 experience levels!

Notice how much of that you did not have to know in advance. You knew the object (player), typed a dot, and let IntelliJ show you the rest. That is how experienced developers work with the Paper API every day.

Try it

Ctrl+click detective

In GiftListener, hold Ctrl and click sendRichMessage. Which file opens? Read the description above the method: what format does it say the message uses? Then press Ctrl+Alt+Left to come back.

Hint

The file's name is shown in the editor tab. If you see a "Download Sources" banner, click it first to see the descriptions.

Show the solution

It opens CommandSender.java, and the description says the message uses the MiniMessage format, with a link to the MiniMessage docs. That tells you two useful things:

  • sendRichMessage belongs to CommandSender, which means anything that can send commands has it: players and the server console alike. A Player is a kind of CommandSender, which is why player.sendRichMessage works. You will learn how one type can be a "kind of" another in Inheritance and interfaces.
  • The tags like <green> are MiniMessage, explained in MiniMessage: easy formatted text.

You just answered a question by reading the API itself. Whenever you wonder "where does this come from?", Ctrl+click it.

Recap

  • Know the window: project tree (Alt+1), editor, run toolbar, Run window (Alt+4), Gradle window, terminal (Alt+F12), Problems (Alt+6).
  • Type an object and a dot to see everything it can do; Ctrl+Space and Ctrl+P help further.
  • Red means error. Alt+Enter fixes most of them, especially missing imports; check you picked the right package.
  • Ctrl+click opens the Paper source and its descriptions; Ctrl+Q shows them in a popup.
  • Rename with Shift+F6 (then check plugin.yml), tidy with Ctrl+Alt+L and Ctrl+Alt+O.
  • Load Gradle changes after editing build files; Invalidate Caches is the last resort.
  • Run Paper Server starts a test server with your plugin; stop it by typing stop. Debug lets you pause at breakpoints.
  • Only edit files in src/main, keep plugin.yml in src/main/resources, and use Java 25 as the project SDK and Gradle JVM.

Quick quiz

  1. You want to know what a Player can do, but you do not know any method names. What is the fastest way?

  2. The word Sound is red, and the build says "cannot find symbol". What is the most likely fix?

  3. You added a library to build.gradle.kts, but IntelliJ still underlines its classes in red. What did you forget?

  4. You renamed your main class with Shift+F6. What should you check right after?

  5. What is the safest way to stop the test server started with Run Paper Server?

Next steps