Throughout my journey as a developer, I’ve encountered a variety of methods for organizing folder structures, from the most straightforward to the highly complex.
Before I explain why I prefer the following folder structure, let’s delve into the motivation behind it.
Motivation
When considering an effective folder structure, it should possess the following qualities:
Ease of Use: It should be simple to determine where a file or folder should be created and where to find existing ones.
Consistency: Developers should consistently apply the proposed folder/file structure.
To achieve ease of use, the folder/file structure should be clear and intuitive, so developers don’t spend excessive time locating or creating files and folders.
For consistency, code reviewers should ensure the structure is adhered to during code reviews. From my experience, simpler folder structures tend to be easier to follow. Complex structures can lead to confusion and misplaced files/folders due to the extra effort required to understand them.
Structure
I advocate for simple folder structures to minimize the time spent organizing files. Here’s my recommended structure:
│ ├── controllers
│ ├── routes
│ ├── models
│ ├── app.ts
app.ts
In this file, initialize the server, connect to a database, and import routes from the /routes folder. Here’s an example:
import { usersRouter } from ‘./routes‘;
import { productsRouter } from ‘./routes‘;
import bodyParser from ‘body-parser‘;
import cors from ‘cors‘;
import mongoose from ‘mongoose‘;
import “dotenv/config“;
const app = express();
const PORT = process.env.PORT || 3001;
const DB_URI = process.env.DB_URI || ‘mongodb://localhost:27017/mydatabase‘;
// Middleware
app.use(bodyParser.json());
app.use(cors());
// Database Connection
mongoose.connect(DB_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log(‘Connected to the database‘))
.catch(err => console.error(‘Database connection error:‘, err));
// Routes
app.use(‘/users‘, usersRouter);
app.get(‘/products‘, productsRouter);
// Server
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
/models
The models folder is crucial for defining schemas and data interactions. It includes the representation of your database tables and the logic to interact with them. Here’s an example of a simple Mongoose model for a User in a file named User.model.ts:
import mongoose, { Schema, Document } from ‘mongoose‘;
export interface IUser extends Document {
name: string;
email: string;
password: string;
}
const UserSchema: Schema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
export default mongoose.model<IUser>(‘User‘, UserSchema);
/routes
To keep things clean, use a /routes folder. Instead of declaring all routes in app.ts, isolate them. For example, in a file named users.routes.ts:
import express from ‘express‘;
import { getUsers, createUser, deleteUser, updateUser } from ‘../controllers/users‘;
export const usersRouter = express.Router();
usersRouter.get(‘/‘, getUsers);
usersRouter.post(‘/‘, createUser);
usersRouter.delete(‘/‘, deleteUser);
usersRouter.put(‘/‘, updateUser);
/controllers
The controllers folder will likely have the most files and code. To manage this, break it down into smaller pieces. For instance:
│ ├── users
│ ├── products
Within each folder, isolate each method into individual files to keep them manageable:
│ ├── getUsers.controller.ts
│ ├── createUser.controller.ts
│ ├── deleteUser.controller.ts
│ ├── updateUser.controller.ts
Conclusion
While this file structure is simple, it’s also very easy to understand and follow. This results in a concise, modularized, and clear folder structure. Remember, you can adapt the folder structure according to your needs, but it’s essential to keep it simple to maintain clarity and organization.
I’m excited to hear your thoughts—what folder structure works best for you? Let me know in the comments below! 🌟