@Override
    public void init() throws IOException {
        super.init();

        this.users = new CachedLoader(super.dataDirectory.resolve("users" + this.fileExtension));
        this.groups = new CachedLoader(super.dataDirectory.resolve("groups" + this.fileExtension));
        this.tracks = new CachedLoader(super.dataDirectory.resolve("tracks" + this.fileExtension));

        // Listen for file changes.
        FileWatcher watcher = this.plugin.getFileWatcher().orElse(null);
        if (watcher != null) {
            this.watcher = watcher.getWatcher(super.dataDirectory);
            this.watcher.addListener(path -> {
                if (path.getFileName().equals(this.users.file.getFileName())) {
                    this.plugin.getLogger().info("[FileWatcher] Detected change in users file - reloading...");
                    this.users.reload();
                    this.plugin.getSyncTaskBuffer().request();
                } else if (path.getFileName().equals(this.groups.file.getFileName())) {
                    this.plugin.getLogger().info("[FileWatcher] Detected change in groups file - reloading...");
                    this.groups.reload();
                    this.plugin.getSyncTaskBuffer().request();
                } else if (path.getFileName().equals(this.tracks.file.getFileName())) {
                    this.plugin.getLogger().info("[FileWatcher] Detected change in tracks file - reloading...");
                    this.tracks.reload();
                    this.plugin.getStorage().loadAllTracks();
                }
            });
        }
    }
Flat-file storage using Configurate {@link ConfigurationNode}s.
The data for users/groups/tracks is stored in a single shared file.
common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/CombinedConfigurateStorage.java