Basics

  • All files are under https://eu5db.com/data/.
  • Each game version has its own folder, named by a version ID such as 1.4.7-0df48df2740c. Read versions.json to find them. default is the latest stable version; public betas are marked beta.
  • The format can change when the site is updated. The types at the bottom of this page are always current.
  • Please be kind to the server: if you need everything, download it once instead of fetching on every request.

Files

PathContents
versions.jsonEvery published game version, newest first, which one is the default, and which are betas.
<version>/manifest.jsonConcept types with their counts, plus node and edge totals.
<version>/index.json[id, name, icon] for every node. Use it to search or to list all IDs.
<version>/search.jsonThe index without script machinery and graphics files (script values, defines, interface…): what the site's search loads first.
<lang>/<version>/index.jsonA translation's index: [id, name, icon, English name], the English name only where it differs.
<version>/lists/<concept>.jsonOne summary row per node of a concept type, as shown in the tables.
<version>/requirements/<concept>.jsonNode ID → its requirements: its condition fields, and a policy's law's. Only concept types with condition fields have one.
<version>/nodes/<shard>.jsonFull details for every node in one shard, keyed by node ID.
<version>/links/<hash>.jsonLinks left out of a node's details: each link group (direction, kind, concept at the other end) lists its first 100, and the node's more names the groups cut and their sizes. The file is named by the node ID's FNV-1a hash in eight hex digits, and maps node ID → { out, in }.
<version>/hashes.jsonNode ID → content hash. The hash changes when the node's content changes.
<version>/changes.jsonNodes added, removed and changed since the previous version.
<version>/map/geography.jsonContinents down to provinces, every location with its terrain (column by column), and the map colours of what they name.
<version>/map/connections.jsonLocation → its neighbors, sea crossings and ports.
<version>/map/locations.bin.gzThe location bitmap at half size, run-length encoded and gzipped: see the Map section.
<version>/map/<date>.jsonA start scenario, named by its start date: owners, controllers, cores, ranks, roads and markets.
<version>/map/<date>.pops.jsonThe start scenario's pops: location → its pops.
<version>/map/rivers.jsonEvery river as a line from upstream to downstream, with its width.
<version>/map/names.jsonLocation and division key → name. Other languages: <lang>/<version>/map/names.json.
assets/<file>Icons and illustrations. The icon fields hold these file names.

Node IDs

A node ID is concept:key, for example law:administration_of_italian_lands_law. It's the same as the node's page address on this site, /concept/key. Edges and modifiers refer to other nodes by ID.

Map

The map/ files describe the game map: which province, area, region, subcontinent and continent each location belongs to, its terrain, and which locations border it. manifest.map.scenarios lists the start scenarios, currently only 1337.4.1.

  • Values are game keys. The type comments say which concept a field names, so culture: "swedish" is the node culture:swedish and an owner "SWE" is country:SWE.
  • Divisions are listed by level, each pointing to its parent: provinces[key] is its area, areas[key] its region, and so on. A key is unique within its level only: a province can share its key with one of its locations.
  • neighbors come from the game's location bitmap, so they include sea zones and lakes along a coast. Check the neighbor's kind to keep only land borders.
  • geography.locations is stored column by column: keys[i] is the location whose index is i, and entry i of every other column is its value (or null). The example below turns it back into one object per location.
  • center is in bitmap pixels (width × height), with y growing downwards.
  • locations.bin.gz is the map itself at half size, gzipped. Little-endian: u32 width, height and run count, then every run's u16 value, then every run's u16 length. Runs fill the image row by row from the top left. A value is a location's index, or 65535 for no location.
  • rivers.json is present when manifest.map.rivers is true. Its points are in the same pixels as center, in the order the water flows: a tributary ends on the river it joins, and a branch of a delta starts on the river it leaves. A river is cut into several lines where its width changes.
const map = "https://eu5db.com/data/1.4.7-0df48df2740c/map";
const geo = await fetch(`${map}/geography.json`).then((r) => r.json());
const start = await fetch(`${map}/1337.4.1.json`).then((r) => r.json());

