Next.js Project Setup: A Clean Architecture Guide
Setting up a new project can often feel like the least glamorous part of development, but it's arguably one of the most important. A solid foundation built on clean architecture, standardized tooling, and proper configuration ensures that your project not only starts strong but remains maintainable and scalable in the long run. This guide will walk you through setting up a Next.js 14 project using the App Router, emphasizing best practices for folder structure, environment variables, TypeScript configuration, linting, formatting, and deployment.
Task 1.1: Project Setup & Environment
Let's dive into the specifics of setting up your Next.js project environment.
Initialize a New Next.js 14 Project (Using App Router)
The first step is to create a new Next.js project. Next.js 14 brings significant improvements, including the App Router, which offers a more flexible and powerful way to structure your application. To start, open your terminal and run the following command:
npx create-next-app@latest
During the setup, you'll be prompted to use TypeScript, ESLint, Tailwind CSS, and the src/ directory. Make sure to select yes for TypeScript and ESLint, as these are crucial for maintaining code quality and providing a better developer experience. You can choose whether or not to use Tailwind CSS based on your styling preferences.
The App Router is a game-changer. It allows you to define routes using the file system within the app/ directory, making your application's structure more intuitive and manageable. Embrace the App Router from the start to take full advantage of Next.js 14's capabilities.
Establish Folder Structure
A well-defined folder structure is essential for maintainability, especially in larger projects. Following a clean architecture approach, as emphasized in the "Subify Web UygulamasΔ± (v1 - MVP)" PRD, will keep your codebase organized and easy to navigate. Hereβs a suggested folder structure:
root/
βββ app/ # App Router directory
β βββ api/ # API routes
β βββ components/ # Reusable React components
β βββ lib/ # Utility functions and helpers
β βββ styles/ # Global styles and CSS modules
β βββ public/ # Static assets
β βββ utils/ # Utility functions
βββ pages/ # (Optional) Legacy pages directory
βββ .env.example # Template for environment variables
βββ tsconfig.json # TypeScript configuration
βββ .eslintrc.json # ESLint configuration
βββ .prettierrc.json # Prettier configuration
βββ vercel.json # Vercel deployment configuration
app/: This is where the heart of your application resides. Inside, you'll find directories for API routes, components, and utility functions. Leverage the App Router's file-based routing to keep your routes organized and predictable. Each route segment corresponds to a directory, and thepage.tsxfile within defines the UI for that route. Consider grouping related components within subdirectories insideapp/componentsto maintain clarity.api/: This directory houses your API routes, allowing you to create serverless functions directly within your Next.js application. Structure your API routes logically, mirroring your application's domain. For example, you might haveapi/users,api/products, and so on. Using route handlers within theappdirectory, you can define the logic for different HTTP methods (GET, POST, PUT, DELETE) within each route segment. This keeps your API logic close to your application's UI and simplifies deployment.components/: A treasure trove of reusable React components. Think of this directory as your component library. Components should be self-contained and responsible for rendering specific UI elements. Break down your UI into smaller, manageable components that can be easily reused throughout your application. Aim for a high level of component reusability to reduce code duplication and ensure consistency across your application. Consider creating auisubdirectory withincomponentsto house more generic, reusable UI elements like buttons, inputs, and modals.lib/: This is where your utility functions, helper functions, and any other non-component-specific code lives. Keep this directory clean and well-organized to avoid cluttering your main application logic. This is the perfect place for functions that handle data fetching, authentication, or any other tasks that are not directly tied to a specific component. Group related utility functions into separate modules within thelibdirectory to improve organization.styles/: All your global styles and CSS modules go here. Separate global styles from component-specific styles to maintain a clear separation of concerns. Use CSS modules for component-level styling to avoid naming conflicts and ensure that styles are scoped to the component they belong to. Consider using a CSS-in-JS library like Styled Components or Emotion for more advanced styling needs.public/: Store your static assets, such as images, fonts, and favicons, in this directory. These assets will be served directly from the root of your domain. Organize your assets within subdirectories to keep thepublicdirectory tidy. Use descriptive names for your asset files to make them easy to identify.utils/: This directory is for functions and constants. You may be tempted to useliboverutilsdirectory, but that depends on what kind of pattern you decide to follow. Either of them are valid options.
This structure is a starting point; feel free to adapt it to your project's specific needs. The key is to maintain a consistent and logical organization throughout your development process.
Create a Template for Environment Variables (.env.example)
Environment variables are crucial for managing configuration settings that vary across different environments (development, staging, production). Never commit your actual environment variables to your repository. Instead, create a .env.example file that outlines the required variables with placeholders.
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key
OPENAI_API_KEY=your_openai_api_key
LEMON_SQUEEZY_API_KEY=your_lemon_squeezy_api_key
# Add more environment variables as needed
Developers can then copy this file to .env.local (which should be added to .gitignore) and replace the placeholders with their actual values. Using environment variables helps keep sensitive information secure and allows you to easily configure your application for different environments. Tools like dotenv can help you load these variables into your application at runtime.
Make sure to NEVER commit the .env.local file to your repository. This file contains sensitive information that should be kept secret.
Configure TypeScript (tsconfig.json)
TypeScript adds static typing to JavaScript, improving code quality and developer experience. Configure your tsconfig.json file for strict mode and optimal DX. Hereβs a recommended configuration:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"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"]
}
strict: true: Enables all strict type-checking options, catching potential errors early.esModuleInterop: true: Enables interoperability between CommonJS and ES modules, allowing you to seamlessly import and export modules in different formats.resolveJsonModule: true: Allows you to import JSON files as modules.paths: Configures module path aliases, allowing you to use shorter and more readable import statements (e.g.,@/components/MyComponentinstead of../../components/MyComponent).
Set Up ESLint and Prettier
ESLint and Prettier are essential tools for maintaining code quality and consistency. ESLint lints your code, identifying potential errors and style issues, while Prettier automatically formats your code to adhere to a consistent style. Configure both with opinionated configs for TypeScript, React, and Next.js.
First, install the necessary dependencies:
npm install --save-dev eslint prettier eslint-config-next eslint-plugin-prettier
Then, configure ESLint by creating a .eslintrc.json file:
{
"extends": ["next", "next/core-web-vitals", "prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error",
"react/jsx-props-no-spreading": "off",
"@next/next/no-img-element": "off",
"react/no-unescaped-entities": "off"
}
}
This configuration extends the recommended Next.js ESLint configuration and adds the Prettier plugin, which will run Prettier as an ESLint rule. The rules section allows you to customize the ESLint rules to fit your project's specific needs. Disabling rules like react/jsx-props-no-spreading and @next/next/no-img-element might be necessary depending on your project's coding style and requirements.
Next, configure Prettier by creating a .prettierrc.json file:
{
"semi": false,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2
}
This configuration specifies the formatting rules that Prettier will use. Customize these rules to match your preferred coding style. Consistent formatting makes the code much easier to read and reduces the likelihood of merge conflicts.
Finally, add lint and format scripts to your package.json file:
"scripts": {
"lint": "next lint",
"format": "prettier --write ."
}
Now, you can run npm run lint to lint your code and npm run format to automatically format your code.
Provide Vercel Deployment Configuration (vercel.json)
Vercel is a popular platform for deploying Next.js applications. Create a vercel.json file in the root of your project to configure your Vercel deployment.
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/next"
}
],
"routes": [
{
"src": "/",
"dest": "/"
}
]
}
This configuration tells Vercel to use the @vercel/next builder to build your Next.js application. The routes section allows you to define custom routes for your application.
Acceptance Criteria
To ensure that your project setup is successful, verify the following:
- A minimal working project must build and start locally and on Vercel.
- The folder structure must align with the Clean Architecture and App Router conventions.
- Coding standards are enforced automatically via lint & format scripts.
- Environment secrets and configs are clear, separated, and never committed.
Why This Matters
A solid project foundational setup isn't just about following best practices; it's about setting your team up for success. By investing time upfront in establishing a consistent structure, standardizing tooling, and implementing proper secret management, you lay the groundwork for a maintainable and scalable SaaS codebase. This translates to faster iteration cycles, reduced technical debt, and a more enjoyable development experience.
By following these steps, you'll be well on your way to building a robust and maintainable Next.js application.
For more information on clean architecture, check out this article on freeCodeCamp.