[Beta][v0.2][2025] MatchMaker: A flexible matchmaking module built on promises and memorystores

:video_game: Matchmaker Package Introduction

The Matchmaker package is a modular and scalable matchmaking system built for Roblox multiplayer games. It handles regionalized player queues, asynchronous matchmaking coordination, private server management, and cross-server state syncing using MemoryStore and Promise-based operations.

Key Features

  • Region-Based Queues: Players are grouped by their geographic region for optimal latency and fairness.
  • Promise-Driven Asynchrony: All operations are non-blocking and structured using robust promise chains.
  • Auto-Match Coordination: One server becomes a match coordinator and is responsible for generating matches based on customizable logic.
  • Private Server Integration: Matches are hosted on dynamically reserved private servers with persistent metadata and lifecycle tracking.
  • Graceful Error Handling: Errors are propagated and isolated cleanly, avoiding unwanted chain continuation.
  • Custom Matchmaking Logic: Plug in your own logic to define how players are grouped into matches.

Documentation:


Demo:


Original theoretical thinking


Release Notes

This is the initial release of the tool. It has been tested on a limited scale (just myself and a second account), so there may be edge cases that aren’t fully handled yet. You’re encouraged to try it out and share any feedback or issues you encounter. It’s also my first time building a tool entirely with Promises, so if you notice any misuses or areas for improvement, I’d really appreciate your guidance.

49 Likes

[v0.2]

  • Fixed an issue where the party data was not registered in the regional queue when using :AddPartyAsync
  • Fixed an issue where the partyremoved event would fire twice for parties which found a match
3 Likes

This is dead? It’s very sad, such a good resource! You need to implement party features to play in the same match with your friends

3 Likes

Hey there! The main goal is to give developers the flexibility to implement their own party system as they see fit, this is why I didn’t develop a party builder module included.

Could you clarify what do you mean by "party features to play in the same match with your friends
"? Note that the system already supports queueing groups of players using :AddPartyAsync(PartyMemberIds, PartyData).

2 Likes

Sorry, I didn’t know. Can I ask if this system will still group players into the same match even when they’re from very different locations? Right now, it seems to separate players by region, but if my game has few players, splitting them could make it hard to find matches. I just want to confirm that distant players can still be grouped when necessary (When the queue is little)

Some important points:

  • For players of the same party: This system works best if the players of the party are in the same server instance (they can be across different location/region in the same party). It could also work if the players of the same party are placed across different servers but you’d need to do the logic of when when the party leader goes into a matchmaking or when it finds a match with messaging service (this is more of a party module to be implemented).
  • Matchmaking across Regions: The current limitation of this system is that if you queue one party in Brazil and another in Europe, they will never be matched. Queuing a party from Spain against one from France is fine, because countries are grouped roughly by continent. I understand the concerns for games with small player bases, but do you really want your players to play with high ping—probably not?

Happy to discuss more :grinning_face:

Can parties made from just 1 player? Also I thought you could implement an algorithm with different weights based on what PolicyService | Documentation - Roblox Creator Hub gives. It is likely what roblox does

Yes, just give a list with one userID.

I guess you are talking about MatchmakingService | Documentation - Roblox Creator Hub but it has its limitations on its own, I recommend reading more documentation on this if you are interested by Roblox’s official matchmaking module.

I was talking about this service that you can use a method to see if an user is 13+ or not, so we could make matchs based on ages like roblox mathmaking does

How do I make a system for ranked matchmaking on this module?
I’m assuming the current version doesn’t have the option to check player’s rating.

This is possible, when you add a party to a queue with :AddPartyAsync, you can add metadata as well and give the rating of each player in the party.

When you create the matchmaking queue with .new the MatchMaking function that you give to the queue will be fire with the parties that are in queue as parameter. See the example given of a solo matchmaker mode in the documentation.

local SoloMatchMaker = MatchMakerService.new({
    Name = "Solo",
    MatchMaking = function(parties)
        local matches = {}
        for _, party in ipairs(parties) do
            table.insert(matches, {
                PlaceId = game.PlaceId,
                Parties = { party },
            })
        end
        return matches
    end,
})
2 Likes

I do not think the latency part is true, because I asked Roblox staff in their post for the Matchmaking, how can you fix the region of the Roblox server that the players are teleported to , to match the region the players are in, and they said you can not set what region the Robox server is in. So this mean , if you are doing a region of all players ( I do not know what the regions are) but but lets say Europe, then all the Europe player can be configured to go to one Region server, but that Region server might not be Europe. The Roblox server could be USA, and now you have tanked all of those Europe players latency because they are now all in a USA Roblox server… So your statement that the ā€˜grouped by their geographic region for optimal latency and fairness.’ is still true because they all got the same tanked latency, and it is fair… but they might be getting better latency if there was not a region setting..

Unless if you can , you have a server for the lobby / queue, and then you already have other game play servers that players are already in (where you want to really teleport region player to) , and can figure out what region that game server is in, and then communicate back to the lobby server what game servers are running in which regions and then send new players to already existing running region servers that match what region they are in.. which also means there always have to be players playing the region servers, and or any new play server will first get players from anywhere until the servers region is sent back to the lobby matchmaking server…

