Next.js
Next.js App Router (TypeScript) Style Guide
General Principles
- Follow Airbnb JavaScript/React Style Guide for React and TypeScript.
Folder and File Structure
- Follow Next JS Project Structure
app/ # App Router pages
components/ # Reusable components
hooks/ # Custom hooks
lib/ # Utilities and helpers
services/ # API calls or external integrations
styles/ # Global and modular styles
types/ # TypeScript types and interfaces
context/ # Context API setup
middleware/ # Middleware (if needed)
config/ # Configuration files
layout.tsx
page.tsx
global.css
middleware.ts
config.ts
package.json
File Naming
- Use kebab-case for React component files, utility, hooks, or helper files.
Examples:
app/home/page.tsx
components/ui/button.tsx
components/login-form.tsx
hooks/use-fetch.ts
lib/format-date.ts
Imports
- Organize imports from libraries to internal files:
// React or third-party libraries
import { useState } from 'react';
import { format } from 'date-fns';
// Internal components and helpers
import NavBar from '@/components/navbar';
import { formatDate } from '@/lib/format-date';
React Components
- Use functional components
- Use TypeScript for typing props and state.
Example:
interface LoginProps {
status?: string;
canResetPassword: boolean;
}
export default fanction LoginForm({status, canResetPassword}: LoginProps){
return (
<div>LoginForm</div>
)
}
TypeScript
- Enable strict mode in
tsconfig.json
:
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
- Avoid using
any
. Always use specific types.
Example:
// Correct
const fetchUser = async (id: number): Promise<User> => {
// ...
};
// Incorrect
const fetchUser = async (id: number): Promise<any> => {
// ...
};
Styling
- Use CSS Modules or Tailwind CSS for modular styling.
Example:
import styles from './NavBar.module.css';
const NavBar: React.FC = () => {
return <nav className={styles.nav}>NavBar</nav>;
};
export default NavBar;
- Global styles are stored in
globals.css
and imported inapp/layout.tsx
.
import './globals.css';
export const metadata = {
title: 'Next.js App',
description: 'Generated by Next.js',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Testing
- Use Jest and React Testing Library for unit testing.
Example:
import { render, screen } from '@testing-library/react';
import Button from '@/components/Button';
test('renders Button with label', () => {
render(<Button label="Click Me" onClick={() => {}} />);
expect(screen.getByText(/Click Me/i)).toBeInTheDocument();
});
- Use Playwright or Cypress for end-to-end testing.
Linting and Formatting
- Use ESLint with the following configuration in
eslint.config.mjs
:
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];
export default eslintConfig;
- Use Prettier with the following configuration in
.prettierrc
optional:
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80
}