Imagine you are building a "Christmas Candles" category page. A customer lands on the page, and your frontend needs to show a grid of candle products with images, prices, and names. Here is what happens under the hood:
This two-step pattern (query returns IDs, resolvers load components) is the foundation of Laioutr's data model.
Data in Laioutr is organized into normalized entities. Each entity has a unique ID and a type (like Product, Category, or BlogPost). Entities hold their data in entity components: named, typed chunks of data attached to an entity.
.vue file that renders UI. They share the name "component" but are entirely different concepts.Here is what a typical product entity looks like:
There is no single file that defines what a Product is. An entity is the sum of all its registered components. This distributed approach is inspired by the Entity-Component-System pattern and is what makes multi-source composition possible.
The Product entity above has a link called ecommerce/product/variants pointing to its ProductVariant entities. Links let you traverse related entities in a single request. Load a product and get all its variants at once.
Links are unidirectional. The ecommerce/product/variants link describes a relation from Product to ProductVariant. To go the other direction, you would need a separate link definition.
When you display product tiles in a grid, you probably need the base and media components but not the full description (which might contain heavy HTML). Laioutr lets you request exactly the components you need:
// In your query, request only the components the product tile needs
const products = await useOrchestr().query('ecommerce/category/products', {
components: ['base', 'media'],
// 'description' is NOT loaded -- saving bandwidth and resolver time
});
This granularity means your category page loads fast because it skips data it does not render. Your product detail page can request description, brand, and other components when it actually needs them.
Here is where the entity-component model really shines. Your product's base info and media might come from Shopify, but you want prices from your ERP and recommendations from an AI service. Each data source provides its own component resolver, and Orchestr composes the results into a single entity:
Your Vue components do not know or care where the data came from. They receive a typed Product entity with all requested components attached. If you later move from Shopify to commercetools, you swap the resolver; the frontend code stays the same.
Because entities are just the sum of their components, you can extend any entity by adding new components. No core changes needed. Define a component token (name + Zod schema) and write 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 loyalty backend. Orchestr automatically discovers the resolver, and the new loyalty component becomes requestable alongside built-in components like base or prices.
This works for extending existing entities and for creating entirely new entity types. See Component Resolvers for a full walkthrough.
If you have used GraphQL, Orchestr's approach will feel familiar. Both let you request exactly the fields you need. The key difference is that Orchestr is server-side only. Queries and resolvers run on your Nuxt server, not in the browser. This means:
Read more about queries, resolvers, and caching in the Orchestr documentation.
Architecture
Understand how a Laioutr frontend is structured, from the visual editor down to the Nuxt application that powers it.
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.