Clean Architecture is a software design pattern that aims to create modular, maintainable, and scalable applications. The main principles of Clean Architecture are separation of concerns, dependency inversion, and testability. In this tutorial, I will show you how to implement Clean Architecture in a Next.js application.
Step 1: Set up a Next.js project
First, you need to create a new Next.js project. You can do this by running the following command in your terminal:
npx create-next-app@latest my-clean-architecture-app
This will set up a new Next.js project with the necessary folder structure and dependencies.
Step 2: Create the project structure
Next, you need to create the directory structure for your project. In Clean Architecture, the code is divided into layers, each with a specific responsibility. The typical layers in Clean Architecture are:
- Entities: Contains the domain models and business logic of your application.
- Use Cases: Contains the application-specific use cases.
- Interface Adapters: Contains the implementation details such as UI components, database access, and external API integration.
- Frameworks & Drivers: Contains the external dependencies such as the Next.js framework itself.
Here is an example directory structure for a Clean Architecture Next.js project:
├── components
├── entities
├── pages
├── services
Step 3: Implement the Entities
In the entities
directory, you can define the domain models and business logic of your application. For example, if you are building a todo list app, you could define a Todo
entity like this:
// entities/Todo.js
export default class Todo {
constructor(title, completed) {
this.title = title;
this.completed = completed;
}
}
Step 4: Implement the Use Cases
In the services
directory, you can implement the application-specific use cases. For example, you could define a TodoService
class that handles CRUD operations for todos:
// services/TodoService.js
import Todo from '../entities/Todo';
export default class TodoService {
constructor() {
this.todos = [];
}
createTodo(title) {
const todo = new Todo(title, false);
this.todos.push(todo);
return todo;
}
getTodos() {
return this.todos;
}
}
Step 5: Implement the Interface Adapters
In the pages
and components
directories, you can implement the interface adapters such as React components and API integration. For example, you could create a TodoList
component that displays the list of todos:
// components/TodoList.js
import { useEffect, useState } from 'react';
import TodoService from '../services/TodoService';
const todoService = new TodoService();
const TodoList = () => {
const [todos, setTodos] = useState([]);
useEffect(() => {
setTodos(todoService.getTodos());
}, []);
return (
<div>
{todos.map(todo => (
<div key={todo.title}>
<p>{todo.title}</p>
<p>{todo.completed ? 'Completed' : 'Incomplete'}</p>
</div>
))}
</div>
);
};
export default TodoList;
Step 6: Use the components in your Next.js pages
Finally, you can use the interface adapters in your Next.js pages. For example, you could create a pages/index.js
file that renders the TodoList
component:
// pages/index.js
import TodoList from '../components/TodoList';
const Home = () => {
return (
<div>
<h1>Todo List</h1>
<TodoList />
</div>
);
};
export default Home;
That’s it! You have now implemented Clean Architecture in a Next.js application. This approach allows you to easily test and maintain your code, as well as scale your application as it grows. I hope this tutorial was helpful to you. Happy coding!
This live stream series is A LOT, so I distilled everything we learned + built a proper demo app that's open source into a 53 minute tutorial: https://youtu.be/jJVAla0dWJo
thank you!
1:35:48 Effect looks good. Is it just like Promise<Either<Failure,Success>> from fp-ts? I found that way of error handling easy and light weight.
My only question is on generating nanoid. In the repository layer we are tightly coupling our persistence/data layers with a package. Please correct me if I am wrong, wouldn’t it be better if we pass that package through the constructor as a service so that it is not tightly coupled to the library?
Hi, thanks for the great tutorial and series. Really enjoying it. Small problem I had watching was would have been nice if it was from scratch so we (i could code along) as you explained things. like the structure, creating of some of those files, but I still enjoyed it. h
Could you please let me know why you are calling const supabase = createClient() for each function?
Thank you for that stream!
That keyboard loved it. 😀
I definitely see the value in this, but for my new MVP this might be an overkill atm, but once its launched and others start working with me then this would make absolute sense, less files edited, more concise folder structures. this makes sense actually. Ill need to take some time to organize it like this.
We need more stuff like this, ❤
Just so you know for the future: when passing arguments to constructors in TS, you can automatically assign them to properties on the class with a syntax like `constructor(private id: string) {}` — that way you don't have to repeat both the property definition and the assignment.
Please create your development environment setup series
Please create you development environment setup series
I came to review concepts, hopefully later we can see a complete auth system with the backend and frontend to see the entire flow with architecture, how to handle everything with jwt and so on.
No relying on underlying implementation is called abstraction – https://youtu.be/BaUsKK6AX5Q?t=246 – its a fundamental concept in Software engineering. To make a more sense, your car is a better example, you don't need to know anything about how it works just to drive and use it for your needs 🤫
Thanks :3
My dude, i am a self taught junior developer and whilst i can write clean code, after 2 years now i realized how our apps we / i am working on have 0 architecture, 0 high level thought, and they are a complete mess on this level and the problems they bring. And it seems my peers are absolutely oblivious to this as they did not signal this and also we never had an 'architectural discussion' ( if that is even something happening at other places 😀 ), and as such i have no direct peer to learn from. So these kind of videos are gems inside the superficial hello world application videos most of youtube is filled with.
Great session man. I like your keyboard setup too 🔥😃
What do you think about using row level security?
What keyboard are you using? 😀
Will you create a video about neovim how to install it and with your config? 😀