Structuring entities into separate components which hold data about the entity is important for two reasons:
An example of a data model is the following:
A entity can have zero or more components. Each component has a unique name and a schema. The schema is a zod type that describes the data that the component will contain.
There is no single file, describing what an entity is, as they are in effect just the sum of all their components. This distributed approach to data modelling is inspired by the Entity-Component-System pattern and allows for flexible extension and composition of entities.
You can see that the Product entity has a link to the ProductVariant entity, called ecommerce/product/variants. This means that you can load a Product entity and get all its variants in a single request.
Links work only in one direction. The ecommerce/product/variants link only describes a relation from a Product to its ProductVariants. It cannot be used the other way around.
When requesting Product data, you might not always need all of the component-data available. E.g. when displaying product-tiles, you probably don't need the description component, which contains the full HTML-description of a product.
To achieve this, you can request only the components you need. So if your product-tiles only need the base and media components, you can request only those components.
Most of the time, your data about a product probably comes from a single source like your shop-system, e.g. Shopify or Adobe Commerce. But sometimes you might need to combine data from multiple sources.
For example, you might want to display a product-tile with the product-name, price and image from your shop-system, but the description from a PIM system like Akeneo. Or your product-prices should always be loaded from your ERP system, while the rest of the product-data comes from your shop-system.
The data model is not fixed. Because entities are just the sum of their components, you can extend any entity by adding new components — no core changes needed. A new component is defined with a token (name + Zod schema) and a component resolver that fetches the data.
For example, to add loyalty-point data to products:
// Define the component token
import { z } from 'zod/v4';
import { defineEntityComponentToken } from '@laioutr-core/core-types/orchestr';
export const ProductLoyalty = defineEntityComponentToken('loyalty', {
entityType: 'Product',
schema: z.object({
points: z.number(),
tier: z.enum(['bronze', 'silver', 'gold']).optional(),
}),
});
Then write a component resolver that provides this data from your backend. The resolver is automatically discovered by Orchestr and the new loyalty component becomes requestable alongside built-in components like base or prices.
This works for both extending existing entities and creating entirely new entity types. See Component Resolvers for a full walkthrough with code examples.
Architecture
Laioutr lets non-developers build and manage their e-commerce frontend using a visual editor called Studio. The output of the Studio is an website that can be hosted or run locally.
Internationalization
Laioutr uses markets and languages to serve multiple regions and locales from a single project. Markets define currency and domains; languages define translations and fallbacks. Together they form the customer context.