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
Examples:
app/home/page.tsx
components/ui/button.tsx
components/login-form.tsx
hooks/use-fetch.ts
lib/format-date.ts
// 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';
Example:
interface LoginProps {
status?: string;
canResetPassword: boolean;
}
export default fanction LoginForm({status, canResetPassword}: LoginProps){
return (
<div>LoginForm</div>
)
}
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"]
}
any
. Always use specific types.Example:
// Correct
const fetchUser = async (id: number): Promise<User> => {
// ...
};
// Incorrect
const fetchUser = async (id: number): Promise<any> => {
// ...
};
Example:
import styles from './NavBar.module.css';
const NavBar: React.FC = () => {
return <nav className={styles.nav}>NavBar</nav>;
};
export default NavBar;
globals.css
and imported in app/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>
);
}
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();
});
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;
.prettierrc
optional:{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80
}