VS Code Setup
- Prettier - Code formatter
- Color Highlight - Visualizes colors
- ESLint - Linter
- Tailwind CSS IntelliSense - Autocomplete
- ES7+ React/Redux - Snippets
.eslintrc.json
{
"extends": [
"next/core-web-vitals",
"eslint:recommended"
]
}
Turbopack
Default bundler for new projects.
// Turbopack is now default
// No configuration needed!
// Faster production builds
// Improved Fast Refresh
// Better performance
Advanced Routing
Dynamic segments.
// 1. Single Slug
// matches: /blog/my-post
app/blog/[slug]/page.tsx
// 2. Catch-all
// matches: /blog/tech/nextjs
app/blog/[...slug]/page.tsx
Async Request APIs
params & searchParams are async.
import { cookies, headers } from 'next/headers';
export default async function Page({
params, searchParams
}) {
const { slug } = await params;
const { q } = await searchParams;
const cookieStore = await cookies();
const headersList = await headers();
}
Components vs Actions
Server Components
Never re-render on client. Useful for GET requests/fetching.
Server Actions
Exposed as API endpoints. Useful for POST/PUT/DELETE.
"use cache"
Opt-in to caching for functions.
"use cache";
export async function getData() {
// This function will be cached
const data = await fetch(url);
return data.json();
}
"use cache: private"
Cache with runtime APIs (cookies).
"use cache";
export async function getRecs(id) {
'use cache: private';
const session = cookies().get('session');
return getPersonalized(session);
}
"use cache: remote"
Cache shared dynamic data.
async function getPrice(id) {
'use cache: remote';
cacheTag(`product-${id}`);
cacheLife({ expire: 3600 });
return db.products.getPrice(id);
}
Tag the Cache
Selectively invalidate data.
import { cache } from 'next/cache';
const getXP = cache(
async () => getXPInfo(id),
['xp-info', id],
{ tags: [`xp-info:${id}`] }
);
Improved Invalidation
Revalidate with profiles.
import { revalidateTag } from 'next/cache';
// Built-in profile
revalidateTag('posts', 'max');
// Custom time
revalidateTag('products', {
revalidate: 3600
});
Clear Tagged Cache
Bust specific tags efficiently.
if (studentId) {
revalidateTag(`xp:${studentId}`);
revalidateTag(`streaks:${studentId}`);
}
// Only busts specific tags!
after() API
Run background tasks non-blocking.
import { after } from 'next/server';
after(async () => {
try {
await Promise.all([
awardXP(),
checkLevelUp()
]);
} catch (err) {
console.error(err);
}
});
Layout Optimization
Move repeated components to Layout.tsx.
export default function Layout({ children }) {
const lessons = getLessons();
return (
<div>
<SideNav lessons={lessons} />
{children}
</div>
);
}
Image Optimization
Prevent layout shift.
<Image
width={500}
height={300}
sizes="(max-width: 768px) 100vw, 33vw"
priority={true} // Above fold
/>
Recommended
Ship in Days, Not Weeks
Skip the setup. Auth, Payments, Email, Database all pre-configured in TypeScript.
Data Sanitization
Validate strictly with Zod.
const schema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().min(18)
});
Security & Secrets
Prevent Leakage
import 'server-only';
// Prevents client import
Remove Console Logs
// next.config.js
compiler: {
removeConsole: {
exclude: ['error']
}
}
Server Actions Usage
Two ways to call.
// 1. Form Action
<form action={serverAction}>...</form>
// 2. Programmatic
await serverAction();
Optimistic UI
Update UI immediately.
const [state, addOpt] = useOptimistic(
initial,
(state, update) => ({...state, ...update})
);
UI Component Patterns
Pricing Card
<div className="card w-96 bg-base-100 shadow-xl border border-primary">
<div className="card-body">
<h2 className="card-title">Pro Plan</h2>
<p className="text-3xl font-bold">$29<span className="text-sm font-normal">/mo</span></p>
<ul className="my-4 space-y-2">
<li className="flex gap-2">✅ Unlimited Projects</li>
<li className="flex gap-2">✅ 24/7 Support</li>
</ul>
<div className="card-actions justify-end">
<button className="btn btn-primary w-full">Subscribe</button>
</div>
</div>
</div>
Navbar / Header
<div className="navbar bg-base-100">
<div className="flex-1">
<a className="btn btn-ghost text-xl">ShipFast</a>
</div>
<div className="flex-none">
<ul className="menu menu-horizontal px-1">
<li><a>Features</a></li>
<li><a>Pricing</a></li>
<li>
<details>
<summary>More</summary>
<ul className="p-2 bg-base-100 rounded-t-none">
<li><a>Blog</a></li>
</ul>
</details>
</li>
</ul>
</div>
</div>