Docs Queue Settings Reference
Documentation
Queue Settings Reference
Every matchmaking setting in one place — 92 settings across 5 queue types and two modes. Filter down to exactly what applies to your queue.
Settings are configured three ways: options on the /queue_* creation
commands, the Admin Actions dropdown on the queue message
(Configure … modals), and the web dashboard's queue editor.
Identity & Display
8What players see: names, images, instructions.
Unique identifier for the queue; forms the DynamoDB key `queue_id = client_id|queue_name`. Set once at creation, never editable.
Headline shown on the queue/launcher embed.
Optional at creation — omitting it reuses queue_name as the headline. No Discord configure modal edits the title after creation, so post-creation edits are web-dashboard only.
Body text on the queue/launcher embed.
Like title: optional at creation, and post-creation edits are web-dashboard only.
Which Elo leaderboard this queue's matches record ratings on.
Blank-submit asymmetry in the Discord modal: headless preserves the current value on blank; hosted clears it to null.
Banner image on the queue/launcher embed.
Free text shown when players vote on match results (e.g. 'Submit screenshots to #evidence').
Whether player names are displayed in the queue join list.
Discord modal field is named `show_names` but persists as `join_notification_show_names`.
Whether the queue message names the leaderboard matches record to.
Tri-state: an explicit yes/no always wins; unset follows `match_result`, so ranked queues name the board and unranked/disabled ones don't. Display only — matches still record to the leaderboard when unranked (elo_k_factor 0), and the board still supplies ratings and the choice definitions used by Unique Choice Matchmaking; on `disabled` nothing records at all, which is the case where naming it was misleading. Both editors offer all three states, and both persist 'automatic' rather than collapsing it: the web form sends null (the per-key merge deletes the key), the Discord modal stores null (which every reader treats as unset). They must stay tri-state — these editors write every field they render on every save, so a two-value control silently pinned the setting whenever an admin saved that modal for an unrelated reason, e.g. setting a queue image. Discord modal field is named `show_leaderboard`; persists as `join_notification_show_leaderboard`. The web form renders it as a three-way select (Automatic / Always show / Always hide) rather than a checkbox, because 'auto' is a distinct stored state — the key absent — that a checkbox cannot express; picking Automatic sends null, which the per-key merge deletes.
Team Composition
8Sizes, player counts, and how teams are formed.
Players per team. Versus/team queues are two equal teams; anonymous queues can set the two sizes independently at creation.
The Match Rules modal takes one `team_size` number and writes `team_sizes: [n, n]` plus the display string `versus: "NvN"` — asymmetric sizes are creation-time (anonymous) only. Creation writes a separate `versus_format` display key that the modal does NOT update (see internal keys).
Players needed before an FFA/co-op match fires (headless) or a lobby can start.
The web form shows min/max players for every queue type; the Discord Match Rules modal only shows them for FFA/co-op.
Cap on players per FFA/co-op match.
Players needed to fill a co-op hosted lobby. Also feeds the default lobby size for host customization.
FFA/co-op range queues hold the pop open after min_players is reached: the first crossing arms a grace window of this many minutes so more players can join (up to max_players). Reaching max_players pops instantly; at the deadline the match starts with everyone present.
No configure modal edits it — the web queue-settings form is the only post-creation editor. Enforced ONLY when min_players < max_players (creation defaults max_players to min_players when omitted, so queues without an explicit max keep instant pops). The window is armed once per min-crossing and not extended by later joins; if players drop below min before the deadline it clears without a match. Runs on QueueGraceTimeoutWorkflow, recovered by the deploy sweeper.
How players are split into teams when a match forms.
This is the QUEUE vocabulary. The /host command and lobby runtime use a different `team_mode` vocabulary (see HOST_TEAM_MODES); hosted-lobby creation translates one into the other ('balanced_teams' → 'balance_elo', etc.). The web form additionally offers a bare 'captains' value — the runtime recognizes it (generic captains display mode, part of CAPTAIN_MODES) but no Discord surface offers it.
Per-queue custom team display names, inherited by every match the queue spawns.
One Discord paragraph field (`team_names_input`, comma/newline-separated `emoji:name` segments) persists TWO parallel arrays: team_names + team_emojis. Blank resets both to defaults (null).
Per-queue custom team emojis (parsed from the same input as team_names).
Matchmaking Rules
6Elo gating, rematch cooldowns, unique-choice matching.
Maximum rating gap allowed between players when forming a match.
Minimum rating gap required between players when forming a match — the handicap-queue gate.
Mirror of max_elo_difference: headless queues check the SPREAD of the candidate roster (highest minus lowest rating); team queues check the pairwise gap between the two team ratings. Pops are simply deferred until a far-enough pairing exists. Pair it with the leaderboard’s elo_cap_threshold rating rule (Cap Threshold, with Cap Range 0) so the matches it forms are also *rated* as handicap matches (±K/2). Not applied to voice-dodge auto-substitution: a formed match keeps its roster spread rules only for the max bound; blocking substitutes on a minimum spread would strand lobbies.
Minutes before the same two players/teams can be matched against each other again.
Clears the rematch cooldown between two players once either of them plays someone else.
Choice-based (faction/position) matchmaking keyed to a leaderboard choice definition: teams are all-same-value or one-of-each-value.
Persists an object {rival_choice, rival_choice_display, choices, scores, balance_teams?, team_quota?} — Discord-only (deliberately omitted from the web form). Modal field is named `rival_team_choice`. Re-selecting the same choice preserves scores and (in balanced mode) the team_quota; picking a different one zeroes the scores and drops the quota, whose keys belong to the old choice. `scores` only ever moves in Faction-vs-Faction mode — balanced teams field one of each value, so no winning faction is recorded — and the standings section is rendered in that mode only.
Fixed per-position formation (e.g. 'goalkeeper:1, defender:2') each team must satisfy under balanced Unique Choice Matchmaking.
Requires SOME rival choice to be configured first (the submit rejects only when none exists — a non-balanced Faction-vs-Faction choice passes and the quota saves, though it is only honored in balanced mode). Nested under rival_teams; saving rewrites the whole object.
Match Rules & Format
2Ranked vs unranked, voting mode, series format.
Whether results record, affect Elo, and who approves them.
Fans out into four derived booleans persisted alongside: match_result_disabled, ranked, admin_confirmation, admin_decide (see internal keys). No longer a creation option on any queue mode — every queue is created as 'ranked' and changed from the Match Rules modal or the web form. (Co-op queues never had one.) Also drives display: any unranked or disabled mode hides the per-player rating in the headless match message, since nothing in the match can move it. /host lobbies are unaffected — their `leaderboard` option exists to show ratings.
Series structure: one match, unlimited matches, best-of-N, or cumulative points over N rounds.
Persisted as a single string ('best_of_3', 'cumulative_5'); the modal/web split it into a format select + count input. The Discord Match Rules modal rewrites competitive_format on EVERY submit — a submit meant to change only the voting mode still rewrites the format. No longer a creation option on any queue mode: every queue starts at 'single_match' and picks up a series format from the modal or the web form.
Scoring & Stats
8How series and rounds turn into rating changes and points.
How the series result becomes a leaderboard rating change — fires once per series (after the final round for multi-round formats).
Naming inversion: 'Configure Scoring' persists the series_* keys, while 'Configure Cumulative Scoring' persists the plain scoring_mode/placement_points keys (per-round). Discord-only.
Per-place rating points (e.g. '25,15,10,5') for Placement Points mode, or the win/loss base for Stat Points mode.
A blank submit never clears a saved list (deliberate, so toggling modes does not wipe it). Discord-only.
How each round's placements become scoreboard points whose totals decide a multi-round series (the 'Match Score' axis, distinct from Rating Mode).
Menu entry only appears for best_of_* / cumulative_* formats. Discord-only.
Per-place points each round awards to the in-series scoreboard (e.g. '20,15,12,10').
Blank never clears a saved list. Discord-only.
Named per-round stats (kills, caps, …) with points-per-unit and optional rounding, submitted each round of a cumulative series.
Modal field is named `stat_definitions`. Menu entry only appears for cumulative_* formats — stricter than Cumulative Scoring, which also shows for best_of_*. Discord-only.
Whether one captain submits team stat totals per round or every player submits individually.
Custom noun for each round of the series (e.g. 'Game', 'Map', 'Half').
Whether the highest or lowest cumulative total wins the series.
Timeouts & Cooldowns
5Idle eviction, re-queue cooldowns, active-match limits.
Auto-remove idle players/teams from a headless queue after this many minutes (enforced by the queue timeout Workflows).
**0 means off** — no timeout workflow is armed and no `timeout_timestamp` is stamped on the queue entry, so players wait indefinitely. Blank is a separate state: it stores null and falls back to 10. All three cases resolve through `workers/shared/matchmaking/idle-timeout.js` (shared so the web form and the bot read the field identically); don't re-introduce a bare `idle_timeout_minutes || 10`, which is what made 0 unreachable in the first place. Turning it off also stops timers that are already running: both timeout Workflows re-check the queue's current setting when they wake, and the deploy sweeper checks it before evicting, so an admin doesn't have to wait out timers armed under the old value. No longer a creation option — headless queues are created at 10 and retimed from Configure Queue Timeouts or the web form. Hosted launchers no longer write it at all, which is harmless: hosted lobby auto-close actually reads `lobby_timeout_minutes` (Configure Lobby Limits), and the hosted-stored idle_timeout_minutes never had a consumer in the lobby-create path. **This setting and the queue's fill target can be mutually unsatisfiable, and that failure is silent.** A queue with `team_sizes` pops all-or-nothing, so every seat must be filled within one timeout window: 10 players / 10 minutes demands a sustained join per minute, and below that rate the early joiners are evicted before the last arrive and the queue never pops at all. It reports as "joins don't register on Discord" (the writes land, so the website shows them; the embed's count just climbs and collapses). `workers/shared/matchmaking/queue-fill-feasibility.js` scores the pairing and warns — on the creation followup, on the Configure Queue Timeouts confirmation, and live under this field in the web form. Advisory only: a busy server may sustain the rate, so it never blocks a save. **Evictions also report themselves on the queue panel now.** Previously an eviction left no trace anywhere unless the queue had an `audit_channel`, so a roster collapsing back toward empty never stated a cause. Each eviction path stamps `idle_evictions_count` / `idle_evictions_since` / `last_idle_eviction_at` onto the queue record (`workers/shared/matchmaking/idle-evictions.js`), folded into the `last_activity` write those paths already make — no extra subrequest, no new message, so nothing pings. The embed then adds an `### Idle Timeout` section: the rule whenever a roster is on screen (the per-player `— timeout` countdowns need explaining), and an "N removed for idling in the last hour" line whenever there have been any, roster or not. Counters are scalar and the roster write stays a surgical `REMOVE`, so this is not a §17 read-modify-write; `ADD` keeps concurrent evictions summing. A one-hour reporting window ages out on its own — a stale window is simply not rendered, so no write is needed to clear it.
Re-queue cooldown applied immediately after players are matched (before the match is played).
Blank submit clears the stored value, which reverts behavior to the runtime default of 1 minute — set 0 explicitly to disable.
Re-queue cooldown applied after a match result is recorded.
Prevents players from re-joining the queue until they report their pending match result.
Blocks joining a new lobby while already in an ongoing match, per-queue or server-wide.
Voice-Join Enforcement
4Dodge protection: kick and cool down players who never join voice.
Replace/remove players who never join the match voice channel after a match forms (via the voice-join timeout Workflow).
How long players have to join voice after a match forms before being treated as dodgers.
How long a voice dodger is blocked from re-joining the queue. Admins can pardon via the Pardon Dodge Cooldown menu action or the web dashboard.
Ping players not yet in voice this many seconds before the dodge timeout fires.
Maps & Voting
3Map pools, veto strategies, vote timers.
Named map pool the queue draws maps from.
How maps are selected for matches. FFA/co-op/anonymous creation only offers Simple; the full veto strategies are versus/team.
Cross-surface drift in the product: creation offers stage_striking / stage_striking_counterpick but not random / smash_striking; the configure modal and web form offer random / smash_striking but not the two stage_striking values. All are real runtime strategies. The modal's 'none' choice persists as null.
Simple Vote only: auto-conclude the map vote after N seconds, picking the leading map (random on no votes). Headless: countdown starts at match creation; hosted: when the lobby fills.
Channels & Auto-Channels
11Where matches post; auto-created temp channels, threads, naming.
Channel where match/lobby-start announcements post.
No longer a creation option — the queue_* commands seed it with the channel the command was run in, and Configure Match Announcements (or the web form) retargets it.
Channel where finished matches are listed; also where 'ping on recorded' mentions post.
Same as match_start_channel: no longer a creation option, seeded with the channel the command was run in and retargeted from Configure Match Announcements or the web form.
Where the match/lobby panel (roster, map vote, report buttons) is posted. A dedicated channel: the bot creates one text channel per match — placed under the Temp-Channel Category and named with the Shared Channel Name Template — and deletes it when the match ends. Results still post to the Match End Channel.
Private = visible only to the match participants, the configured admin role(s), and the bot. Public = visible to everyone, so non-players can tune in and watch. The Temp-Channel Category controls placement only (where the channels nest), not visibility; with no category set the channel is created at the server root. The per-match channel doubles as the shared text channel (no separate one is created); voice channels are still governed by Shared Match Channel / Per-Team Channels. Legacy queues saved with the old single "dedicated" value are treated as private.
Discord category where auto-created match channels are placed.
Auto-create a shared text/voice channel for all players in each match; deleted when the match ends.
Auto-create per-team channels, private (team-only) or public.
Known quirk: the Discord Auto-Channels modal persists this key unconditionally with default 'disabled', so submitting that modal on an FFA/co-op queue (where the field isn't shown) resets any stored value to disabled.
Spin up a public or private thread for each match.
Cross-setting coupling: when no dispute channel is set, disputes fall back to the match thread — which only exists if threads are enabled here.
Whether the bot moves players into (and back out of) auto-created voice channels.
Naming template for the auto-created shared channel. Tokens: {code} {title} {vs}.
Naming template for auto-created per-team channels. Tokens: {code} {title} {team} {emoji} {n} {vs}.
Naming template for the auto-created match thread. Tokens: {code} {title} {vs}.
Notifications & Pings
8Join feeds, match start/end pings, recorded-result pings.
Channel where queue join/leave events post.
Role mentioned in the join-notification post.
Role pinged when the queue message is posted or reposted — the "we are open, come queue" announcement.
Completes the lifecycle: joins, match start, match end and disputes could each ping a role; the queue going up could not. The mention rides the queue message itself rather than a second post, so the notification lands on the Join button and costs no extra subrequest — and because Discord does not re-notify on an edit, the message can re-render all night without pinging again. Fires on repost as well as create, since a league running a session per night reposts the queue each time and that repost is the announcement. Rate-limited by `queue_open_notification_cooldown` (default 2 minutes) via its own `last_open_notification` stamp — deliberately not the join ping's `last_role_notification`, which would let either ping suppress the other.
Minimum gap between Queue Open Ping Role pings. Set to 0 to ping on every post and repost.
The guard exists so a double-click, or a repost to fix the wrong channel, does not ping the whole role twice. But the default is a guess at someone else's workflow: an admin fixing something mid-announcement reposts several times on purpose and wants each one to ping, which is why this is theirs to set. Three-way like the idle timeout — a positive number is minutes, `0` is no cooldown at all, and unset is the 2-minute default; `0` therefore has to stay distinguishable from blank, so blanking the field restores the default rather than disabling the guard. A suppressed ping is never silent: the repost confirmation says the cooldown held it and how long is left.
Minutes between "what lanes are still missing" pings (e.g. "needs +1 Mid and +1 Jungle to start — 8/10 placed"), from the moment the queue is posted until a match starts. 0 turns it off.
A lane-matched queue can sit at 8/10 indefinitely because the two free seats are a Mid and a Jungle while everyone still queueing is a Mid — the player count reads "nearly there" and only the per-lane gap says why nothing is moving. The grouped queue display shows that to whoever is reading the message; this pings it to the people who are not. Needs Queue Open Ping Role set (it reuses that role and that audience) and a lane formation configured; without either it does nothing. The chain starts on post/repost and ends when a match starts, when the queue is reposted (a new chain replaces the old), or when the queue is unposted or closed — all four via one stored epoch, which is also what makes it impossible for two chains to ping at once. A cycle with an empty pool stays silent rather than announcing that a queue nobody joined needs all ten slots. A chain also ends on its own after an hour, whatever the interval: "ends when the match starts" is the real stop condition, but a session that never fills never reaches it, and an overnight queue would ping the role until morning and get itself muted. The hour is wall clock rather than a number of pings, because a count made the coverage depend on the interval — at the 1-minute floor an earlier 15-ping cap bought only 15 minutes of chasing on a scrim session that ran all evening, and then went quiet, which reads from the channel as the pings simply not working. A backstop of 30 reminders still applies for the short intervals where an hour would otherwise be 60 interruptions; at 2 minutes the two coincide, and above that the hour is always what ends it. Each reminder deletes the previous one, so the channel holds exactly one, always current — and when the chain ends the last one is deleted too, so a match that started, a queue that was unposted at the end of the night, and a queue that was closed or deleted all leave nothing behind still asking for players. The count is seats FILLED out of seats needed, not pool size: a queue holding a third Mid for two Mid seats is ten players and nine placed, and the pool itself is uncapped, so "placed" is both the accurate word and the one that keeps the count from contradicting the gap beside it.
Role pinged when a match starts.
Role pinged when a match ends.
Who gets a real mention in the match-end-channel post when a result records.
Posts into match_end_channel — a silent no-op if that channel is unset (the modal warns). The Discord modal for it is headless-only, but hosted lobbies consume the setting too (copied onto the lobby at creation); for hosted queues set it via the web form.
Results, Disputes & Evidence
8Captain vote timeouts, screenshots, AI scanning, dispute routing.
After one captain reports a result, auto-record from that single report if the other captain never votes within this many minutes.
Blocks recording a match result until a screenshot has been submitted as evidence.
Adds a 'Scan Result' button that has AI read a scoreboard screenshot to pre-fill the match result.
Scoreboard-reading instructions live on the leaderboard/server config (the board's Screenshot Scanning page on the dashboard), not on the queue.
When an AI scan reads every player and stat cleanly, record it with no manual approval step.
Channel where players upload match screenshots.
Channel where match events (scores, disputes, results) are logged.
Channel where dispute notifications post when players request admin help.
Role mentioned when a dispute is filed.
Access & Eligibility
12Passwords, minimum-rating gates, admin roles, party queue.
Password players must enter to join a headless queue.
Creation option exists only on /queue_versus headless; every headless queue can set it post-creation via the modal or web. Never pre-filled in modals (sensitive).
Password required to open a lobby from the launcher.
Default join password applied to newly created hosted lobbies (hosts can change it per lobby).
Hide the lobby code from the embed and only reveal it via a button click once the lobby is full.
Stored key is still `private_lobby_code` — the setting was renamed from "Private Lobby Code" because a Yes/No named after one of its states never said what Yes did, and a league that switched it on reported the code as having disappeared. Renaming the key would mean migrating every stored queue and lobby for no user-visible gain, so only the labels moved. Lives in two different Discord modals depending on mode. The web form only shows it for hosted queues.
Rating floor to join (or host from) the queue; unrated players are treated as the league’s default rating.
The headless menu hides this for team queues (teams join with team ratings); the launcher menu always shows it. Discord-only — not editable on the web.
Which of the player’s ratings the floor is checked against; per-format types resolve from the actual match being joined.
Nulled automatically whenever min_elo_to_join is cleared.
Whether SETTING the in-game lobby code is limited to lobby admins and the queue creator. Viewing is unaffected — everyone in the match can always read it.
The queue's CURRENT value is authoritative — utils/lobby-code-access.js reads the queue rather than trusting the copy stamped onto the lobby at creation, so turning the restriction on bites the match already in progress. (The stamped copy is kept only as a fallback for when that read fails; on its own it reads `false` for every lobby predating the setting, which is indistinguishable from deliberately open.) Lobby admins are still answered for free from the denormalized `admin_roles`, so a restricted league's staff never pay the read. Lobby admins — Discord Administrator or a configured Admin Role — and the queue's creator can always set it, on either setting: the creator is the scrim host who opens the queue and makes the room but is often not playing, since the game seats a host and spectators apart from the players. This flag only decides whether the OTHER players in the match may. Open by default, because on a pickup queue whoever makes the room is just a player.
Roles (beyond server administrators) allowed to confirm/reject results in Admin Approval / Admin Decides modes, and to run a live match’s roster — Substitute Player / Kick Player in the match message’s admin dropdown. Holders are also granted visibility into the private lobby channels and (via Manage-Threads on the parent channel) private lobby threads the bot creates, so an admin can oversee a lobby they aren’t a participant in.
Every save also mirrors the first role into the legacy single `admin_role` key. The web form edits only the legacy `admin_role` (single role), not this array.
Enables the '👥 Join as Party' button so pre-made groups queue together with a same-team guarantee. On headless queues the button sits on the queue message; on hosted launchers it appears on each open lobby (plus 'Host as Party' on the launcher), and the party joins that lobby together.
Headless runtime eligibility additionally requires: team size ≥ 2, formation not players_choose/captains/no_teams, unique-choice matchmaking off, and no queue password. Hosted lobbies support parties on every bot-formed team shape — Balanced (balance_elo), random teams, anonymous, and the captains draft (picking any party member drafts the whole party; a party captain pre-fills their team) — excluding only players_choose and password-protected lobbies. Hosted enablement applies to lobbies created after the change.
Consent step for hosted party joins: in invite mode, each picked teammate gets a DM with Accept/Decline (pinged in the lobby channel if their DMs are closed) and the party only joins once everyone has responded — declines simply shrink the party. Instant keeps the frictionless no-accept flow.
Hosted launchers only; requires Party Queue enabled. Copied onto lobbies at creation, so a change applies to lobbies created afterwards. Invites expire after 10 minutes (lazily — the first click after expiry cleans up); a leader's new pick supersedes their pending invite, which doubles as cancel. The headless queue's party flow stays no-accept by design (its counterweights: dodge-penalty redirection to the leader, any member's Leave pulls the whole party).
Caps how many players a party may contain below the structural team-size limit — e.g. 2 for duos-only in a 5v5. Values below 2 are treated as off (to forbid parties entirely, disable Party Queue).
Enforced at the teammate picker (fewer selectable slots) and again at the join gate on both surfaces. On hosted launchers the cap is copied onto lobbies at creation, so a change applies to lobbies created afterwards; headless queues read it live.
Largest allowed Elo gap between the highest- and lowest-rated member of a party — a guard against smurf/boost pairings queueing together. The refusal names both players and their ratings.
Checked at party-formation time (join or invite): headless uses the queue-format rating each entry already carries; hosted does one bulk ratings read on the lobby's leaderboard. Unrated players count as the league's default starting rating on both surfaces, so brand-new accounts can't dodge the cap by being unrated — but note that makes the check approximate for genuinely new players. Hosted caps copy onto lobbies at creation (new lobbies only); headless reads live.
Hosted-Launcher Controls
7Host permissions, lobby caps, host customization bounds.
Whether pressing 'Host Lobby' creates a lobby immediately with queue defaults or first shows the host a customize modal.
Lower bound of the player count a host may pick when customizing their lobby.
Upper bound (hard cap 25) of the player count a host may pick when customizing their lobby.
Restrict who may open lobbies from this launcher.
Caps simultaneous open lobbies for one host in this queue. Admin hosts bypass this cap (staff seeding).
Caps still-forming lobbies across all hosts (started/full lobbies stop counting). Enforced for everyone, including admins.
Auto-close a hosted lobby that never fills after this many minutes (scheduled as a Cloudflare Workflow at lobby creation).
Per-Lobby Fields
Set on an individual hosted lobby (by its host or a server admin), not on the queue. They override or supplement the queue's defaults for that one lobby.
| Field | Who sets it | What it does |
|---|---|---|
| lobby_title | host or admin | Renames a live lobby; must be non-empty. Governed by the league-wide `lobby_permissions.title` setting (see below). |
| lobby_password | host or admin | Sets/removes the join password on one lobby (blank clears). |
| region | host or admin | Free-text region/ping label shown in the lobby embed; display-only. Governed by the league-wide `lobby_permissions.region` setting (see below). |
| lobby_image_url | host or admin | Embed image URL (http/https). Governed by the league-wide `lobby_permissions.image` setting (see below). |
| competitive_format | host or admin | Per-lobby override: single_match / endless_matches / best_of_N / cumulative_N. |
| disabled_maps | host or admin | Per-lobby map pool override — unselected maps are disabled; at least one must remain. |
| team_mode | set at creation | Runtime team-formation vocabulary for the lobby (see HOST_TEAM_MODES); from /host verbatim, or translated from the queue’s team_formation. |
| match_result | set at creation | The queue’s match_result mode, copied onto the lobby beside the four booleans it derives. Stored because `ranked` defaults to false on the lobby record, so a false value cannot tell "the admin chose unranked" apart from "never configured" — the message builder needs that distinction before it hides per-player ratings. Absent on lobbies created before it was stored, which renders as ranked (ratings shown, i.e. unchanged). |
| lobby_permissions (league-wide) | league admin, from the dashboard | Not a lobby field — the league-wide policy that decides who may use the four host-editable ones above. Discord Management → Lobby Permissions sets `image`, `title`, `team_names` and `region` each to `host` (default: lobby host or a server admin), `admin` (administrators only; the menu entry stays, a non-admin host is refused on submit) or `off` (the entry is removed from lobby panels). It exists because on a queue-popped lobby the "host" is an ordinary member, so all four are surfaces a player can write NSFW images or slurs onto in public. Snapshotted onto each lobby at creation so the renderers can drop a disabled entry; re-read live on every attempt, so a change reaches lobbies that are already open. The queue-level lobby_image_url / team_names defaults are unaffected — those are already staff-set. |
| host customize overrides | prospective host | One-shot overrides at lobby creation when host_lobby_mode = host_customizes; player count bounded by host_lobby_min/max_players and must divide evenly into teams for every non-FFA/non-co-op queue mode (versus, team, anonymous). |
The Two Team-Formation Vocabularies
Queues store team_formation (see Team Composition above).
Lobbies run on a separate team_mode vocabulary: /host stores its option verbatim, while hosted launchers
translate the queue value at lobby creation
(balanced_teams → balance_elo, FFA/co-op → none,
captains modes pass through).
| team_mode value | Label | Where it comes from |
|---|---|---|
| players_choose | Players Choose | /host + translated from queue players_choose + hosted matchmaking submit flows |
| players_choose_positions | Players Choose (with positions) | retired — no longer creatableFully removed. The lobby message builders never rendered a position picker, so the mode stored position_names nobody could select from; the whole feature has since been deleted — the /settings positions command, the hosted_lobby_choose_position handler, handleSetPosition, and the position_names field itself. Both createLobby and /host now reject the mode by name. Role-based matchmaking lives on headless queues via rival_teams (Unique Choice Matchmaking). Kept in this list because pre-existing lobby rows still carry the value; nothing reads it. |
| random | Random | /host onlyNo automatic on-fill randomizer — random assignment fires via the manual Randomize Teams action. |
| random_anonymous | Random (anonymous) | /host + anonymous submit flows |
| random_positions | Random (with positions) | retired — no longer creatableSame story as players_choose_positions: no picker was ever rendered, and the machinery behind it is deleted. Use rival_teams on a headless queue instead. |
| random_teams | Random Teams | translated from queue random_teams |
| captains_host_picks | Captains (Host Picks) | /host + queue (hosted) |
| captains_highest_elo | Captains (Highest Elo) | queue captains_* pass through unchanged |
| captains_lowest_elo | Captains (Lowest Elo) | queue captains_* pass through unchanged |
| captains_random | Captains (Random) | queue captains_* pass through unchanged |
| captains_volunteer | Captains (Volunteer) | queue captains_* pass through unchanged |
| balance_elo | Balance by Elo | /host balance_elo + translated from queue balanced_teams |
| no_teams | No Teams | /host + ffa/coop submit flows |
| none | None | translated from ffa/coop queues |
Internal & Derived Keys
Keys the system writes automatically — you never set these directly, but you may see them in exports or the API.
Display string ('5v5') written by the Match Rules modal alongside team_sizes.
Creation writes the sibling key `versus_format` instead; the modal does not update versus_format, so /queue_manage list and queue status can show a stale format after a modal size edit.
Display string ('5v5') written at queue creation; read by queue status and /queue_manage list. Allowlisted for web PATCH but has no web form control.
Four booleans the result-voting flow consumes, fanned out from match_result whenever it is saved (by the bot and by the web form).
The web PATCH allowlists each flag individually with no consistency check against match_result.
Legacy single admin-role key, auto-synced to the first entry of admin_roles on every Discord save; older readers (team matches, FFA) still consume it. The web form edits this key directly.
Legacy queue-level key still read as a fallback by some consumers (`team_formation || team_mode || "random_teams"`). Distinct from the lobby-level team_mode runtime field (see HOST_TEAM_MODES).
Looking for the concepts?
This page is the reference. For how queues, modes, team formation, and formats actually work, read the matchmaking guide.
Matchmaking & Queues Guide