FixtureForge
Turn a list of team names into a dated round-robin fixture list, with home and away balanced as evenly as the draw allows. Built for organisers of small leagues and club competitions.
Not sure the season fits before your finals? Work out the dates first — how many rounds and match weeks your team count needs, and when the last round lands.
New here? A 60-second worked example
- Put your team names in the first box, one per line (2 to 32) — or press Reload 8-team example to fill in eight and build at once. That button changes the team names only; the other boxes keep whatever they already hold.
- Choose the first round date. If you want, also set the days between rounds, a kick-off time, and single or double round robin. Every other box on the page is optional and may be left empty.
- Press Build fixture list. The dated list and the home, away and byes table appear below, in this page; nothing you type is sent anywhere.
- Press Copy list to paste it elsewhere, or print the page for paper. To see what each optional box does, press Fill every option example — it puts one working line in every box and builds.
Nothing is saved: reload the page and the list is gone, so copy or print it first. If something looks wrong, the page says so in a message above the list instead of printing a broken draw.
Commas or semicolons work too. Blank lines are ignored. The names above are an example — replace them with your own.
Spare week: round numbers separated by commas, for example 3, 9. Each one puts a week with no matches right after that round — for a cup weekend or a winter break — and the rounds after it move later. No fixtures are lost.
The grounds box takes one ground, or several written one per line (up to 8): with two or more, the matches of a round are shared out between them and the turn moves on each round, so the same ground is not always holding the first game of the day. A ground shows up after the kick-off time on every match line it applies to, and in the Venue column of the spreadsheet block below; a single match, a whole round, or a run of rounds or matches can be sent to a ground out of turn with the match venue box further down, or right after a time in the match time box. No pairing, date, time or home and away count is ever changed by either venue box. To leave a fixture out altogether, name it in the drop box further down.
One line per round, written as round number = YYYY-MM-DD. Use it for a winter break or a cup weekend. A round you do not list simply keeps the usual spacing from the round before it, and the list marks every round whose date you set.
One line per round, written as round number = HH:MM (24-hour). Those rounds use their own time instead of the single kick-off time above; every round you do not list keeps that one. Every match in the round shares that time unless you give one its own time in the match box below.
One line per match, written as R1M2 = HH:MM (24-hour): R is the printed round number and M is the match number inside that round. A whole round is written R5 = 16:30, which covers every match of round 5 without your counting them, and several whole rounds together are written R7-R9 = 11:00 (rounds 7, 8 and 9). A run of matches inside or across rounds is written R3M1-M3 = 16:30 (matches 1 to 3 of round 3) or R1M1-R3M2 = 16:30 (from match 1 of round 1 up to match 2 of round 3).
The match numbers count only real matches, in the order printed, and start again at 1 in every round; sit-out lines are not counted. A match you name wins over both boxes above for that one fixture — handy when two games in a round cannot kick off together. A line may also carry a ground after the time, written R1M2 = 14:00 @ Northgate Pitch: the fixture then gets that time and that ground, which is the same as also writing it in the match venue box below, and either form can be used for a whole round or a run just as well. The other way round, a line reading R7M1 = none gives those fixtures no time at all, even where the single time or their round's time would have applied ("no time", "tbc", "blank", "empty" and "-" mean the same); their match line ends with no time and their Time cell in the spreadsheet block is empty.
One line per match, written as R1M2 = Ground name, using the same round and match numbers as the match time box above. R4 = Harbour Park sends the whole of round 4 to that ground, and R7-R9 = Vale Road sends rounds 7, 8 and 9 there in one line. A run of matches works too, written R4M1-M2 = Harbour Park. Those fixtures get their own ground — printed after the time on the match line and written in the Venue column of the spreadsheet block — while every other match keeps the ground the box above gives it, or none at all if that box is empty. Handy when one game in a round is played somewhere else, or a whole run of rounds is away from the usual ground. A ground can just as well be written on the end of a time, as R1M2 = 14:00 @ Harbour Park in the box above; both spellings do the same thing, and naming the same fixture twice stops the whole build with a message instead of guessing.
A line reading R6M2 = none works the other way round: those fixtures are given no ground at all, even where the grounds box above would have placed them, so one match can be taken out of a rotation ("no ground", "no venue", "blank", "empty" and "-" mean the same). No pairing, date, time or home and away count is changed by this; a match you name wins over the grounds box above.
The round-robin draw always gives every pair a match; this box is for the ones that are not going to happen. One fixture per line, written R6M2 — round 6, its second match — using the same round and match numbers as the two boxes above. A whole round is written R12, a run of whole rounds R7-R9, and a range of matches R1M1-M3; "R6M2 = off" works as well.
A dropped fixture is left out of the list, the spreadsheet block and the home and away table, and the summary says how many went and names any team left with no match at all. When exactly one fixture is dropped, the summary also names that fixture in full, with its round and both teams, so you can see which one line did it. The numbers are the ones the list would print with nothing dropped, so a drop line never changes what another line means.
Leave every time box empty and no time is shown at all. Set the single time — for example 19:45 — and each match line ends with it; the round box overrides it for the rounds you name, and the match box overrides both for the matches you name, one at a time, as a whole round, as a run of whole rounds, or as a range of matches. A range counts a whole run of matches in one line, so "R1M1-M4" covers all four games of an eight-team round, "R2" on its own covers all of round 2 and "R2-R5" covers rounds 2 to 5 without your counting anything. A ground named on one of those lines, after an @, is written on the match lines and in the Venue column of the spreadsheet block exactly as if it had been written in the venue boxes, so one line can place a fixture in time and place at once.
A "none" line in the match time box is the one thing that takes a time away again, and a "none" line in the match venue box is the one thing that takes a ground away. The checkbox adds a second block below the list: one row per match, ready to paste into a spreadsheet.
The example buttons save you filling in the forms by hand, and neither of them hides anything: every line they write is one you could have typed yourself. "Reload 8-team example" puts eight team names in the box above, leaves every other box exactly as it is, and builds at once — so if a box further down already holds a line the page cannot read, the message about it stands until you fix or clear that box.
"Fill every option example" puts one working line in every optional box and builds; it keeps your own team names when two or more are already in the box, and only puts the eight-team example in when that box is empty or holds fewer than two names. What it writes: two grounds taking turns, a single kick-off time, one round given its own time, a match given its own time and ground together, a second match time reading "none" so that fixture shows no time, a whole round sent to one ground, a venue line reading "none" so that fixture shows no ground, one dropped fixture, one round given a set date, a spare week after round 5 (after the last round the draw has, when it has fewer than five), and the spreadsheet block ticked. Every line is worked out from the teams and the first round date in the form, so the example always fits what you have typed; with a draw too small to hold them all, some of the optional lines are left out rather than aiming at a round or a match the draw does not have.
"Clear the option boxes" empties every optional box — including the reset lines this example writes — and leaves the team names, the first round date, the gap, the format and the layout exactly as they are.
Fixture list
Tip: print this page (Ctrl or Cmd + P) for a paper copy. The form, the buttons, the footer and this tip are left off, so only the fixture list and the home, away and byes table go on the paper, and the list is never cut short. The spreadsheet block is never printed — that is what its copy button is for.
If a long season needs too many pages, set List layout to "one round per line" first: it is the same fixtures, dates and times, written on far fewer lines. Paper size, margins and any page breaks are the browser's job and are not set by this page.
Home, away and byes
Spreadsheet export (CSV)
One row per match — Round, Date, Home, Away, Time. A Venue column is added when you typed a ground into the box above or named one for a match: a row holds that match's own ground when you named one (in the match venue box or after a time on a match time line), otherwise the ground the box above gives that match — with one ground there that is the same name on every row, with several they take turns through each round — and an empty cell when neither applies, including a fixture you gave the ground "none". That is the same ground the match line above prints after the time. In the double round robin there is also a Leg column (1 for the first half of the season, 2 for the reverse half), so every row says which meeting of the pair it is.
The Time column holds the time that match shows in the list: its own time when you named it in the match box, otherwise its round's time, and empty when no time applies — including a fixture you gave the time "none". The date is written as YYYY-MM-DD so a spreadsheet reads it as a date, sit-out rows are left out, and a fixture named in the drop box adds no row at all. Spare weeks have no matches, so they add no rows. Not printed; copy it and paste it into a spreadsheet.
About this tool and how the draw works
FixtureForge is a single static page, built by an AI agent. It runs entirely in your browser: nothing you type is uploaded or saved anywhere, and if you reload the page the list is gone. Copy or print it before you leave. If you only want to know how long the season takes and when it would finish, the season date planner on the next page counts the rounds and the weeks for you.
The pairings use the fixed circle method, not a random draw: the same team names in the same order always produce the same fixture list, so you can re-run it and compare. Each pair meets exactly once per leg, and home and away are then handed out match by match — whichever team has had fewer home games so far gets the home slot. That keeps the home and away totals within one game of each other wherever the team count allows, and the table under the list reports the exact counts per team so you can check.
Dates: the first round takes the date you picked, and each round after it sits the chosen number of days after the round before it. The optional round-dates box overrides that for the rounds you name — one line each, in the form "round number = YYYY-MM-DD" — and later rounds carry on from the new date, so a set date moves the rounds after it too. Rounds must still run in order: a date earlier than the week before it is refused rather than printed, and a round number outside the draw is refused with a message saying how many rounds this draw has.
Spare weeks: the optional spare-week box takes round numbers, for example "3, 9", and puts a match-free week straight after each of those rounds. It is meant for a cup weekend, a holiday or a winter break. Because it only adds a week to the calendar, every fixture is still played once: the pairings, the home and away counts and the number of matches do not change at all, and the rounds after a spare week are dated later by one gap. In the list a spare week is labelled "Spare week" with its date and "(no matches)" rather than a round number, so the round numbering of the fixtures stays as it was. A spare week cannot carry its own date; put the date on the round before it or after it, or use the round-dates box. Spare weeks add no rows to the CSV block.
Times: the single kick-off time covers the whole competition and is appended to each match line. The per-round box overrides it for the rounds you name — one line each, in the form "round number = HH:MM" — and a round you do not list keeps the single time, or shows no time at all when that box is left empty.
The per-match box is the finest of the three: one line per match, in the form "R1M2 = HH:MM", where R is the printed round number and M is the match number inside that round. One line can name a whole round as "R5 = HH:MM", which covers every match that round holds; several whole rounds as "R7-R9 = HH:MM", which covers rounds 7, 8 and 9; or a run of matches, written "R1M1-M3 = HH:MM" for matches 1 to 3 of round 1, or "R1M1-R3M2 = HH:MM" to run from match 1 of round 1 up to match 2 of round 3. Every match the line covers gets that value. A match time line can also carry a ground after the time, written "R1M2 = 14:00 @ Northgate Pitch", which is worked out before the readers run: the fixture gets that time and that ground, exactly as if the ground had been written in the match venue box, and the forms above (whole round, run of rounds, range of matches) work with the @ spelling too. The match numbers count only real matches, in the order they are printed, and start again at 1 in every round, so they survive spare weeks and the reverse half of a double draw; a sit-out line is never counted.
Messy input is refused as a whole rather than half-applied: a line that is not in one of the forms above, a round or match number this draw does not have (the message says how many it has), a range that runs backwards or ends past the last round, or an overlap where two lines name the same match.
A match with its own time shows that time in the list and in the CSV block; every other match keeps its round's time. A match line whose value is "none" (also "no time", "tbc", "blank", "empty" or "-") does the opposite: the fixtures it covers show no time at all, even where the single time or their round's time would have applied, and their Time cell in the spreadsheet block is left empty.
Only 24-hour values such as 09:05 or 19:45 are accepted; anything else is reported as an error instead of being printed. A line whose left-hand side before the @ is neither a readable time nor "none" is not split at all — it is reported as a time error, so a mistyped time is never quietly turned into a ground.
Grounds: the grounds box takes one ground or several, written one per line (up to 8), for example "Riverside Sports Ground" and "Northgate Pitch". With one ground every match is played there. With two or more, the matches of a round are shared out between them in turn — the first match of the round at the first ground, the second at the second, and so on — and the turn moves on by one each round, so the same ground is not always holding the first game of the day and a team's games are not always at the same ground.
The optional match venue box can still send a single fixture, a whole round, or a run of rounds or matches to a ground out of turn: it works exactly like the time boxes — one line per match in the form "R1M2 = Ground name", a whole round as "R4 = Ground name" (every match of round 4, however many that round holds), a run of whole rounds as "R7-R9 = Vale Road", or a range of matches as "R1M1-M3 = Ground name" — and a match you name wins over the rotation for that one fixture. A ground can also be written on the end of a time in the match time box, as "R1M2 = 14:00 @ Harbour Park"; that is read as a time and a ground and does the same job as a line here, so a fixture can be placed in time and place with one line, and a fixture named in both places (or twice in the same box) stops the build with a message rather than picking one.
A venue line reading "none" (also "no ground", "no venue", "blank", "empty" or "-") is the one that takes a ground away: the fixtures that line covers are given no ground at all, even where the grounds box above would have sent them, so a single match can be pulled out of a rotation. Those matches show no ground after the time and have an empty Venue cell, and the summary says how many were left without one.
Whichever way a ground is decided, it is printed after the kick-off time on the match line and written in the Venue column of the spreadsheet block, which appears as soon as any venue line or grounds box has something in it, so the list and the paste agree. With every venue box empty nothing is printed and the CSV block has no Venue column. None of them changes a pairing, date, time or home and away count; a ground name longer than 60 characters or a list of more than 8 grounds is refused with a message.
Fixtures not played: the round-robin draw gives every pair a match, and the drop box is the way to take one back out. Each line names a fixture with the same round and match numbers as the time and venue boxes — "R6M2" for round 6, its second match — and a whole round ("R12"), a run of whole rounds ("R7-R9") or a range of matches ("R1M1-M3") can be named in one line, one per line in the box. A trailing "= off" or "= skip" is accepted and ignored, so "R6M2 = off" also works.
Those numbers are the ones the list would print with nothing dropped, so a drop line never moves the meaning of another line, and the rest of the draw is untouched: every other pairing, date and time is exactly what it would have been. A dropped fixture is left out of the printed list, out of the CSV block and out of the home and away table, which is why that table can look uneven after a drop — the summary says how many fixtures went, names the single dropped fixture in full when there is just one of them, and the table says out loud that the dropped fixtures are not counted and reports the home-away gap of the fixtures still being played.
A round whose every fixture is dropped is still printed, dated, as "(no fixtures played)"; a team left with no match at all is named in the summary; and a drop box that would take out every match in the draw is refused with a message rather than printing an empty list.
List layout only changes how the same fixtures are written out. "One match per line" is the standard list; "one round per line" puts every match in a round on a single line separated by a bar, which fits a long season on far fewer lines. It never changes the pairings, dates, times or home and away counts, and the copy button copies whichever layout you picked.
The spreadsheet block is a plain comma-separated table, one row per match, with the round number, the date, the home team, the away team and the kick-off time. In the double round robin it starts with one extra column, Leg, holding 1 for the rounds in the first half of the season and 2 for the reverse half, so two rows for the same pair of teams can always be told apart; in the single round robin the block has no Leg column. When a ground applies the order is Round, Date, Home, Away, Venue, Time. Any team name or ground containing a comma or a quote is wrapped in quotes, so the columns survive the paste. It is not printed.
Printing: use your browser's print and the form, footer and controls drop out, leaving just the fixture list and the home/away table; the spreadsheet block is not printed, so use its copy button to paste it into a spreadsheet. Paper size, margins and page breaks are left to the browser, and the print tip above the list offers the compact layout when a long season would otherwise run onto many pages. There is no PDF download button — the browser's own "save as PDF" in the print dialog does that.
Known limits: the drop box can only remove fixtures, never add one; a ground or a time named for a fixture you have dropped is simply ignored; the grounds in the box above take turns through a round rather than being chosen freely, so a particular match still needs a line of its own to be sent out of turn; a "none" line can only take a ground or a time away, it never names a new one; the @ spelling on a match time line carries one ground for the fixtures that line covers and cannot also name a second one; the option example is written for the usual draw, so with a very small draw some of its lines are left out; and there are no cup brackets and no file download, so export is copy, print or paste. Not run in a browser — the checks are code reading, so please report anything odd.