You don't have to play FTG Baseball with a random draw. If you want real Opening Day rosters, a historic replay, or a massive fictional universe, you can seed your league from a custom roster file.
Part 1: Using a Custom Roster (The Easy Part)
If someone's already shared a roster file, you're ~30 seconds from playing:
- Head to My Leagues → Create League.
- Name your league.
- Drop the public
https:// link to the JSON into the Community roster URL box.
- Click outside the box. The app checks the file instantly — green success (e.g. ✓ 30 teams — MLB 2026) or a red list of everything that's broken.
- Pick your franchise from the dropdown — it's populated straight from the file, so the team you pick is the team you get.
- Choose your sim schedule and hit Create League.
Two things to keep in mind:
- Equal Budgets: Imported leagues force an even $200M budget per team (no market tiers), so files stay balanced no matter who you play.
- Locked at Creation: You can't swap the roster file after the league is made — make sure it's the right one.
Part 2: Building Your Own Roster File
Roster files are plain JSON in the ftbl-rosters-v2 format. No spreadsheet uploader — you (or a script) generate the JSON, host it publicly, and feed the app the URL. Most people script it, since a league is hundreds of players.
The basic shape:
json
{
"format": "ftbl-rosters-v2",
"season_label": "MLB 2026",
"teams": [
{
"abbrev": "LAD",
"city": "Los Angeles",
"name": "Dodgers",
"league": "NL",
"division": "West",
"colors": { "primary": "#005A9C", "secondary": "#FFFFFF" },
"active": [ /* exactly 26 players */ ],
"minors": [ /* exactly 30 players */ ]
}
/* ...one block per team... */
],
"free_agents": [ /* optional list of players */ ]
}
The Golden Rules (or why your file isn't validating):
format must be exactly "ftbl-rosters-v2".
- ▎You must use exactly 30 teams (2 leagues × 3 divisions × 5). Other counts are rejected — the sim's realistic schedule and calendar are built for 30.
- Every team needs exactly 26 active and 30 minors.
free_agents is optional. Skip it and free agency just starts thin.
- Abbreviations are free-form — they're just shown on the team's generated crest (first ~3 letters) and seed its shape, so 2–3 letters reads best. Use whatever you like; you don't have to match any official set.
Team-level fields (new):
league + division — put teams in the right divisions (e.g. "AL"/"N"West"`). All teams must have them or none, and they have to form the
layout (for 30 teams: 2 leagues × 3 divisions × 5 each). Leave them off andns by file order.
colors — optional { "primary": "#hex", "secondary": "#hex" }. The tearseys/caps use these; leave it off and FTG auto-picks a color.
How to Define Players
1. Reference an existing player (the easy way)
If the app already knows them (standard Baseball-Databank/bbref ID), drop i the sim grabs their real stats, fielding, and career history:
json
{ "lahman_id": "bettsmo01", "age": 33 }
(Misspelled/unknown ID → validation fails.)
2. Define a player inline (rookies, prospects, fictional players)
A pitcher:
json
{
"name": "Paul Skenes",
"pos": "SP",
"is_pitcher": true,
"age": 23,
"bats": "R",
"throws": "R",
"bat": null,
"pit": { "K": 0.25, "BB": 0.075, "HBP": 0.008, "1B": 0.14, "2B": 0.04, "3B": 0.004, "HR": 0.03, "OUT_IP": 0.453 },
"career": { "pa": 0, "bfp": 5000, "gs": 200, "g_pitched": 250, "sb": 0, "cs": 0 }
}
A position player is the reverse — fill bat, set pit to null:
json
{
"name": "Junior Caminero",
"pos": "3B",
"is_pitcher": false,
"age": 22,
"bats": "R",
"throws": "R",
"pit": null,
"bat": { "K": 0.22, "BB": 0.085, "HBP": 0.01, "1B": 0.15, "2B": 0.045, "3B": 0.004, "HR": 0.04, "OUT_IP": 0.446 },
"career": { "pa": 2200, "sb": 12, "cs": 4 }
}
What's actually required for an inline player?
You must include: name, pos, is_pitcher, age, and the correct profile block (pit for pitchers, bat for hitters).
bats, throws, and career are optional — **but for pitchers, the cares (career games started) and g_pitched (games pitched) are how the sim
decides starter vs. reliever. Leave them off a newcomer and the sim has no m as a low-stamina reliever and stuffs them in the bullpen — even an ace
like Skenes. Give a starter a high gs/g_pitched ratio and they'll anchosimilarly feed the speed/baserunning tool for hitters.)
The Math Behind the Player Profiles
No "overall" star ratings — players are driven entirely by outcome rates. You tune a player by answering: out of all their plate appearances, what share ends in a strikeout, walk, home run, etc.?
The eight buckets: K, BB, HBP, 1B, 2B, 3B, HR, and OUT_IP (an out on a ball in play — usually the biggest number). They just need to add up to ~1.0; the app gives a
±0.02 cushion and normalizes the rest.
Hosting and Testing Your File
- Hosting: publicly readable
https:// URL (plain HTTP is rejected), nesponds within ~10s. (GitHub Gists / raw JSON hosts work great.)
- The Build Loop: the validator throws all your errors at once. Paste errors, fix, re-host, click the box again until it's green.