// One object per location, from the columns.
const { keys, ...columns } = geo.locations;
const locations = Object.fromEntries(keys.map((key, index) => [key, Object.fromEntries(
  Object.entries(columns).map(([field, values]) => [field, values[index]]))]));

// Every location in Scandinavia, with its 1337 owner.
const regionOf = (key) => geo.areas[geo.provinces[locations[key].province]];
const scandinavia = keys.filter((key) => regionOf(key) === "scandinavian_region");
console.log(scandinavia.map((key) => [key, start.locations[key]?.owner]));

Finding a node's shard

Nodes are split across 256 files so that a page only downloads a small part of the data. To find which file holds a node, hash its ID with 32-bit FNV-1a, take the result modulo 256, and write it as two lowercase hex digits:

  1. Start with hash = 0x811c9dc5.
  2. For each byte of the ID in UTF-8: hash = (hash XOR byte) × 0x01000193, keeping the low 32 bits.
  3. The shard is hash mod 256, zero-padded to two hex digits: 00 to ff.
function shardOf(id) {
  let hash = 0x811c9dc5;
  for (const byte of new TextEncoder().encode(id)) {
    hash ^= byte;
    hash = Math.imul(hash, 0x01000193) >>> 0;
  }
  return (hash % 256).toString(16).padStart(2, "0");
}

Shard d2 → https://eu5db.com/data/1.4.7-0df48df2740c/nodes/d2.json

Example

const base = "https://eu5db.com/data";
const { default: version } = await fetch(`${base}/versions.json`).then((r) => r.json());

const id = "estate_privilege:noble_serfdom_rights";
const shard = await fetch(`${base}/${version}/nodes/${shardOf(id)}.json`).then((r) => r.json());
const node = shard[id];

console.log(node.name, node.modifiers, node.out, node.in);

With curl: curl https://eu5db.com/data/1.4.7-0df48df2740c/lists/law.json

Types

Optional fields are left out of the JSON when they're empty. body is the parsed game script; see a node file for its shape.

export type Manifest = { version: VersionInfo, concepts: Array<ConceptInfo>, nodeCount: number, edgeCount: number, shardCount: number, diagnostics: Array<DiagnosticCount>, 
/**
 * Present when the version has map data (`map/`).
 */
map?: MapInfo, 
/**
 * Scripted triggers that hold once their `type` was unlocked ([`crate::game::GameSpec::unlock_checks`]):
 * pages show what unlocks it alongside the check.
 */
unlockChecks?: Array<string>, 
/**
 * The dates the game runs between, `START_DATE` and `END_DATE` in the defines (mods may move
 * them): pages draw date windows along this span.
 */
startDate?: string, endDate?: string, };

export type Index = { nodes: Array<[string, string | null, string | null]>, };

export type TranslatedIndex = { nodes: Array<[string, string | null, string | null, string | null]>, };

export type ListRow = { id: string, key: string, name?: string, icon?: string, 
/**
 * Its description, for concepts whose lists show it ([`crate::concept::Concept::row_desc`]).
 */
desc?: string, dlc?: string, 
/**
 * The mod that defines it, when mods are loaded.
 */
mod?: string, 
/**
 * Only some countries can have it, for who they are; see [`crate::model::Node::exclusive`].
 */
exclusive?: boolean, parent?: string, 
/**
 * Its place among its `parent`'s children in the game's files: the order the game lists
 * them in (a game rule's settings).
 */
order?: number, 
/**
 * How many definitions link to it, by kind, for the kinds its concept counts
 * ([`crate::concept::Concept::row_counts`]).
 */
counts?: { [key in EdgeKind]?: number }, 
/**
 * Every definition that holds it (`contains`), when that isn't just its `parent`: a
 * production method several buildings have.
 */
partOf?: Array<string>, props?: { [key in string]: JsonValue }, propLabels?: { [key in string]: { [key in string]: string } }, modifiers?: Array<ModifierEntry>, 
/**
 * What its amounts add up to and its baseline, to compare it with the others built on the
 * same baseline (the page has the layers).
 */
stack?: Stack, 
/**
 * Structural outgoing edges (membership, prerequisites, unlocks, event chains).
 */
out?: Array<EdgeRef>, 
/**
 * How long it lasts where effects apply it; see [`durations`].
 */
durations?: Array<Duration>, };

