Pokémon Showdown uses three different team formats, each optimized for different use cases:
Export format - Human-readable format for import/export
JSON format - Structured format for programmatic use
Packed format - Compressed format for transmission and storage
The export format is designed to be human-readable and is used in the teambuilder’s import/export features.
Example
Articuno @ Leftovers
Ability: Pressure
EVs: 252 HP / 252 SpA / 4 SpD
Modest Nature
IVs: 30 SpA / 30 SpD
- Ice Beam
- Hurricane
- Substitute
- Roost
Ludicolo @ Life Orb
Ability: Swift Swim
EVs: 4 HP / 252 SpA / 252 Spe
Modest Nature
- Surf
- Giga Drain
- Ice Beam
- Rain Dance
Each Pokemon is separated by a blank line and follows this structure:
SPECIES @ ITEM
Ability: ABILITY
EVs: HP_EVS HP / ATK_EVS Atk / DEF_EVS Def / SPA_EVS SpA / SPD_EVS SpD / SPE_EVS Spe
NATURE Nature
IVs: [non-31 IVs]
- MOVE1
- MOVE2
- MOVE3
- MOVE4
Only non-default values are included (e.g., IVs only shown if not 31, EVs only if not 0).
JSON format is used internally in the Pokemon Showdown codebase. It’s a structured array of PokemonSet objects.
Example
[
{
"name" : "" ,
"species" : "Articuno" ,
"gender" : "" ,
"item" : "Leftovers" ,
"ability" : "Pressure" ,
"evs" : { "hp" : 252 , "atk" : 0 , "def" : 0 , "spa" : 252 , "spd" : 4 , "spe" : 0 },
"nature" : "Modest" ,
"ivs" : { "hp" : 31 , "atk" : 31 , "def" : 31 , "spa" : 30 , "spd" : 30 , "spe" : 31 },
"moves" : [ "Ice Beam" , "Hurricane" , "Substitute" , "Roost" ]
},
{
"name" : "" ,
"species" : "Ludicolo" ,
"gender" : "" ,
"item" : "Life Orb" ,
"ability" : "Swift Swim" ,
"evs" : { "hp" : 4 , "atk" : 0 , "def" : 0 , "spa" : 252 , "spd" : 0 , "spe" : 252 },
"nature" : "Modest" ,
"moves" : [ "Surf" , "Giga Drain" , "Ice Beam" , "Rain Dance" ]
}
]
PokemonSet Type
interface PokemonSet {
name : string ; // Nickname
species : string ; // Species name
gender ?: string ; // M, F, or empty
item ?: string ; // Held item
ability ?: string ; // Ability name
evs ?: StatsTable ; // Effort Values
ivs ?: StatsTable ; // Individual Values
nature ?: string ; // Nature name
level ?: number ; // Level (1-100)
shiny ?: boolean ; // Shiny status
happiness ?: number ; // Happiness (0-255)
moves : string []; // Move names (up to 4)
}
interface StatsTable {
hp : number ;
atk : number ;
def : number ;
spa : number ;
spd : number ;
spe : number ;
}
Packed format is a compressed string representation used for network transmission, logging, and team storage.
Example
Articuno||leftovers|pressure|icebeam,hurricane,substitute,roost|Modest|252,,,252,4,||,,,30,30,|||]Ludicolo||lifeorb|swiftswim|surf,gigadrain,icebeam,raindance|Modest|4,,,252,,252|||||
Line breaks added for readability - this is normally all one line.
Pokemon are delimited by ]. Each Pokemon follows this structure:
NICKNAME|SPECIES|ITEM|ABILITY|MOVES|NATURE|EVS|GENDER|IVS|SHINY|LEVEL|HAPPINESS,POKEBALL,HIDDENPOWERTYPE,GIGANTAMAX,DYNAMAXLEVEL,TERATYPE
Field Details
Pokemon nickname (blank if same as species)
Species name (blank if identical to nickname)
Item ID in lowercase, no spaces
Ability name/ID, OR
0, 1, H for ability slot (preferred for standard abilities)
Comma-separated move IDs (lowercase, no spaces)
Nature name (blank = Serious, except Gen 1-2 = no nature)
Comma-separated: HP,Atk,Def,SpA,SpD,Spe
Blank values = 0
All blank = omit commas entirely
In Let’s Go = AVs instead of EVs
Comma-separated: HP,Atk,Def,SpA,SpD,Spe
Blank values = 31
All blank = omit commas entirely
In Gen 1-2 = DVs (IVs divided by 2, rounded down)
Post-hyper-training values
S for shiny, blank for non-shiny
Pokemon level (blank = 100)
Happiness value (blank = 255)
Pokeball type (blank = regular Poke Ball)
Hidden Power type for hyper-trained Pokemon (blank if not applicable)
G for Gigantamax, blank otherwise
Dynamax level (blank = 10)
Tera Type (blank = first type of Pokemon)
If POKEBALL, HIDDENPOWERTYPE, GIGANTAMAX, DYNAMAXLEVEL, and TERATYPE are all blank, the trailing commas are omitted.
The Teams module provides conversion functions:
const { Teams } = require ( 'pokemon-showdown' );
// Accepts export, JSON string, or packed format
const team = Teams . import ( teamString );
// Returns: PokemonSet[]
const exportedTeam = `
Articuno @ Leftovers
Ability: Pressure
EVs: 252 HP / 252 SpA / 4 SpD
Modest Nature
- Ice Beam
- Hurricane
` ;
const team = Teams . import ( exportedTeam );
console . log ( team [ 0 ]. species ); // "Articuno"
const packedTeam = "Articuno||leftovers|pressure|icebeam,hurricane,substitute,roost|Modest|252,,,252,4,||,,,30,30,|||]" ;
const team = Teams . import ( packedTeam );
console . log ( team . length ); // 1
const exportString = Teams . export ( team );
// Returns: string (human-readable format)
Example:
const team = [{
species: "Pikachu" ,
item: "Light Ball" ,
ability: "Static" ,
moves: [ "Thunderbolt" , "Quick Attack" , "Iron Tail" , "Volt Tackle" ],
nature: "Adamant" ,
evs: { hp: 0 , atk: 252 , def: 0 , spa: 0 , spd: 4 , spe: 252 },
ivs: { hp: 31 , atk: 31 , def: 31 , spa: 31 , spd: 31 , spe: 31 }
}];
const exported = Teams . export ( team );
console . log ( exported );
// Output:
// Pikachu @ Light Ball
// Ability: Static
// EVs: 252 Atk / 4 SpD / 252 Spe
// Adamant Nature
// - Thunderbolt
// - Quick Attack
// - Iron Tail
// - Volt Tackle
const packedString = Teams . pack ( team );
// Returns: string (compressed format)
Example:
const team = Teams . import ( exportedTeam );
const packed = Teams . pack ( team );
console . log ( packed );
// Articuno||leftovers|pressure|icebeam,hurricane,substitute,roost|Modest|252,,,252,4,||,,,30,30,|||]
Unpack (Packed → JSON)
const team = Teams . unpack ( packedString );
// Returns: PokemonSet[]
Example:
const packed = "Pikachu||lightball|static|thunderbolt,quickattack,irontail,volttackle|Adamant|,252,,,4,252|||||" ;
const team = Teams . unpack ( packed );
console . log ( team [ 0 ]. item ); // "Light Ball"
Export Single Set
const setString = Teams . exportSet ( pokemonSet );
// Returns: string (single Pokemon in export format)
Round-Trip Conversions
You can convert between any two formats by going through JSON:
Export → Packed
Packed → Export
const packed = Teams . pack ( Teams . import ( exportedTeam ));
Team Generation
Generate random teams for random battle formats:
const team = Teams . generate ( format , options ? );
Format ID or Format object (e.g., "gen9randombattle")
PRNG seed as array of 4 numbers for reproducible generation
Example
const { Teams } = require ( 'pokemon-showdown' );
// Generate random team
const team = Teams . generate ( 'gen9randombattle' );
console . log ( team . length ); // 6
// Convert to packed format for battle
const packed = Teams . pack ( team );
// Use in battle
stream . write ( `>player p1 {"name":"Player","team": ${ JSON . stringify ( packed ) } }` );
Random team generation only works for formats with team: 'random' in their configuration.
Team Validator
Validate team legality for a specific format:
const { TeamValidator } = require ( 'pokemon-showdown' );
const validator = new TeamValidator ( formatid );
const problems = validator . validateTeam ( team );
Returns null if the team is legal
Returns string[] of problems if the team is illegal
Example
const { Teams , TeamValidator } = require ( 'pokemon-showdown' );
// Import a team
const team = Teams . import ( exportedTeamString );
// Validate for Gen 9 OU
const validator = new TeamValidator ( 'gen9ou' );
const problems = validator . validateTeam ( team );
if ( problems ) {
console . error ( 'Team is illegal:' );
problems . forEach ( problem => console . error ( '- ' + problem ));
} else {
console . log ( 'Team is legal!' );
}
The simulator does not automatically validate teams. Always validate before using teams in non-random formats.
Complete Example
Here’s a complete workflow from export format to battle:
const { Teams , TeamValidator , BattleStream } = require ( 'pokemon-showdown' );
// Import teams from export format
const team1Export = `
Pikachu @ Light Ball
Ability: Static
EVs: 252 Atk / 4 SpD / 252 Spe
Adamant Nature
- Volt Tackle
- Iron Tail
- Quick Attack
- Thunderbolt
` ;
const team2Export = `
Charizard @ Charizardite Y
Ability: Blaze
EVs: 252 SpA / 4 SpD / 252 Spe
Timid Nature
- Flamethrower
- Air Slash
- Roost
- Solar Beam
` ;
// Convert to JSON
const team1 = Teams . import ( team1Export );
const team2 = Teams . import ( team2Export );
// Validate teams
const validator = new TeamValidator ( 'gen9ou' );
const problems1 = validator . validateTeam ( team1 );
const problems2 = validator . validateTeam ( team2 );
if ( problems1 || problems2 ) {
console . error ( 'Teams are not legal for Gen 9 OU' );
process . exit ( 1 );
}
// Pack for battle
const packed1 = Teams . pack ( team1 );
const packed2 = Teams . pack ( team2 );
// Start battle
const stream = new BattleStream ();
stream . write ( `>start {"formatid":"gen9ou"}` );
stream . write ( `>player p1 {"name":"Player 1","team": ${ JSON . stringify ( packed1 ) } }` );
stream . write ( `>player p2 {"name":"Player 2","team": ${ JSON . stringify ( packed2 ) } }` );
Command-Line API
All team operations are available via command-line for non-JavaScript languages:
# Convert packed to export
echo "Pikachu||lightball|static|volttackle,irontail,quickattack,thunderbolt|Adamant|,252,,,4,252|||||" | \
./pokemon-showdown unpack-team
# Validate team
echo '<team string>' | ./pokemon-showdown validate-team gen9ou
# Generate random team
./pokemon-showdown generate-team gen9randombattle
Next Steps
Usage Guide Learn how to use teams in battles
Battle Formats Explore available battle formats