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

        this.users.directory = MoreFiles.createDirectoryIfNotExists(super.dataDirectory.resolve("users"));
        this.groups.directory = MoreFiles.createDirectoryIfNotExists(super.dataDirectory.resolve("groups"));
        this.tracks.directory = MoreFiles.createDirectoryIfNotExists(super.dataDirectory.resolve("tracks"));

        // Listen for file changes.
        FileWatcher watcher = this.plugin.getFileWatcher().orElse(null);
        if (watcher != null) {
            this.users.watcher = watcher.getWatcher(this.users.directory);
            this.users.watcher.addListener(path -> {
                String fileName = path.getFileName().toString();
                if (!fileName.endsWith(this.fileExtension)) {
                    return;
                }

                String user = fileName.substring(0, fileName.length() - this.fileExtension.length());
                UUID uuid = Uuids.parse(user);
                if (uuid == null) {
                    return;
                }

                User u = this.plugin.getUserManager().getIfLoaded(uuid);
                if (u != null) {
                    this.plugin.getLogger().info("[FileWatcher] Detected change in user file for " + u.getPlainDisplayName() + " - reloading...");
                    this.plugin.getStorage().loadUser(uuid, null);
                }
            });

            this.groups.watcher = watcher.getWatcher(this.groups.directory);
            this.groups.watcher.addListener(path -> {
                String fileName = path.getFileName().toString();
                if (!fileName.endsWith(this.fileExtension)) {
                    return;
                }

                String groupName = fileName.substring(0, fileName.length() - this.fileExtension.length());
                this.plugin.getLogger().info("[FileWatcher] Detected change in group file for " + groupName + " - reloading...");
                this.plugin.getSyncTaskBuffer().request();
            });

            this.tracks.watcher = watcher.getWatcher(this.tracks.directory);
            this.tracks.watcher.addListener(path -> {
                String fileName = path.getFileName().toString();
                if (!fileName.endsWith(this.fileExtension)) {
                    return;
                }

                String trackName = fileName.substring(0, fileName.length() - this.fileExtension.length());
                this.plugin.getLogger().info("[FileWatcher] Detected change in track file for " + trackName + " - reloading...");
                this.plugin.getStorage().loadAllTracks();
            });
        }
    }
Flat-file storage using Configurate {@link ConfigurationNode}s.
The data for each user/group/track is stored in a separate file.
common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/SeparatedConfigurateStorage.java