Common Patterns
PokéAPI resources are linked by URL. Once you understand how to traverse those links, you can build rich Pokémon data pipelines without hard-coding anything. This page covers the patterns you'll use most.
Pattern 1 — Follow a linked resource
Almost every field that references another resource includes both name (for display) and url (to fetch the full object). You can traverse the graph by following URLs:
// Fetch a Pokémon, then fetch its primary type
const pikachu = await fetch('https://pokeapi.co/api/v2/pokemon/pikachu').then(r => r.json());
const primaryTypeUrl = pikachu.types[0].type.url;
const electricType = await fetch(primaryTypeUrl).then(r => r.json());
console.log(electricType.damage_relations.double_damage_from.map(t => t.name));
// → ["ground"]Cache the results of URL fetches. The same type, ability, or move URL will appear in thousands of Pokémon responses — fetch it once and reuse it.
Pattern 2 — Resolve sprites
Sprites are in the sprites field and link to static image files hosted on GitHub:
const pokemon = await fetch('https://pokeapi.co/api/v2/pokemon/charizard').then(r => r.json());
// Official artwork (high quality)
const artwork = pokemon.sprites.other['official-artwork'].front_default;
// Classic front sprite
const sprite = pokemon.sprites.front_default;
// Shiny variant
const shiny = pokemon.sprites.front_shiny;{
"sprites": {
"front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png",
"front_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/6.png",
"other": {
"official-artwork": {
"front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/6.png"
}
}
}
}Pattern 3 — Traverse an evolution chain
Evolution chains use a nested chain structure. Each chain node is a ChainLink:
async function getEvolutionChain(pokemonName) {
// Step 1: get the species to find the evolution chain URL
const species = await fetch(
`https://pokeapi.co/api/v2/pokemon-species/${pokemonName}`
).then(r => r.json());
// Step 2: fetch the evolution chain
const chain = await fetch(species.evolution_chain.url).then(r => r.json());
// Step 3: flatten the nested chain into an array
function flattenChain(link) {
return [
link.species.name,
...link.evolves_to.flatMap(flattenChain)
];
}
return flattenChain(chain.chain);
}
console.log(await getEvolutionChain('charmander'));
// → ["charmander", "charmeleon", "charizard"]Pattern 4 — Get all moves a Pokémon can learn
The moves array on a Pokémon lists every move it can learn, including which game version and at what level:
const bulbasaur = await fetch('https://pokeapi.co/api/v2/pokemon/bulbasaur').then(r => r.json());
// Filter to level-up moves in Red/Blue
const levelUpMoves = bulbasaur.moves
.filter(m =>
m.version_group_details.some(
d => d.move_learn_method.name === 'level-up' &&
d.version_group.name === 'red-blue'
)
)
.map(m => ({
name: m.move.name,
level: m.version_group_details.find(
d => d.version_group.name === 'red-blue'
).level_learned_at
}))
.sort((a, b) => a.level - b.level);
console.log(levelUpMoves);
// → [{ name: "tackle", level: 0 }, { name: "growl", level: 0 }, ...]Pattern 5 — Batch fetching with Promise.all
When you need data for multiple Pokémon, use Promise.all to fetch in parallel rather than sequentially:
async function fetchTeam(names) {
return Promise.all(
names.map(name =>
fetch(`https://pokeapi.co/api/v2/pokemon/${name}`).then(r => r.json())
)
);
}
const team = await fetchTeam(['pikachu', 'charizard', 'blastoise', 'venusaur']);
const stats = team.map(p => ({
name: p.name,
hp: p.stats.find(s => s.stat.name === 'hp').base_stat
}));Don't fire hundreds of parallel requests at once — this is the "hammering" the Fair Use policy warns about. For large batches, limit concurrency with a semaphore or process items in chunks of 10–20.
Pattern 6 — Flavour text in a specific language
Use flavor_text_entries to get the Pokédex entry for a specific game and language:
const species = await fetch('https://pokeapi.co/api/v2/pokemon-species/pikachu').then(r => r.json());
const entry = species.flavor_text_entries.find(
e => e.language.name === 'en' && e.version.name === 'firered'
);
// Clean up the text (PokéAPI includes form feeds and soft hyphens)
const text = entry.flavor_text.replace(/\f/g, ' ').replace(//g, '');
console.log(text);
// → "It keeps its tail raised to monitor its surroundings. If you grab its tail,
// it will try to bite you."