Skip to content
Sarj Code Standards

prefer-server-data-preparation

Prepare data-only input collections before an interactive client view when possible.

Why

Preparing display data where its inputs are loaded can reduce browser work, payloads and knowledge of server data shapes. A small client component can receive the values its interaction actually needs.

Fix

When these inputs are available on the server, prepare the collection in its loader or Server Component and pass the prepared values. Otherwise lift the projection to the owning producer when useful. Keep unsaved edits, browser-dependent values and interactive filtering reactive in the client; review callers before moving anything.

Examples

Before — flagged Prepare data before the client view when possible
src/options.tsx
"use client";
import { useState } from "react";
export function Options({ rows }: { rows: readonly { language: string }[] }) {
const [selected, setSelected] = useState("");
const languages = rows.map((row) => row.language);
return (
<select value={selected} onChange={(event) => setSelected(event.target.value)}>
{languages.map((language) => (
<option key={language}>{language}</option>
))}
</select>
);
}
tsconfig.json
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "preserve"
},
"include": ["src/**/*"]
}
After — preferred The client receives prepared language values
src/options.tsx
"use client";
import { useState } from "react";
export function Options({ languages }: { languages: readonly string[] }) {
const [selected, setSelected] = useState("");
return (
<select value={selected} onChange={(event) => setSelected(event.target.value)}>
{languages.map((language) => (
<option key={language}>{language}</option>
))}
</select>
);
}
tsconfig.json
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "preserve"
},
"include": ["src/**/*"]
}

References