Frontend Architecture
How Next.js and Convex work together in YeetCode's frontend.
YeetCode's frontend architecture follows a clear separation of concerns: Next.js is the shell (routing, images, middleware, deployment) and Convex owns the data layer on the client.
Core Principles
Server Components by Default
Pages (page.tsx) stay as Server Components. They are layout shells that compose Client Components:
// app/dashboard/page.tsx — Server Component (no "use client")
export default function DashboardPage() {
return (
<div>
<h1>Dashboard</h1>
<UserStats /> {/* Client Component */}
<RecentActivity /> {/* Client Component */}
</div>
);
}Never make entire pages into Client Components. Keep pages as Server Components stitching together client-side pieces.
Client Components Own Their Data
Individual Client Components declare their own Convex useQuery subscriptions:
"use client";
import { useQuery } from "convex/react";
import { api } from "@yeetcode/convex-backend/_generated/api";
export function UserStats() {
const stats = useQuery(api.stats.getUserStats);
if (!stats) return <Skeleton />;
return <StatsDisplay data={stats} />;
}Each component is self-contained — it fetches exactly the data it needs and handles its own loading states.
No SSR for Authenticated Convex Data
Authenticated pages have no SEO benefit from server-side rendering. The data behind auth doesn't need to be in the initial HTML — it loads in real-time via Convex subscriptions on the client.
SSR for Public Content
Public content served from Convex (articles, changelogs) should use preloadQuery for SSR:
// app/changelog/[slug]/page.tsx — Server Component with SSR data
import { preloadQuery } from "convex/nextjs";
export default async function ChangelogEntry({ params }) {
const preloaded = await preloadQuery(api.changelog.getEntry, { slug: params.slug });
return <ChangelogContent preloadedEntry={preloaded} />;
}These pages need SEO and fast first paint, so server-rendering the Convex data makes sense.
Marketing Pages Are Standard Next.js
Marketing and static pages (pricing, landing, about) use standard Next.js SSR/ISR without Convex. They don't need real-time data.
Summary
| Page Type | Rendering | Data Source |
|---|---|---|
| Authenticated app pages | Client-side | Convex useQuery subscriptions |
| Public dynamic content | SSR via preloadQuery | Convex |
| Marketing/static pages | SSR/ISR | Next.js (no Convex) |