Hotelgroepen Websites: Multi-Property Architectuur met Next.js
Jouw regionale directeur mailt om 16:00 uur: de nieuwe boutique-overname in Charleston gaat online in acht weken, brandstandaarden verplicht, boeking engine geïntegreerd, geen uitzonderingen. Je opent je huidige multi-site setup—zeventien WordPress installaties, elk met zijn eigen plugin-doolhof, elk kapot gaan anders na updates, elk met een aparte staging omgeving. Jouw dev team schat minimaal twaalf weken. Ik heb dit exact scenario zien gebeuren bij hotelgroepen met 8, 25, zelfs 47 properties. De architectuurbeslissing die je vandaag neemt, bepaalt of je volgende property drie dagen of drie maanden kost. De meeste groepen kiezen het pad dat veilig voelt—dan besteden ze twee jaar aan ontwarren. Hier is de Next.js-aanpak die één platform kan laten draaien voor elke property zonder chaos.
Er is een beter alternatief. Een enkele Next.js-applicatie—goed gearchitecteerd—kan elke property in een hotelgroep bedienen vanuit één codebase, één deployment-pipeline en één content management-laag. Elke property krijgt zijn eigen branding, zijn eigen content, zijn eigen domein. Het engineering team krijgt zijn gezondheid terug.
Dit artikel breekt precies uit hoe je dat systeem bouwt. Niet theorie—echte architectuurpatronen die we op echte hotelgroep-projecten hebben gebruikt.
Inhoudsopgave
- Waarom hotelgroepen een geïntegreerd platform nodig hebben
- Architectuuroverzicht: Één codebase, veel properties
- Multi-Tenancy-patronen in Next.js
- Headless CMS-strategie voor hotelgroepen
- Gedeelde componenten vs property-level aanpassingen
- Boeking engine-integratie
- Domeinrouting en property-resolutie
- Prestaties op schaal
- Gecentraliseerd beheerdashboard
- Implementatie en DevOps
- Real-world kostenvergeliking
- Veelgestelde vragen

