Entities and locations look like the same "tree" in GLPI, but they solve opposite problems: an entity segments data and permissions; a location is only a physical reference. Confusing the two - or designing the entity hierarchy after the data is already in - is the root of rework that costs days. This guide shows how GLPI stores those trees in the database, a step-by-step plan for the structure, and the pitfalls that only surface while sustaining multi-entity environments.
Entity, location and group: who does what
Before you create any node, fix the boundary. All three mechanisms organize GLPI, but along different axes - and the wrong choice produces either data leakage or pointless bureaucracy.
| Mechanism | Segments permission? | Hierarchical? | What the user now sees | Typical use |
|---|---|---|---|---|
| Entity | Yes (data and access) | Yes | Only its entity's data | Branch, MSP client, isolated department |
| Location | No | Yes | Nothing changes - it is just a physical label | Building, floor, room, rack, data center |
| Group | Partial (tickets) | Yes | Tickets assigned to its group | Support team, squad, on-call |
Field rule of thumb: an entity is a confidentiality boundary, a location is the physical map of the asset, a group is the work queue. If the question is "who is allowed to see this", the answer is almost always entity - a location never hides anything from anyone.
How GLPI stores the entity tree
The Administration > Entities screen is just a shell over the glpi_entities table. Each row points to its parent through the entities_id column, keeps the full path in completename and the depth in level. Two silent columns - sons_cache and ancestors_cache - hold the pre-computed tree in serialized form; that is where the visibility filters read from, not from a recursive JOIN at query time.
-- Entity tree: parent, level and full path
SELECT e.id,
e.name AS entity,
e.completename AS path,
e.level AS level,
p.name AS parent_entity
FROM glpi_entities e
LEFT JOIN glpi_entities p ON p.id = e.entities_id
ORDER BY e.completename;
The completename ("HQ > IT > Support") is what appears in selectors and reports; the level speeds up visibility queries. Remember those two names: you audit the tree by completename, and GLPI decides the scope by level without scanning the whole table.
Inheritance: what cascades to the children (and what does not)
A child entity does not automatically inherit data from its parent - it inherits configuration flagged as recursive. Categories, SLAs, business rules, notification templates and locations all carry the (entities_id, is_recursive) pair: to apply across the whole tree, the item must sit on the root entity (entities_id = 0) with is_recursive = 1. Creating a category inside a child entity traps it there, and the siblings cannot see it.
-- ITIL categories NOT shared across the whole tree
-- (a correct global item has entities_id = 0 and is_recursive = 1)
SELECT id, name, entities_id, is_recursive
FROM glpi_itilcategories
WHERE NOT (entities_id = 0 AND is_recursive = 1);
The common mistake is to create an ITIL category "just for that client" and later find out half the operation cannot see it. In sustaining work, we run this check before any multi-entity go-live: an item that should be global but is not at (0, recursive) is a bug waiting for the first ticket.
Step by step: design the structure before the data
- List the real confidentiality boundaries (who must NOT see what). Each hard boundary becomes an entity; everything else is a location or a group.
- Draw the tree on paper with at most three levels. Depth charges a toll on every selector and report.
- Create the entities through the interface, top-down - never via SQL (see pitfalls).
- Configure the common items on the root (categories, SLAs, notifications) with
is_recursiveticked; push down to a child only what is exclusive to it. - Only then register users, assets and tickets. Moving data between entities later is expensive and drags attachments along.
Locations: the physical hierarchy and the field everyone forgets
The glpi_locations table is hierarchical through its own locations_id (parent), but each location also belongs to an entity (entities_id) and has is_recursive. A location created inside a child entity does not appear in the other entities unless it is recursive - the same mechanism as categories. And the value 0 in locations_id is not null: it is the "no location" sentinel.
-- Computers with no location set, by entity
SELECT e.completename AS entity,
COUNT(*) AS no_location
FROM glpi_computers c
JOIN glpi_entities e ON e.id = c.entities_id
WHERE c.locations_id = 0 -- 0 = none (sentinel), not NULL
AND c.is_deleted = 0
GROUP BY e.completename
ORDER BY no_location DESC;
An inventory with no location is the silent pattern that blows up at the first physical incident ("which rack is it in?"). The query above becomes a CMDB hygiene indicator we track per entity, not a surprise in the middle of the night.
Field pitfalls
The worst of all: creating an entity straight in the database via SQL. The row goes in, but the parent's sons_cache and ancestors_cache are not recomputed - and since the visibility filters read from those caches, the entity becomes invisible to getSonsOf(). The symptom is cruel: the entity exists in the table, shows up in a SELECT, but vanishes from selectors and from the interface tree. We learned the hard way to never create an entity by INSERT: it is creation through the screen that recomputes the caches. If a legacy import already came in via SQL, the fix is to reopen and save each entity through the interface to force the tree to rebuild.
- Treating entity 0 as empty - the root entity has
id = 0, which is a VALID id. Code and integrations that testif (!entities_id)discard the root by accident; in select2 components the root value is""(empty string), never"0". - A document that vanishes when you move a ticket - the attachment (
Document_Item) requires the document to sit in the same entity as the ticket. Moving the ticket to another entity without taking the document along breaks access to the attachment. - A shared location without recursion - creating a rack or room inside a child entity expecting HQ to see it: without
is_recursive, each entity only sees its own locations. - Too many entities - each entity multiplies configuration (categories, SLAs, notifications, per-entity profile assignment). Ten nearly identical entities cost ten times the maintenance. If the only difference between two areas is a report, use a group or a location, not an entity.
Organizational structure checklist
- Map the confidentiality boundaries before touching GLPI; only those become entities.
- Cap the entity tree at three levels of depth.
- Create entities through the interface, never via SQL.
- Configure the common items on the root with
is_recursive = 1; push down only the exclusive ones. - Treat
idandlocations_idequal to0as a valid value, not as empty. - Run the checks for unshared global items and for assets with no location before every go-live.
Need to design (or rescue) a multi-entity structure without rework, or geo-reference your locations on a map? NexTool deploys and sustains multi-entity GLPI environments with the tree reviewed end to end, and the Geolocation module puts your locations on the map. Talk to our deployment and sustaining team.
Reviewed by the NexTool Solutions team.