Execution Contexts & Folia
AbyssalLib’s scheduler is built from the ground up to seamlessly support both standard Bukkit/Paper and Folia. You write your scheduling logic once, and the TaskDispatcher automatically routes it to the correct underlying platform.
Sync vs Async
By default, all tasks scheduled using Clock.TICKS run synchronously on the main server thread (or the region thread in Folia).
To run heavy calculations, database queries, or network requests off the main thread, append .async() to the builder.
Folia Support & Contexts
Folia fundamentally changes server architecture by replacing the single main thread with multiple independent "Region Threads." If you modify a block or an entity, you must be executing on the thread that currently owns that region.
AbyssalLib provides context methods on the TaskBuilder to handle this routing for you. If you are not running Folia, these methods simply default back to the standard Bukkit main thread, ensuring your plugin works flawlessly on both platforms.
Use .entity(Entity) when your task modifies or tracks a specific entity. The task will execute on the thread currently ticking that entity, and will safely suspend or migrate if the entity teleports across region boundaries.
Use .region(Location) when your task modifies blocks or spawns entities at a specific coordinate. The task will route to the thread responsible for that chunk.
.global() is the default behavior if no context is specified. It is meant for tasks that do not interact with the world, blocks, or entities (e.g., Discord bot updates, database syncing, or global server broadcasts).
Mixing Async and Folia
You can combine .async() with Folia contexts. However, if you flag an entity or region task as .async(), it simply runs on a detached async thread pool, completely ignoring the region threading.
Only do this if you need the entity's data read-only for a background process, and ensure you do not call Bukkit API methods that modify the world from that async task!