Server vs. kliens komponensek 2026-ban · a döntési szabály, amit alkalmazunk
Két év RSC után végre stabil a szabály. Bemutatjuk, amit alkalmazunk · default szerver, négy konkrét trigger esetén promóció kliensre.
Két év RSC után végre stabil a szabály. Bemutatjuk, amit alkalmazunk · default szerver, négy konkrét trigger esetén promóció kliensre.
Két év éles RSC-szállítás után végre megnyugodott a gyomorérzet. A magyar csapatok nagy része még mindig vallásként kezeli a kérdést · 'mi RSC-bolt vagyunk' vagy 'csak rakd rá a `'use client'`-et, megy'. Mindkettő pénzt költ feleslegesen. A valódi szabály rövidebb, mint amit bármelyik tábor szeret hallani.
Default minden komponens Server Component, és csak akkor promóváljuk kliensre, ha a négy konkrét trigger közül valamelyik tűzbe lép. Ennyi az egész szabály. A poszt többi része a négy trigger, a rossz döntés ára, és az az eset, amikor a helyes válasz az, hogy 'egyik sem, telepítsd újra a határvonalat'.
Ha egy komponens adatot rendel, layoutot rajzol, másik komponenseket komponál, vagy adatbázist hív · az Server Component. Nincs state, nincs `useEffect`, nincs event handler · csak `async` függvény és JSX. A `'use client'` kártyára, listára, layoutra, section header-re már nem reflexből kerül. Ez a szokás a Pages Router évekből maradt, és JS-t szállít a semmiért.
Minden más szerver. Ha a '4' és 'ez csak egy link' között bizonytalan vagy, a válasz a szerver · a link `<a href>`, nem `onClick` handler.
Egy szervernek szánt komponens kliensre tolva: extra JS letöltés, parse, hidratáció. Minden prop, ami átkerül a határvonalon, szerializációs költség lesz. A szép komponálható fa hirtelen JSON blobot cipel, ami a HTML-lel együtt megy le. Két felesleges `'use client'` egy layoutban: a marketing oldal 40KB bundle-t veszít a semmiért.
Egy kliensnek szánt komponens szerveren maradva: nem reagál, a felhasználó kattint és nem történik semmi, vagy a fejlesztő `'use client'`-et tesz a szülőre, hogy 'megjavítsa'. Az utóbbi a legdrágább · most az egész részfa, beleértve a szerver-only gyerekeket is, kliens lesz, és újra kell írni.
Amit első nap nem mond senki: a szerver-kliens határvonal valódi architekturális artefakt. Megtervezed, megnevezed, kicsire tartod. Kliens-szigeteinket arról nevezzük el, amit csinálnak · `<TabsClient>`, `<EditorClient>`, `<MapClient>`. A szerver-wrapper mellettük marad komponálható és adat-fetchelő. Bármi más zagyvaság.
// app/dashboard/page.tsx · szerver
import { TabsClient } from "./tabs-client";
import { fetchSummary, fetchActivity } from "@/lib/data";
export default async function Page() {
const [summary, activity] = await Promise.all([
fetchSummary(),
fetchActivity(),
]);
return (
<section>
<h1>Dashboard</h1>
<TabsClient
summary={<SummaryView data={summary} />}
activity={<ActivityList items={activity} />}
/>
</section>
);
}
// app/dashboard/tabs-client.tsx
'use client';
import { useState, type ReactNode } from "react";
export function TabsClient({ summary, activity }: { summary: ReactNode; activity: ReactNode }) {
const [tab, setTab] = useState<"summary" | "activity">("summary");
return (
<>
<nav role="tablist">
<button onClick={() => setTab("summary")}>Összegzés</button>
<button onClick={() => setTab("activity")}>Aktivitás</button>
</nav>
{tab === "summary" ? summary : activity}
</>
);
}
Figyeld meg, mi van a kliens-fájlban: state, két gomb, egy switch. Ennyi. A tab-ek tartalma szerver-komponens, prop-ként átadva. Az adatlekérést nem visszük át a határvonalon, csak slot-okat.
Szerveren fetchelünk, kis kliens-szigetnek átadjuk az eredményt. Filter, tab, drawer, accordion. Az interaktív felület apró marad.
A form szerver-komponens. A submit server action. Az optimistic UI egy kis kliens-wrapperben él a form körül. A `'use client'` direktívák száma egy marad.
Térkép, chart, rich-text editor: dinamikus import egy kliens-komponensen belül. Wrap `<Suspense>`-be, hogy az oldal többi része ne várjon. A környező keretet a szerver rendereli.
Ha küzdesz a határral, valószínűleg két dolgot kolokáltál, ami testvér kéne legyen. Bontsd a fát. A minta: szerver-komponens, ami fetchel és layoutol, plusz mellette egy kliens-komponens, ami az interakciót viszi, közöttük `children` vagy render-prop slot. Elég ilyen után már nem reflexből nyúlsz a `'use client'`-ért.
Nézd meg a bundle-t. Ha egy marketing-jellegű oldal több mint 80KB kliens JS-t szállít, valami `'use client'`-et visel, ami nem kéne. Tíz perc bundle analyzerrel szinte biztosan kiesik.
Az összegzés egy post-it-en: szerver default, valódi triggerre promóválj, a kliens-szigetet kicsire tartsd, és a határt úgy tervezd, mint egy publikus API-t. Két év után még mindig többet törlünk `'use client'`-et, mint amennyit hozzáadunk.

Alapító, DField Solutions
Pénzügyi cégeknél és kreátor-eszközöknél is építettem már olyan rendszereket, amik nap mint nap élesben futnak. Budapesttől San Franciscóig · startupoknak és nagyobb vállalatoknak egyaránt.
Beszéljünk a projektedről. 30 perc, nincs kötelezettség.