export type NodeDetail = { out: Array<EdgeRef>, in: Array<EdgeRef>, 
/**
 * Requirements declared on the definitions it belongs to (a policy's law). Its own are its
 * body's condition fields (the manifest's `conditions`).
 */
inherited?: Array<RequirementSource>, durations?: Array<Duration>, 
/**
 * The link groups cut to [`LINK_CAP`]: their full sizes. The rest of each is in the
 * node's [`links_file`].
 */
more?: Array<LinkGroup>, id: string, concept: string, key: string, name?: string, desc?: string, 
/**
 * The game's own guide to it, after its description ([`crate::concept::Concept::guide`]).
 */
guide?: string, 
/**
 * The modder's comment on the definition in its script, for a definition the game doesn't
 * describe: not the game's text, so pages set it apart.
 */
note?: string, 
/**
 * How the engine applies the definition where its script doesn't say, as a note the web
 * app words ([`crate::game::Hooks::mechanics_note`]).
 */
mechanics?: string, 
/**
 * Game-relative asset path; replaced by a published file name when assets are exported.
 */
icon?: string, 
/**
 * Large picture for the top of the page; an asset path like `icon`.
 */
illustration?: string, file: string, line: number, 
/**
 * Blocks other files add to the definition (`INJECT:`, merged on_actions), in load order.
 * The body holds their items after its own, and their line numbers are in their own file.
 */
injected?: Array<SourceRef>, dlc?: string, 
/**
 * The mod that defines it, when mods are loaded.
 */
mod?: string, 
/**
 * Every mod whose script is in the definition, in load order: the one that defines it and
 * the ones that merge into it (`INJECT`).
 */
mods?: Array<string>, 
/**
 * Only some countries can have it, for who they are (a tag, a culture, a religion…), as the
 * game's own stages work it out; what kind of country they are (a government) doesn't count.
 */
exclusive?: boolean, parent?: string, props?: { [key in string]: JsonValue }, 
/**
 * Property field → raw value → localized display label. Raw values remain in `props`.
 */
propLabels?: { [key in string]: { [key in string]: string } }, modifiers?: Array<ModifierEntry>, 
/**
 * Amounts that add up across definitions (a unit's stats); see [`crate::concept::Stacking`].
 */
stack?: Stack, body: Block, 
/**
 * Localized text for localization keys appearing in the body.
 */
locs?: { [key in string]: string }, 
/**
 * Icons for things the body names that aren't nodes (a societal value's side), by the same
 * keys as `locs`: game-relative asset paths, replaced by published file names like `icon`.
 */
icons?: { [key in string]: string }, 
/**
 * Token → node id for every resolved reference in the body (drives links in the UI).
 */
links?: { [key in string]: string }, 
/**
 * Token → number for references to constant script values, shown next to the name.
 */
values?: { [key in string]: JsonValue }, 
/**
 * Token → modifiers of the definition it names, for concepts whose modifiers are shown
 * where they are named ([`crate::concept::Concept::modifiers_where_named`]).
 */
namedModifiers?: { [key in string]: Array<ModifierEntry> }, 
/**
 * Token → properties of the definition it names that are shown beside its name
 * ([`crate::concept::Concept::props_where_named`]).
 */
namedProps?: { [key in string]: { [key in string]: JsonValue } }, 
/**
 * Token → place id (`region:balkan_region`, see [`crate::game::GameSpec::place_levels`]) for every
 * resolved place on the map in the body (drives map links in the UI).
 */
places?: { [key in string]: string }, 
/**
 * Fields of the body cut to their first entries, too long to show whole, by line.
 */
trimmed?: Array<Trimmed>, };

export type EdgeRef = { node: string, kind: EdgeKind, via: string, 
/**
 * See [`Edge::keywords`].
 */
keywords?: Array<string>, value?: JsonValue, 
/**
 * See [`Edge::scale`].
 */
scale?: JsonValue, 
/**
 * See [`Edge::scale_range`].
 */
scale_range?: Record<string, [number | null, number | null]>, 
/**
 * See [`Edge::by_name`].
 */
byName?: ByName, 
/**
 * See [`Edge::at`].
 */
at?: Threshold, };