Waarom hotelgroepen een geïntegreerd platform nodig hebben
De typische hotelgroep-website-situatie ziet er zo uit: Property A draait WordPress met een thema van 2019. Property B is op Squarespace omdat de GM's neefje het ingesteld heeft. Property C heeft een aangepaste PHP-site die niemand wil aanraken. De bedrijfssite draait op een volledig ander platform.
Elke property-update vereist een ander workflow. Brandconsistentie is een pijpdroom. SEO-strategie is verdeeld over tientallen domeinen zonder gedeelde autoriteit. Wanneer corporate besluit om een nieuw amenities-badge toe te voegen of de boeking widget bij te werken, moet iemand die wijziging op 15 verschillende plaatsen aanbrengen.
De kosten stapelen op:
- Onderhoudsoverhead: Elk platform heeft zijn eigen hosting, beveiligingspatches, plugin-updates nodig
- Merkafdrift: Properties wijken langzaam af van merkrichtlijnen
- Developer context switching: Jouw team (of bureau) heeft expertise nodig over meerdere platforms
- Trage property launches: Nieuwe overnames kosten maanden om online te gaan
- Analytics-fragmentatie: Geen geïntegreerde weergave van prestaties in de portfolio
Een gecentraliseerd multi-property platform lost dit alles op. Één codebase. Één deployment. Één CMS. Property-specifieke content en branding geleverd via configuratie, niet aparte codebases.
Architectuuroverzicht: Één codebase, veel properties
Hier is de high-level architectuur die werkt:
┌─────────────────────────────────────────────┐
│ CDN / Edge Network │
│ (Vercel, Cloudflare, Fastly) │
├─────────────────────────────────────────────┤
│ Next.js Application │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Property │ │ Property │ │ Property │ │
│ │ Resolver │ │ Theming │ │ Content │ │
│ │ Middleware│ │ Engine │ │ Fetcher │ │
│ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────┤
│ API Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Headless │ │ Booking │ │ Media │ │
│ │ CMS │ │ Engine │ │ CDN │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────┘
De Next.js-app fungeert als de rendering-laag. Middleware bepaalt welke property wordt aangevraagd (via domein, subdomein of pad). De theming-engine past property-specifieke stijlen toe. De content-ophaler haalt property-gescoped content op uit de headless CMS.
Alles stroomafwaarts—de CMS, boeking engine, mediaopslag—wordt bevraagd met een property-identifier. Die identifier is de draad die het gehele systeem samenbindt.
Multi-Tenancy-patronen in Next.js
Er zijn drie primaire benaderingen voor multi-tenancy in Next.js. Elk heeft voor- en nadelen.
Patroon 1: Subdomein-gebaseerde routing
Elke property krijgt een subdomein: grandplaza.hotelgroup.com, seasideresort.hotelgroup.com.
Next.js middleware onderschept het verzoek, extraheert het subdomein en lost de property-config op:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { getPropertyByDomain } from '@/lib/properties';
export function middleware(request: NextRequest) {
const hostname = request.headers.get('host') || '';
const subdomain = hostname.split('.')[0];
const property = getPropertyByDomain(subdomain);
if (!property) {
return NextResponse.redirect(new URL('/not-found', request.url));
}
// Inject property context into headers for downstream use
const response = NextResponse.next();
response.headers.set('x-property-id', property.id);
response.headers.set('x-property-slug', property.slug);
return response;
}
Voordelen: Schone URLs, gemakkelijke property-isolatie, goed voor SEO als properties geen aparte TLD's nodig hebben.
Nadelen: SSL-certificaatbeheer voor wildcards, minder merkonafhankelijkheid per property.
Patroon 2: Aangepast domeinmapping
Elke property heeft zijn eigen domein: grandplazahotel.com, seasideresort.com.
Dit is wat de meeste hotelgroepen werkelijk willen. De middleware-logica is vergelijkbaar, maar je matcht tegen een domeinopzoektabel:
const DOMAIN_MAP: Record<string, string> = {
'grandplazahotel.com': 'grand-plaza',
'www.grandplazahotel.com': 'grand-plaza',
'seasideresort.com': 'seaside-resort',
'www.seasideresort.com': 'seaside-resort',
};
Vercel ondersteunt aangepaste domeinen per project van nature en je kunt tot 50 domeinen toewijzen op hun Pro-plan ($20/maand vanaf 2026). Voor grotere portfolio's verwijdert hun Enterprise-plan die limiet.
Voordelen: Volledige merkonafhankelijkheid, bestaande domeinautoriteit behouden.
Nadelen: DNS-beheeroverhoofd, complexere SSL-provisioning.
Patroon 3: Op pad gebaseerde routing
Alle properties onder één domein: hotelgroup.com/properties/grand-plaza, hotelgroup.com/properties/seaside-resort.
Voordelen: Eenvoudigste om te implementeren, geconsolideerde domeinautoriteit voor SEO.
Nadelen: Minder merkidentiteit per property, URL-structuur voelt corporate.
| Patroon | Merkonafhankelijkheid | SEO-flexibiliteit | Implementatiecomplexiteit | Het beste voor |
|---|---|---|---|---|
| Subdomein | Gemiddeld | Gemiddeld | Laag | Budget-bewuste groepen |
| Aangepast domein | Hoog | Hoog | Gemiddeld | Gevestigde merken |
| Op pad gebaseerd | Laag | Hoog (geconsolideerd) | Laagst | Nieuwe portfolio-sites |
De meeste hotelgroepen waarmee we werken bij Social Animal kiezen uiteindelijk voor aangepast domeinmapping. Properties hebben merkwaarde in hun domeinen en marketingteams willen de onafhankelijkheid.

