§ How to · with Forge AI
How to make a Roblox matchmaking system (with AI)
By Sametcan Tasgiran, Founder & Developer·Published ·Updated
A Roblox matchmaking system needs five pieces: queue management, room creation, skill-based matching (MMR), TeleportService routing, and a queue UI. Forge AI generates all five in 1m 18s.
7 files · 280 lines · 1m 18s · 1 credit. MessagingService-coordinated cross-server queue.
Queue management
Players join queue via UI button. Server holds queue state, attempts to fill rooms continuously. UI shows estimated wait time.
Room creation
ReserveServer-based private rooms. Rooms hold 2-12 players (configurable). New room created when no matchable existing room available.
Skill-based matching
Each player has an MMR score (default 1000). Matchmaker prefers rooms with similar MMR (±100). MMR adjusts on win/loss.
TeleportService routing
Players teleport to reserved server when room fills. Teleport carries player MMR + party info via TeleportData.
Cross-server queue
MessagingService syncs queue state across all servers — players across any server can match into the same room.
Party support
Players can party up before queuing. Parties stay together when matched. Up to 4-player parties supported by default.
Files Forge AI ships for this prompt
7 files · 280 lines · 1m 18s · 1 credit
ServerScriptService/QueueManager.lua
Queue state, match attempts, MMR matching
92 lines
ServerScriptService/CrossServerSync.lua
MessagingService queue broadcast
52 lines
ServerScriptService/MMRTracker.lua
Player MMR persistence + win/loss adjustment
38 lines
ServerScriptService/PartyManager.lua
Party invites, join, leave
42 lines
ReplicatedStorage/Remotes/JoinQueue
Client → queue
instance
ReplicatedStorage/Remotes/PartyInvite
Send/accept party invites
instance
StarterGui/MatchmakingUI.lua
Queue button, wait time, party display
56 lines
Sample output: ServerScriptService/QueueManager.lua
--!strict
-- ServerScriptService/QueueManager.lua (Forge AI · excerpt)
local Players = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local MMRTracker = require(script.Parent.MMRTracker)
type QueueEntry = { player: Player, mmr: number, partyId: string?, joinedAt: number }
local ROOM_SIZE = 6
local MMR_TOLERANCE = 100
local PLACE_ID = 0 -- set to your room place ID
local queue: { QueueEntry } = {}
local function tryMatch()
if #queue < ROOM_SIZE then return end
-- Find ROOM_SIZE players with MMR within tolerance
table.sort(queue, function(a, b) return a.mmr < b.mmr end)
for i = 1, #queue - ROOM_SIZE + 1 do
local window = queue[i + ROOM_SIZE - 1].mmr - queue[i].mmr
if window <= MMR_TOLERANCE then
-- Match found — extract these players
local matched: { QueueEntry } = {}
for j = i, i + ROOM_SIZE - 1 do table.insert(matched, queue[j]) end
for j = i + ROOM_SIZE - 1, i, -1 do table.remove(queue, j) end
-- Reserve server and teleport
local code = TeleportService:ReserveServer(PLACE_ID)
local players = {}
for _, entry in ipairs(matched) do table.insert(players, entry.player) end
TeleportService:TeleportToPrivateServer(PLACE_ID, code, players)
return
end
end
end
return { join = function(p: Player) table.insert(queue, { player = p, mmr = MMRTracker:get(p), partyId = nil, joinedAt = os.clock() }); tryMatch() end }Building a Roblox matchmaking system
Matchmaking is the invisible system that decides if your competitive Roblox game feels fair. Players don't notice good matchmaking — they just enjoy the games. Players notice bad matchmaking immediately — stomps, long queues, repeated opponents. Forge AI ships the invisible version.
The Forge AI matchmaking prompt produces a 7-file system in 1m 18s. QueueManager holds the queue state and attempts to fill rooms. MMRTracker persists per-player skill ratings. CrossServerSync uses MessagingService to share queue state across all running servers, so the entire game's player base is one matchmaking pool.
MMR-based matching is the fairness layer. Each player has a Matchmaking Rating starting at 1000. The matchmaker prefers rooms where MMR is within ±100 of all players. After a win, MMR increases by 25; after a loss, decreases by 20. The asymmetry slightly favors progression over time, which keeps players engaged.
Queue starvation is the production failure mode. New games have small player bases — strict MMR matching means long queues and players quit. Forge's mitigation: MMR tolerance widens over time (60s → ±250, 120s → ±500, 180s → any match). This guarantees a match in under 3 minutes regardless of player count.
Reserved server rooms use TeleportService:ReserveServer to spin up private game instances. When a room fills, all 6 matched players teleport simultaneously. The reserved server holds them as a closed lobby — random players cannot join mid-match. This is the standard pattern for ranked games in Roblox.
Party support is the social layer. Players can party up via PartyManager and queue together. Match attempts require the entire party to fit in the same room. This is what makes friends-playing-together work — without it, ranked games feel anti-social.
See more on the Luau generator, the game builder, or browse the full blog.
Frequently asked
How does the cross-server queue work?+
MessagingService:PublishAsync broadcasts queue events. Each server hears them and updates its local view of the global queue. Match attempts use the unified view. Race conditions on simultaneous matches are resolved by 'first to publish wins'.
What if no match is found in a long time?+
After 60 seconds in queue, MMR tolerance widens to 250. After 120 seconds, to 500. After 180 seconds, any 6 players match. This prevents queue starvation while preferring close matches when possible.
How is MMR adjusted on win/loss?+
MMRTracker uses a simplified Elo: +25 MMR on win, -20 MMR on loss. Adjustments are clamped to ±50 to prevent wild swings. MMR persists in DataStore.
How do parties stay together?+
PartyManager tracks party membership. When any party member queues, all members are added with the same partyId. Match attempts require all party members to be included in the same room or the match is rejected.
What happens if a player disconnects mid-queue?+
PlayerRemoving removes them from the queue. If they were in a party that's mid-match, the match aborts for the whole party. They forfeit any rank changes.
Related Forge AI prompts
Roblox leaderboard
4 files · 110 lines · 31 seconds · 1 credit. Cross-server, throttle-safe.
Roblox FPS
14 files · 480 lines · 2m 35s · 1 credit. Three weapons by default (rifle, shotgun, pistol) — extensible.
Roblox combat system
5 files · 140 lines · 42 seconds · 1 credit. Drop into your place and press Play.