if that makes sense… but over all from what I got doing region matchmaking is pointless..

1 Like

Indeed the ā€œoptimal latencyā€ part is a bit exagerated. There are multiple cons in my appraoch which don’t have an answer today, and I might have relied on some assumptions on my part from Roblox which are not correct:

  • When teleporting a player to an empty private server, Roblox picks the best region for that player. I had a quick check. → This isn’t exactly correct (quick AI check : Roblox chooses a server region at the moment a new server is created based on overall data center availability, load balancing needs, and the dominant player geography for that game rather than for each individual player; developers cannot directly control this, and once a private server is assigned a region, all players teleported into it use that same region regardless of where they are located.)

  • All players in a single region should share the same latency → Not correct due to 1) and also due to the fact that a region can sometimes be quite big and that it might not reflect two players at the opposite side of the same region. Also some players that are next to each other but not the same region would not be match together directly, unless there is a global backup queue.

The more I think about this, the more I tend to suggest using the new matchmaking functionality released by Roblox which has been made open to public recently. It isn’t as flexible as what you could do with this module (due to the limitations on the number of custom signals), but you’ll end up with a better latency between players for sure without a big overhead.

Hey, I recently ran into this error and I was wondering if you know why:

Looks like an internal Roblox error from MemoryStoreService API caused this, I’ll still check regarding the promise rejection not being handled.

1 Like

Hey, the module is really great and I’m seriously surprised about the smaller feedback. but I wanted to ask about something, I’m trying to set minimum required players to start a match (I’m making a shooter game and I want a similar matchmaking to Rivals) but I can’t find any option featuring this so I’m asking if there’s any setting for it.
I just tried in Solo in studio and It told me that it’s teleporting me to a match.

Oh now I’m starting to understand it correctly, so Duo matchmaking pairs 2 people, not 2v2 as I misunderstood, so now I just have to find a way to make even 2v2 matches which will make sure that People can be already paired up in parties but also just solo queuing 2v2.

Also I noticed that Parties do not get removed after player stopped matchmaking or left, as my output prints: [MatchMakerService-2v2-EUW] Retrieved 11 parties

1 Like

Okay so I managed to make the 2v2 system:

local function GetPartySize(party)
	return #party.MemberIds
end

local function Matchmaking2v2(Parties)

	local Matches = {}

	
	if #Parties < 2 then
		return Matches
	end

	local Duos = {}
	local Solos = {}

	-- Split parties
	for _, party in ipairs(Parties) do
		if GetPartySize(party) == 2 then
			table.insert(Duos, party)
		else
			table.insert(Solos, party)
		end
	end

	-- Duo vs Duo
	while #Duos >= 2 do
		local p1 = table.remove(Duos, 1)
		local p2 = table.remove(Duos, 1)

		table.insert(Matches, {
			PlaceId = MatchPlaceId,
			Parties = {p1, p2},
		})
	end

	-- Duo vs 2 Solos
	while #Duos >= 1 and #Solos >= 2 do
		local duo = table.remove(Duos, 1)
		local s1 = table.remove(Solos, 1)
		local s2 = table.remove(Solos, 1)

		table.insert(Matches, {
			PlaceId = MatchPlaceId,
			Parties = {duo, s1, s2},
		})
	end

	-- 4 Solos
	while #Solos >= 4 do
		local s1 = table.remove(Solos, 1)
		local s2 = table.remove(Solos, 1)
		local s3 = table.remove(Solos, 1)
		local s4 = table.remove(Solos, 1)

		table.insert(Matches, {
			PlaceId = MatchPlaceId,
			Parties = {s1, s2, s3, s4},
		})
	end

	return Matches
end

MatchMaker2v2 = MatchMakerModule.new{
	Name = "2v2",
	MatchMaking = Matchmaking2v2,
}
MatchMaker2v2.PartyRemoved:Connect(PartyRemoved)
MatchMaker2v2.PartyAdded:Connect(PartyAdded)

This works great for me but I have tested it just in Studio yet.
I’ll also look at the Parties not being destroyed when player canceled matchmaking or left and try to update yall

1 Like

@Lord_Monever are you sure the Cross-Region matchmaking works?
I’ve had no problems with the matchmaking system until now, when I found out the cross-region matchmaking doesn’t work? It might be me though, thats why I wanted to ask,

I set the CROSS_REGION_TIMEOUT to 5 for testing with my testers, one is from NA, other one from SEA and I’m from EUNE.
image
So we tried to get into a match (FFA) that requires 3 people and we waited for minutes but nothing, it keeps repeating: No match to create (img):

The matchmaking works normally on all modes from the same regions but not from the cross_region and I don’t know how to fix it.

I don’t expect my Playerbase to be big especially in the release of the game so this feature is neccessary for my game.

These are the whole settings in RegionalQueue:

If you could help me I’d be really glad.
Vice

Hi,
I have been checking this resource out for awhile.

Are you able to share your updates, for matchmaking in 2 v 2 duo , teams of 2 , or solo can still play in the 2 v 2 duo teams? Like share a .rbxl of it, or an editable testing place?

Thanks a bunch!