export type EdgeKind = "contains" | "belongs_to" | "requires" | "unlocks" | "triggers" | "grants" | "removes" | "changes" | "calls" | "modifies" | "references" | "weighs" | "mentions";

export type ModifierEntry = { 
/**
 * `modifier_type:<key>` node id.
 */
modifier: string, value: JsonValue, 
/**
 * One of the game's [`crate::game::GameSpec::scopes`], whose union its own file declares.
 */
scope: import("./Scope").Scope, 
/**
 * Path of the block the entry was found in.
 */
via: string, 
/**
 * What the game multiplies the value by, as a stat (`scale = { value = x multiply = 0.01 }`
 * in the block, or the definition's own scale field): see [`crate::concept::Concept::modifier_scale`].
 */
scale?: JsonValue, 
/**
 * The values the scale reads, as far as the conditions the entry applies under bound them
 * (`limit = { purity > 75 }`): `{ "purity": [75, null] }`, least and most, `null` for no bound.
 */
scale_range?: Record<string, [number | null, number | null]>, };

export type RequirementSource = { 
/**
 * Definition declaring these conditions (may be a parent law).
 */
source: string, body: Block, links: { [key in string]: string }, locs: { [key in string]: string }, values: { [key in string]: JsonValue }, places?: { [key in string]: string }, 
/**
 * The node's `icons` for things these conditions name.
 */
icons?: { [key in string]: string }, };

/**
 * What the manifest says about the map.
 */
export type MapInfo = { 
/**
 * Scenario file names (start dates), in order.
 */
scenarios: Array<string>, 
/**
 * The version has `rivers.json`.
 */
rivers: boolean, 
/**
 * The version has pictures of its map (`map/preview-*` and `map/band-*`).
 */
pictures?: boolean, };

/**
 * `geography.json`: [`Geography`] with its locations column by column ([`LocationColumns`]).
 */
export type Geography = { 
/**
 * Size of the location bitmap in pixels. `center` coordinates are in this space, with y
 * growing downwards.
 */
width: number, height: number, 
/**
 * The map wraps around horizontally: the left and right edges touch.
 */
wrapX: boolean, continents: Array<string>, 
/**
 * Subcontinent → continent.
 */
subcontinents: { [key in string]: string }, 
/**
 * Region → subcontinent.
 */
regions: { [key in string]: string }, 
/**
 * Area → region.
 */
areas: { [key in string]: string }, 
/**
 * Province → area.
 */
provinces: { [key in string]: string }, locations: LocationColumns, 
/**
 * Concept → key → `rrggbb` map colour, for every definition the map data names that has one
 * (countries, religions, cultures, terrain, goods, ranks).
 */
colors: { [key in string]: { [key in string]: string } }, 
/**
 * Topographies of open water: lakes (`is_lake`) and those the game tags as ocean. An
 * impassable location with one is impassable sea.
 */
waterTopographies: Array<string>, terrain: Terrain, 
/**
 * How subjects take their overlord's colour; none in versions without its defines.
 */
subjectColors?: SubjectColors, 
/**
 * The continent the map opens on: where the main menu's featured countries start.
 */
focus?: string, };

/**
 * `geography.json` stores locations column by column: entry `i` of each column belongs to the
 * location whose `index` is `i`, the `i`th of the sorted `keys`. With 28,000 locations, field
 * names would otherwise be most of the file.
 */
export type LocationColumns = { keys: Array<string>, color: Array<string | null>, province: Array<string>, kind: Array<LocationKind>, topography: Array<string | null>, vegetation: Array<string | null>, climate: Array<string | null>, religion: Array<string | null>, culture: Array<string | null>, modifier: Array<string | null>, rawMaterial: Array<string | null>, naturalHarborSuitability: Array<number | null>, pixels: Array<number>, center: Array<[number, number] | null>, };

