Configuration

The per-plugin data folder, the built-in config file, and bundled resource files.

Endstone gives each plugin a private data folder and a built-in config file, so you can persist settings and state across restarts without managing paths yourself.

Where files live

A plugin's files live in two places - the package you ship, and the data folder the server creates for it at runtime. In your project, bundle a default config.toml inside the package, next to your code:

pyproject.toml
__init__.py
my_plugin.py
config.toml

The entry point my-plugin becomes the plugin name my_plugin (dashes turn into underscores), and the server gives it a matching data folder under plugins/:

config.toml

self.data_folder points at plugins/my_plugin/. On first run, save_default_config() copies the config.toml you packaged in endstone_my_plugin/ into that folder; anything else your plugin writes lands here too.

The data folder

Every plugin gets its own folder, exposed as self.data_folder - a pathlib.Path that's created for you. Write anything you like into it:

import json

def on_disable(self) -> None:
    scores_file = self.data_folder / "scores.json"
    scores_file.write_text(json.dumps(self.scores))

Configuration

For settings, use the built-in config.toml. self.config returns it as a dict, loading the file on first access:

def on_enable(self) -> None:
    greeting = self.config.get("greeting", "Hello!")
    self.logger.info(greeting)

Ship defaults

Bundle a config.toml with your plugin package and call save_default_config() to write it into the data folder on first run. It does nothing if the file already exists, so a player's edits are never overwritten:

def on_enable(self) -> None:
    self.save_default_config()
    greeting = self.config["greeting"]

reload_config() re-reads the file (filling in packaged defaults for any missing keys), and save_config() writes the current self.config back to disk:

self.config["greeting"] = "Welcome back!"
self.save_config()

Resource files

To ship non-config resources - a data file, a template - call save_resources(path). It copies a file packaged inside your plugin into the data folder, preserving its relative path, and skips files that already exist unless you pass replace=True:

self.save_resources("data/levels.json")

The path is relative to your package, so bundle the file under endstone_my_plugin/:

__init__.py
my_plugin.py
levels.json

It's recreated at the same relative path inside the data folder:

config.toml
levels.json

When flat files aren't enough - you need queries, indexes, or concurrent writes - reach for a database.

On this page