Headless CMS-strategie voor hotelgroepen
De CMS-keuze maakt of breekt deze architectuur. Je hebt een systeem nodig dat multi-tenancy op contentniveau ondersteunt—waar editors voor Property A niet per ongeluk Property B's content kunnen wijzigen, maar corporate admins alles kunnen beheren.
CMS-opties die goed werken
Sanity is mijn topkeuze voor hotelgroepen. De documentniveaupermissies, aangepaste studio-configuratie en GROQ-querytaal maken property-gescoped content-opvraging triviaal. Je kunt een enkele Sanity Studio bouwen met workspace-per-property weergaven. De prijsstelling begint bij $99/maand voor het Team-plan (2026-prijsstelling) en schaalt goed naar grote contentvolumes.
Contentful werkt als je al in hun ecosysteem zit. Hun space-level isolatie wijst goed toe aan properties, hoewel het duur kan worden—elke space op het Premium-plan voegt kosten toe, en je kijkt naar $2.500+/maand voor enterprise-schaal hotelgroep-behoeften.
Strapi (zelf gehost) is de budgetoptie. Je zult de multi-tenancy-laag zelf moeten bouwen met aangepaste middleware en op rol gebaseerde toegangscontrole, maar er zijn geen licentiekosten per seat.
We behandelen het volledige CMS-selectieproces in onze headless CMS development guide.
Contentmodellering voor hotels
Hier is een contentmodel dat werkt in alle properties:
// Sanity schema example
export const property = defineType({
name: 'property',
title: 'Property',
type: 'document',
fields: [
defineField({ name: 'name', type: 'string' }),
defineField({ name: 'slug', type: 'slug' }),
defineField({ name: 'domain', type: 'string' }),
defineField({ name: 'brand', type: 'reference', to: [{ type: 'brand' }] }),
defineField({ name: 'location', type: 'geopoint' }),
defineField({ name: 'theme', type: 'propertyTheme' }),
defineField({ name: 'bookingEngineId', type: 'string' }),
],
});
export const room = defineType({
name: 'room',
title: 'Room Type',
type: 'document',
fields: [
defineField({ name: 'property', type: 'reference', to: [{ type: 'property' }] }),
defineField({ name: 'name', type: 'string' }),
defineField({ name: 'description', type: 'blockContent' }),
defineField({ name: 'maxOccupancy', type: 'number' }),
defineField({ name: 'amenities', type: 'array', of: [{ type: 'reference', to: [{ type: 'amenity' }] }] }),
defineField({ name: 'gallery', type: 'array', of: [{ type: 'image' }] }),
],
});
Het sleutelpatroon: elk contentdocument verwijst naar een property. Queries filteren altijd op property. Editors zien alleen de content van hun property. Corporate admins zien alles.
Gedeelde componenten vs property-level aanpassingen
Hier wordt de architectuur interessant. Je wilt 80% van de componenten gedeeld over properties, met 20% waardoor property-specifieke aanpassingen mogelijk zijn.
De theming-laag
Maak een themaconfiguratie per property die in jouw componentsysteem voedt:
// types/theme.ts
export interface PropertyTheme {
colors: {
primary: string;
secondary: string;
accent: string;
background: string;
text: string;
};
typography: {
headingFont: string;
bodyFont: string;
};
logo: {
light: string;
dark: string;
};
borderRadius: 'none' | 'sm' | 'md' | 'lg';
heroStyle: 'fullbleed' | 'contained' | 'split';
}
Tailwind CSS v4 (uitgebracht 2025) maakt dit aanzienlijk gemakkelijker met zijn CSS-first configuratie en native thema-functiesteuning. Je kunt CSS custom properties instellen op layoutniveau en deze cascaden door elk component:
// app/layout.tsx
export default async function PropertyLayout({ children }: { children: React.ReactNode }) {
const property = await getCurrentProperty();
const theme = property.theme;
return (
<html
style={{
'--color-primary': theme.colors.primary,
'--color-secondary': theme.colors.secondary,
'--font-heading': theme.typography.headingFont,
'--font-body': theme.typography.bodyFont,
} as React.CSSProperties}
>
<body className="font-body text-text bg-background">
{children}
</body>
</html>
);
}
Componentsamenstelling
Gedeelde componenten accepteren thematokens en renderen anders per property zonder vertakkingslogica:
// components/HeroSection.tsx
export function HeroSection({ property }: { property: Property }) {
const heroConfig = property.theme.heroStyle;
const variants = {
fullbleed: 'h-screen w-full',
contained: 'h-[70vh] max-w-7xl mx-auto rounded-2xl overflow-hidden',
split: 'grid grid-cols-2 h-[80vh]',
};
return (
<section className={variants[heroConfig]}>
{/* Shared hero content structure */}
</section>
);
}
Boeking engine-integratie
Hotelwebsites bestaan om één reden: om boekingen te genereren. De integratie van de boeking engine moet rotsvast zijn.
De meeste hotelgroepen gebruiken een van deze boeking engines: SynXis (Sabre), Pegasus, Bookassist, SiteMinder, of een eigenprijs centraal reserveringsysteem. Het integratiepatroon is bijna altijd hetzelfde: geef een property-identifier, datumbereik en aantal gasten door om beschikbaarheid te krijgen.
// lib/booking.ts
export async function checkAvailability({
propertyCode,
checkIn,
checkOut,
adults,
children,
}: BookingQuery) {
const response = await fetch(`${BOOKING_ENGINE_URL}/availability`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${BOOKING_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
hotel_code: propertyCode,
arrival: checkIn,
departure: checkOut,
guests: { adults, children },
}),
});
return response.json();
}
Voor de boeking widget zelf heb je twee opties:
- Embedded iframe: De boeking engine levert een widget die je insluit. Minste werk, minste controle.
- API-driven aangepaste UI: Je bouwt de zoek- en resultatUI, roept de boeking API direct aan en geeft alleen aan de boeking engine af voor betaling. Meer werk, veel beter UX.
Optie 2 is waar een Next.js-architectuur echt schittert. Je kunt een prachtige, snelle, op-merk boeking-ervaring bouwen die inheems aanvoelt voor elke property. Server Components kunnen beschikbaarheidsgegevens vooraf ophalen. De boeking stroom blijft op jouw domein, wat beter is voor conversietracking en SEO.
Domeinrouting en property-resolutie
De property-resolutie stroom moet snel zijn. Echt snel. Het draait op elk enkel verzoek.
Hier is het patroon dat in productie werkt:
- Edge middleware lost domein → property slug op (in-geheugen opzoekwerk, sub-milliseconde)
- Property-config wordt in de cache opgeslagen aan de rand met Vercel Edge Config of Cloudflare KV
- Volledige property-gegevens (thema, navigatie, voeterinhoud) worden eenmaal per build opgehaald via ISR of bij verzoektijd met caching
// lib/property-resolver.ts
import { get } from '@vercel/edge-config';
export async function resolveProperty(hostname: string): Promise<PropertyConfig | null> {
// First: check edge config (sub-5ms)
const domainMap = await get<Record<string, string>>('domain-map');
const propertySlug = domainMap?.[hostname];
if (!propertySlug) return null;
// Second: get full property config (cached)
const propertyConfig = await get<PropertyConfig>(`property:${propertySlug}`);
return propertyConfig;
}
Vercel Edge Config is perfect hiervoor—het is een wereldwijd gedistribueerde sleutelwaardewinkel met leeslatentie onder 1ms. Het kost $0 op Pro-abonnementen voor tot 512KB data, wat genoeg is voor een property-opzoektabel.
Prestaties op schaal
Hotelwebsites hebben specifieke prestatiekenmerken die belangrijk zijn:
- Beeldrijke pagina's: Kamergalerijen, property-foto's, bestemmingsimagerie
- Seizoens verkeersspikes: Vakantieperiodes, conventieseizoen, lokale evenementen
- Globaal publiek: Internationale reizigers die van overal bladeren
- Conversie-kritiek: Elke 100ms laadtijd kost boekingen
Strategie voor statische generatie
Gebruik Incremental Static Regeneration (ISR) voor property-pagina's. Hotelcontent verandert niet elke minuut—een revalidatieperiode van 60 seconden is meestal prima:
// app/[propertySlug]/page.tsx
export async function generateStaticParams() {
const properties = await getAllProperties();
return properties.map((p) => ({ propertySlug: p.slug }));
}
export const revalidate = 60;
Voor een groep van 30 properties met ~20 pagina's per property genereer je ~600 pagina's vooraf. Next.js handhaaft dit zonder zweetdruppels. Buildtijden blijven onder de 5 minuten.
Afbeeldingsoptimalisatie
Next.js Image-component met een remote loader handhaaft per-property afbeeldingsoptimalisatie. Als je Sanity gebruikt, hun image CDN met automatische formaatconversie en resizing is uitstekend. Cloudinary is een ander solide alternatief voor $89/maand voor het Plus-plan.
Een typische hotelkamerpagina zou naar het volgende moeten streven:
- LCP onder 2,5s op 4G-verbindingen
- CLS van 0 (geen layoutverschuiving van laadafbeeldingen)
- Totaal paginagewicht onder 1,5MB bij eerste laadbeurt
Gecentraliseerd beheerdashboard
Naast de CMS hebben hotelgroepen operationele dashboards nodig. Dit is waar je aangepaste tooling bouwt:
- Property-overzicht: Status van elke property-site (live, staging, onderhoud)
- Content-versheid: Welke properties hebben hun seizoensinhoud niet bijgewerkt
- Prestatiemonitoring: Core Web Vitals per property
- Analytics rollup: Boeking-trechtermetrieken in alle properties
We bouwen dit doorgaans als een aparte Next.js-app (vaak met de App Router's server-side-mogelijkheden) die dezelfde gegevensbronnen aansluit. Het beheerdashboard is een intern hulpmiddel—het hoeft niet flashy te zijn, maar het moet functioneel zijn.
Implementatie en DevOps
Één codebase betekent één CI/CD-pipeline. Hier is de implementatiestroom:
- Code-wijzigingen: PR → review → merge naar main
- Bouwen: Next.js bouwt alle statische pagina's in alle properties
- Implementeren: Vercel (of vergelijkbaar) implementeert op edge-netwerk
- DNS: Elk property-domein wijst naar de implementatie
Inhoudwijzigingen vereisen geen implementatie. De headless CMS activeert ISR-revalidatie via webhook:
// app/api/revalidate/route.ts
export async function POST(request: Request) {
const body = await request.json();
const { propertySlug, contentType } = body;
// Revalidate specific paths for the changed property
revalidatePath(`/${propertySlug}`);
if (contentType === 'room') {
revalidatePath(`/${propertySlug}/rooms`);
}
return Response.json({ revalidated: true });
}
Real-world kostenvergeliking
Laten we de werkelijke kosten voor een hotelgroep met 20 properties vergelijken:
| Kostencategorie | Aparte sites (WordPress) | Geïntegreerd Next.js-platform |
|---|---|---|
| Hosting (maandelijks) | $2.000-4.000 (20 × beheerde WP) | $150-400 (Vercel Pro/Team) |
| CMS-licenties | $0-600 (plugins per site) | $99-300 (Sanity/Contentful) |
| SSL-certificaten | $0-400 (als niet Let's Encrypt gebruiken) | $0 (automatisch voorzien) |
| Onderhoud (jaarlijks) | $40.000-80.000 (updates, beveiliging) | $10.000-20.000 |
| Nieuwe property-lancering | $5.000-15.000 per site | $500-2.000 (content + config) |
| Jaarlijks totaal (geschat) | $75.000-150.000 | $15.000-35.000 |
De cijfers zijn niet eens dicht. En dit houdt geen rekening met de developer experience-verbeteringen—het hebben van één codebase betekent dat jouw team het systeem werkelijk begrijpt. Geen meer "welke WordPress-versie draait die property?"
Voor hotelgroepen die deze aanpak overwegen, hebben we onze Next.js development capabilities uiteengezet en je kunt onze prijsstructuur zien voor een meer gedetailleerde schatting.
Veelgestelde vragen
Hoe lang duurt het om een hotelgroep naar een geïntegreerd Next.js-platform te migreren? Voor een groep van 10-20 properties verwacht je 3-5 maanden vanaf kickoff tot volledige lancering. De eerste property kost het langst (8-10 weken) omdat je het platform bouwt. Elke volgende property is vooral content-migratie en themaconfiguratie, wat 1-2 weken kost. We lanceren doorgaans in golven—3-4 properties tegelijk.
Kunnen individuele properties nog altijd unieke pagina's hebben die andere properties niet hebben? Absoluut. Het contentmodel ondersteunt property-specifieke paginatypes. Als jouw resort-property een "Trouwvenues"-sectie nodig heeft maar jouw zakenhotel niet, dat is een content-level beslissing. Het CMS-schema ondersteunt optionele paginatypes en de Next.js dynamische routing handhaaft het renderen van elke pagina die bestaat in de CMS voor een bepaalde property.
Wat gebeurt er als je een nieuw hotel acquireert en het aan het platform moet toevoegen? Dit is een van de grootste winsten. Het toevoegen van een nieuwe property betekent: een property-ingang aanmaken in de CMS, het thema configureren (kleuren, lettertypen, logo), het domeinmapping toevoegen en content invullen. Een competent content team kan een nieuwe property in 1-2 weken live hebben. Vergelijk dat met 2-3 maanden om een zelfstandige website te bouwen.
Hoe ga je met meertalige ondersteuning om in properties in verschillende landen? Next.js heeft ingebouwde i18n-routeringondersteuning. Gecombineerd met een headless CMS die gelokaliseerde content ondersteunt (Sanity en Contentful doen dit allebei prima), kunt je elke property in zijn relevante talen bedienen. Een property in Barcelona heeft misschien Spaans, Catalaans, Engels en Frans nodig. Een property in Miami heeft misschien alleen Engels en Spaans nodig. Elke property-taalgconfiguratie is onafhankelijk.
Werkt deze architectuur ook met Astro in plaats van Next.js? Ja, en voor sommige hotelgroepen is het eigenlijk de betere keuze. Als je properties primair content-gedreven zijn met minimale interactiviteit (geen complexe boeking stroom, bijvoorbeeld), kan Astro's multi-page-architectuur nog betere prestaties leveren met minder JavaScript. De multi-tenancy-patronen zijn vergelijkbaar—middleware-gebaseerde property-resolutie, headless CMS met property-scoping, thematokens per property.
Hoe handhaaf je SEO wanneer properties op aparte domeinen staan maar vanuit één applicatie worden bediend? Elk property-domein krijgt zijn eigen sitemap, eigen robots.txt, eigen structured data (Hotel schemamarkering) en eigen metatags. Vanuit Googles perspectief zijn dit volledig aparte websites. De canonieke URLs wijzen naar elk property's eigen domein. Je krijgt ook het voordeel van gegenereerde centraalschemamarkering—elke property krijgt automatisch goede JSON-LD voor hotels, kamers, beoordelingen en informatie over lokale bedrijven.
Wat over property-specifieke integraties zoals lokale activiteitenboekingen of spa-reserveringssystemen? De componentarchitectuur ondersteunt property-level integratieconfiguratie. Elke property-config in de CMS kan aangeven welke third-party integraties het gebruikt. De renderlaag includes voorwaardelijk die integratiecomponenten. Een spa-property krijgt de spa-boekingswidget. Een zakenhotel in het centrum krijgt de configurator voor vergaderruimtes. Deze worden geladen als dynamische imports zodat ze het bundleformaat niet beïnvloeden voor properties die deze niet gebruiken.
Is er een risico dat een property's verkeerspieken andere properties beïnvloeden? Op een platform als Vercel of Cloudflare Pages eigenlijk niet. Deze edge-platforms zijn ontworpen voor verkeerspieken. Statische pagina's worden vanuit CDN-cache bediend, dus een piek op één property verbruikt geen servermiddelen die een ander zouden beïnvloeden. Voor dynamische routes (zoals real-time beschikbaarheidscontroles) zou je snelheidsbeperking per property willen om te voorkomen dat de virale moment van één property je quotas voor de boeking engine-API uitput. Maar dat is een API-level concern, geen hosting concern.