nextjs-shadcn-netlify-test: A Next.js boilerplate that treats hydration like a hostile environment
Nine shadcn theme files, a defensive body wrapper, and Netlify config tuned to make Next.js 15 behave.
- The repo is a compatibility harness that tests whether Next.js 15, shadcn/ui, and Netlify can share one clean app shell.
- Its most important line resets the body class after hydration, which makes browser extension noise less likely to break the app.
- Nine separate global theme files turn shadcn/ui into a swap-in design system instead of a fixed palette.
- The Netlify configuration makes deployment behavior part of the architecture, not an afterthought.
The most revealing line in aidenybai/nextjs-shadcn-netlify-test is the empty page. `page.tsx` returns nothing, which tells you the repository is not trying to impress users. It is trying to prove that a stack can survive theming, hydration, and deployment without drama.
This is a test bench, not a starter kit
The repo reads like an internal compatibility harness for a senior frontend engineer. Next.js 15, shadcn/ui, Tailwind, Biome, and Netlify all show up, but the interesting part is the choreography between them. Nothing here is decorative. Every file exists to answer a deployment or hydration question.
The body tag is the sharp edge
The sharpest code lives in `src/app/ClientBody.tsx`. Instead of trusting the server-rendered body class forever, the client restores a known value after hydration so browser extensions cannot leave the DOM in a mismatched state.
'use client';
import { useEffect } from 'react';
export function ClientBody() {
useEffect(() => {
document.body.className = 'antialiased';
}, []);
return null;
}
That is defensive engineering in one line. The app assumes the browser may alter `body` before React finishes hydrating, and it chooses consistency over preserving whatever happened to be there.
Nine CSS files, one design system
The theme strategy is simple and unusually practical. Instead of forcing one palette into every context, the repo keeps separate `globals.[color].css` files, each one defining the same HSL variables for shadcn/ui. Swap the import, and the entire surface changes with it.
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--accent: 210 40% 96.1%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 210 40% 98%;
}
That matters because shadcn/ui is opinionated about tokens, not about brands. The repo uses that to make theme changes a file-level decision instead of a component rewrite.
Netlify is the other half of the test
The deployment config is not just housekeeping. `next.config.js` changes the build output directory depending on environment, and `netlify.toml` skips the default Next plugin path while still opting into `@netlify/plugin-nextjs`. The message is blunt: this stack will work, but only if you tell every layer exactly what to do.
const nextConfig = {
eslint: { ignoreDuringBuilds: true },
typescript: { ignoreDuringBuilds: true },
distDir: process.env.NODE_ENV === 'production' ? '.next' : '.next-dev',
};
That is a conscious tradeoff. It favors a reliable deploy signal over strict build-time enforcement, which makes sense in a repository whose job is to verify the plumbing more than police the codebase.
What it looks like compared with the defaults
| Concern | Common default | This repo's move | Tradeoff |
|---|---|---|---|
| Theme surface | One global stylesheet or runtime theme swap | Nine preset CSS files with identical tokens | More files, less runtime branching |
| Hydration | Trust the server markup and fix mismatches later | Reset `body` on the client after hydration | Small client-side repair for a browser-side problem |
| Build checks | Fail builds on lint and TypeScript errors | Ignore those checks during builds | Faster green builds, less build-time safety |
| Hosting | Use the host's default Next.js path | Explicit Netlify plugin and distDir wiring | More setup, fewer surprises |
The pattern is useful anywhere the app shell matters more than the demo content. If you ship a theme-heavy product and want a deployment target that is not the framework's home turf, this is a clean, opinionated starting point.