export type Location = { 
/**
 * Position in the sorted location keys; the value of its pixels in `locations.bin.gz`.
 */
index: number, 
/**
 * `rrggbb` colour of the location in `locations.png`.
 */
color?: string, province: string, kind: LocationKind, 
/**
 * `topography`.
 */
topography?: string, 
/**
 * `vegetation`.
 */
vegetation?: string, 
/**
 * `climate`.
 */
climate?: string, 
/**
 * `religion` of the location template. A scenario's pops say who actually lives there.
 */
religion?: string, 
/**
 * `culture` of the location template.
 */
culture?: string, 
/**
 * `static_modifier` the location always has.
 */
modifier?: string, 
/**
 * `goods` the location produces.
 */
rawMaterial?: string, naturalHarborSuitability?: number, 
/**
 * Size in bitmap pixels.
 */
pixels: number, 
/**
 * Mean position of its pixels.
 */
center?: [number, number], };

export type LocationKind = "land" | "sea_zone" | "lake" | "impassable_mountains" | "non_ownable";

export type Connections = { 
/**
 * Locations sharing a border, of any kind (land, sea zone, lake…).
 */
neighbors?: Array<string>, 
/**
 * Crossings over water to locations that share no border (`adjacencies.csv`), on both ends.
 */
crossings?: Array<Crossing>, 
/**
 * Sea zones the location has a port on.
 */
ports?: Array<string>, };

export type Crossing = { to: string, 
/**
 * The sea zone crossed.
 */
through: string, };

export type Scenario = { 
/**
 * Start date, `START_DATE` in the defines, such as `1337.4.1`.
 */
date: string, 
/**
 * Locations the scenario sets anything on besides pops.
 */
locations: { [key in string]: ScenarioLocation }, 
/**
 * Countries the scenario sets anything on, by tag.
 */
countries: { [key in string]: ScenarioCountry }, 
/**
 * Locations that start as market centers.
 */
markets: Array<string>, 
/**
 * Roads between two locations.
 */
roads: Array<[string, string]>, };

export type ScenarioLocation = { 
/**
 * `country` tag.
 */
owner?: string, 
/**
 * `country` tag.
 */
controller?: string, 
/**
 * How far the owner has integrated it: `core`, `integrated`, `conquered` or `colony`.
 */
integration?: string, 
/**
 * `country` tags holding a core on it.
 */
cores?: Array<string>, 
/**
 * `location_rank`.
 */
rank?: string, 
/**
 * `country` tags of the pop-based countries (`type = pop`, the game's societies of pops)
 * whose pops live here: the locations of their `add_pops_from_locations`.
 */
popBased?: Array<string>, 
/**
 * `country` tags of the building-based countries (`type = building`, the game's
 * extraterritorial countries) owning a building here in the `building_manager`.
 */
buildingBased?: Array<string>, };

export type ScenarioCountry = { 
/**
 * Location key.
 */
capital?: string, 
/**
 * `country` tag of its overlord, when it is a subject.
 */
overlord?: string, 
/**
 * `subject_type`.
 */
subjectType?: string, 
/**
 * A subject drawn in a shade of its overlord's colour: its subject type's
 * `use_overlord_map_color`, yes unless it says no (tributaries and imperial free cities do).
 */
overlordColor?: boolean, 
/**
 * `is_valid_for_release = no`: no country holding its cores can release it.
 */
unreleasable?: boolean, 
/**
 * `culture`: a country that holds cores but no land at the start, which the owners of its
 * cores can release, has its definition's `culture_definition` here, the culture it is
 * released with.
 */
culture?: string, };

export type Pop = { 
/**
 * `pop_type`.
 */
type: string, 
/**
 * `culture`.
 */
culture?: string, 
/**
 * `religion`.
 */
religion?: string, 
/**
 * Thousands of people.
 */
size: number, };

export type River = { 
/**
 * From 0, the narrowest, to `WIDTHS - 1`.
 */
width: number, 
/**
 * Pixel coordinates in the location bitmap, `[x0, y0, x1, y1, …]`, from upstream to
 * downstream. A tributary ends on the river it flows into; a branch starts on the one it
 * leaves.
 */
points: Array<number>, };
© 2026 Soft Santa Cruz, S.L.U. All rights reserved. Unofficial fan project, not affiliated with Paradox Interactive. Game content © Paradox Interactive. · About · Privacy · Legal notice