Skip to content
BasaltSoftware
Bedrock 1.26.60

Site colour

Discord
Esc

    ↑↓ moveEnter openEsc close

    Keyboard shortcuts
    Ctrl K
    Search the whole site, from any page
    /
    Jump to the sidebar search, or search the whole site where there isn't one
    Enter
    Open the top search result
    Esc
    Clear the search, or close this panel
    ?
    Show these shortcuts

    Minecraft runs at 20 ticks a second, so each tick has 50 ms to finish. Basalt is healthy when it holds 20.00 TPS and the work in each tick takes only a small part of those 50 ms. This page explains how to check that, and which settings to change when it does not hold.

    Run /status in game as an operator, or status in the terminal. The numbers to watch:

    Line What it tells you
    Current TPS Ticks per second over the last second and the last five seconds. 20.00 is perfect.
    Tick time The average milliseconds a tick took over the same two windows, and the slowest of the last 100 ticks.
    Memory The memory Basalt is using (shown on Linux).
    Players How many are online, and the limit.
    Chunks How many chunks are loaded.
    Entities The total, broken down into items, mobs, others (orbs, arrows and the like) and players.
    Scripts Each plugin’s memory, event subscriptions, running intervals and any warnings.

    How to interpret tick time:

    • Under 10 ms: plenty of headroom.
    • Regularly over 25 ms: the world is getting heavy. Look at entity and chunk counts and at the plugin lines.
    • Over 50 ms: ticks are taking longer than they have, and TPS will drop.

    A single slow tick is not a problem. If a tick runs late, Basalt does not slow the game down for good: later ticks stay on schedule, and ticks that fell behind are run back to back to catch up, up to one second’s worth. Sustained overload is what causes visible lag.

    Almost all of the game runs on one thread, tick by tick. In rough order of how often they matter:

    1. Loaded chunks. Every player keeps a square of chunks around them loaded and ticking. Players spread far apart cost more than players together.
    2. Entities. Dropped items, mobs and their pathfinding. Items floating in flowing water are the most expensive kind.
    3. Redstone and machines. Large clocks and hopper halls. See Redstone and machines.
    4. Plugins. Before-event handlers run while the game waits for them.

    Loading and generating chunks, handling connections and writing to disk happen on other threads and do not hold up a tick.

    All of these are in basalt.toml and need a restart. See Configuration for the full list.

    The radius, in chunks, of terrain sent to each player. Default 8.

    This is the biggest lever for network traffic and for how many chunks are loaded. The number of chunks grows with the square of the radius: a radius of 8 is roughly 290 chunks per player, 12 is roughly 620, 16 is roughly 1090.

    • Many players on modest hardware: 6 to 8.
    • Few players, or a strong machine: 10 to 12.

    Leaving client_side_chunk_generation_enabled on lets clients draw terrain beyond what Basalt sends, which makes a small view distance look much further.

    The radius, in chunks, around each player where the world actually runs: mob AI and spawning, crop growth and other random ticks. Default 4, the same as vanilla. It can be no larger than view_distance.

    Lowering it to 3 saves a good share of world ticking on a busy server. Raising it makes farms and mobs further from players keep running, at a matching cost. Most servers should leave it at 4.

    How long, in seconds, a chunk stays loaded after the last player moves away. Default 300.

    A longer delay means players who wander back find the area still loaded and their dropped items still there, but more chunks stay in memory. Lower it (for example to 120) if memory is tight or players explore a lot.

    The most threads Basalt uses for connections and chunk work. Default 8; 0 means every core the machine has.

    On a machine with more than eight cores and many players, 0 lets chunk loading use them all. On a shared machine, set it to the number of cores you want Basalt to have.

    mob_ai = false stops all mob thinking: mobs stand still but still fall, get pushed and take damage. It is a blunt tool, useful for lobbies and minigame servers where mobs are decoration.

    mob_ai_kinds lists mobs that keep their AI anyway:

    mob_ai = false
    mob_ai_kinds = ["zombie", "skeleton"]

    player_tick = false turns off each player’s hunger upkeep: hunger, saturation and exhaustion, starving, and the healing a well-fed player gets (natural regeneration). Players never get hungry and only heal by other means, such as potions. Default true.

    It suits lobbies and kit servers, and saves an attribute update every tick for each moving player.

    Ticks between full saves. Default 6000 (five minutes). Saving is cheap, about a millisecond or two, and disk writes happen off the main thread, so there is little to gain from raising it. Lowering it reduces what could be lost in a crash.

    Batches of network data smaller than this many bytes are sent uncompressed. Default 256. Leave it alone unless you are measuring.

    Set these with /gamerule or in the world’s config.json.

    Rule Effect on load
    randomtickspeed Vanilla’s default is 1. Higher values multiply the cost of random ticks in every ticking chunk.
    domobspawning Turning it off stops natural spawning, which keeps mob counts down.
    dofiretick Turning it off stops fire spreading, which can otherwise change many blocks.

    Redstone runs inside the tick. The circuit logic itself is very cheap; the cost is in the blocks that change. Every block that changes state has to be updated, its neighbours told, and the change sent to nearby players, at roughly 10 microseconds a block.

    For scale, measured on the developer’s machine:

    Build Cost
    68 lines of 15 redstone dust with lamps, all switching at once (about 1,190 block changes) About 12.6 ms for that tick
    The same build while nothing is switching About 0.08 ms a tick
    512 hoppers in one chunk, all moving an item every 4 ticks About 6.9 ms a tick

    Practical advice:

    • Fast clocks driving long dust lines are the most expensive thing in redstone. Prefer repeaters or observers over long dust runs, and slow clocks down.
    • Large hopper systems are fine in moderation. Hundreds of hoppers that are all busy at once add up.
    • Circuits only run when the area around them is loaded (redstone_load_radius, 32 blocks by default).
    • As a last resort, redstone = false freezes all redstone.

    Each plugin runs on its own thread, so a slow plugin does not directly slow the game. The exception is before events and custom commands: the game waits for the plugin’s answer, for up to 50 ms.

    Basalt watches plugins and warns, in the log and in /status, when one:

    • takes more than 10 ms in a before-event handler or command, or misses the 50 ms limit,
    • uses more than 100 MB of memory (at 250 MB it is stopped),
    • keeps adding event subscriptions or intervals for five minutes, which usually means a leak,
    • runs JavaScript for 10 seconds without a break, in which case it is interrupted.

    If /status shows a plugin as stopped, /reload starts it again. Advice for plugin authors is in Events.

    • view_distance is the main control over bandwidth.
    • Packets are batched and compressed once per batch.
    • The rate limits (max_inbound_packets_per_second and the rest) protect against clients that flood packets. The defaults suit normal play; see Configuration.
    • Host large resource packs on a CDN so they do not download through the game connection. See Resource packs.
    1. Run /status when the lag happens and note tick time, chunks and entities.
    2. High entity counts: look for item spills and oversized mob farms.
    3. High chunk counts for the number of players: lower view_distance, then chunk_unload_delay.
    4. Tick time high with modest counts: suspect redstone or a plugin. Check the Scripts lines for warnings.
    5. Still heavy: lower tick_distance to 3, and consider mob_ai_kinds. On a lobby or minigame server, player_tick = false also helps.
    6. Build in release mode. A debug build (cargo run without --release) is many times slower.