Organizing your Express.js project structure for better productivity
Tags: node
Published: 2022-01-20 17:12:02

**Written by [Geshan Manandhar](https://blog.logrocket.com/author/geshanmanandhar/)✏️**

Express.js is the most popular Node.js framework for web development. It’s fast, unopinionated, and has a large community behind it. It is easy to learn and also has a lot of modules and middleware available for use.

Express is [used](https://expressjs.com/en/resources/companies-using-express.html) by big names like Accenture, IBM, and Uber, which means it’s also great in a production environment. If you are similarly using Express in this manner (or even just using Express with a team), it’s important to learn how to organize your project structure to increase productivity.

In this post, we will learn how to organize an Express project to be used by a team of software engineers in order to enhance productivity and maintainability. Let’s get started!

## Why use Express.js?

In addition to being one of the most popular Node frameworks, Express also provides the optimal building blocks like routing, middleware, and other components to get an application working quickly. It offers simplicity, efficiency, and minimalism without the baggage or opinions. That is why a good structure is needed when working with Express, especially in a team of software engineers.

## Comparison with other frameworks

In comparison to other frameworks like [NestJS](https://blog.logrocket.com/node-back-end-next-level-nestjs/) or AdonisJs, Express does not draw upon any structure or format. It does not impose any opinions on how to lay out the files and which part of the logic should reside somewhere specific.

For example, if you have worked with [Laravel](https://blog.logrocket.com/whats-new-in-laravel-8/) in PHP, it essentially makes decisions for you on where to put the controllers, how things will function, or which ORM to use by default.

Express, on the other hand, does not come with these premeditated decisions. It lets the user decide the structure and layout of the project. This can be a double-edged sword, because having no opinions provides flexibility, but if used incorrectly, can lead to a disorganized mess that is very difficult to understand.

This also leaves room for inconsistencies, which is very bad for a team. Therefore, the next section will detail a well-organized, while still unopinionated structure for an Express project.

## Example of a well-organized Expess.js project structure

For a good web project, for instance, an API will surely have some routes and controllers. It will also contain some middleware like authentication or logging. The project will have some logic to communicate with the data store, like a database and some business logic.

This is an example structure that can help organize the code for the things I mentioned above. I will explain further how I organized this project below:

![Image of file structure in Express](https://blog.logrocket.com/wp-content/uploads/2022/01/expressjs-project-structure.png)

Let’s dive deeper into the main folders `src` and `test` and the subfolders inside them. The main entry point of this organized Express application is the `index.js` file on the root, which can be run with Node using `node index.js` to start the application. It will require the Express app and link up the routes with relative routers.

Any middleware will also be generally included in this file. Then it will start the server.

### Folder structure

In the image above, you will see two main folders: `src` houses the source code, and `test` has all the testing code in it. Time to dig a bit deeper into the `src` subfolders.

First, we have the `configs` folder, which keeps all the configs needed for the application. For example, if the app connects to a database, the configuration for the database (like database name and username) can be put in a file like `db.config.js`. Similarly, other configurations like the number of records to show on each page for pagination can be saved in a file named `general.config.js` inside this `configs` folder.

The next folder is `controllers`, which will house all the controllers needed for the application. These controller methods get the request from the routes and convert them to HTTP responses with the use of any middleware as necessary.

Subsequently, the `middlewares` folder will segregate any middleware needed for the application in one place. There can be middleware for authentication, logging, or any other purpose.

Next up, we have the `routes` folder that will have a single file for each logical set of routes. For example, there can be routes for one type of resource. It can be further broken down by versions like v1 or v2 to separate the route files by the version of the API.

After that, the `models` folder will have data models required for the application. This will also depend on the datastore used if it is a relational or a non-relational (NoSQL) database. Contents of this folder will also be defined by the use of an [Object Relational Mapping (ORM)](https://blog.logrocket.com/why-you-should-avoid-orms-with-examples-in-node-js-e0baab73fa5/#whatisorminnodejs) library. If an ORM like [Sequelize](https://blog.logrocket.com/using-sequelize-with-typescript/) or [Prisma](https://blog.logrocket.com/prisma-2-introduction/) is used, this folder will have data models defined as per its requirement.

Consequently, the `services` folder will include all the business logic. It can have services that represent business objects and can run queries on the database. Depending on the need, even general services like a database can be placed here.

Last but not the least, we have the `utils` directory that will have all the utilities and helpers needed for the application. It will also act as a place to put shared logic, if any. For example, a simple helper to calculate the offset for a paginated SQL query can be put in a `helper.util.js` file in this folder.

The `test` folder has subfolders like `unit` and `integration` for unit and integration tests.

The `unit` folder inside the `test` folder will have a structure similar to the `src` folder, as each file in the `src` folder will need a test, and it is best to follow the same structure, like so:

![Expanded test folder structure in Express](https://blog.logrocket.com/wp-content/uploads/2022/01/Express-test-folder-structure.png)

The `helper.util.test.js` file is placed inside the `utils` folder in the `unit` folder. This is the same pattern as in the `src` folder. In our example project in the next section, we will use Jest to write and run the tests.

Even with this folder structure, some things can be missed. For example, if your project is using [RabbitMQ with Node](https://geshan.com.np/blog/2021/07/rabbitmq-docker-nodejs/), you will need to keep the publishers and consumers in well-organized folders. Similarly, if you are creating a CLI application to do [web scraping with Node](https://geshan.com.np/blog/2021/09/web-scraping-nodejs/), this project structure might be only partially helpful. Having mentioned that, this folder structure will suffice for most API or general web projects that need a better layout.

Also, keep in mind that other files may be needed, like a `.env` file to keep the secrets safe and different per deployment environment. In the next part, we will look into an example project that follows the structure I have just laid out.

## Example Project with Node.js and MySQL

There are many great examples of using [Node.js with MySQL](https://blog.logrocket.com/node-js-express-js-mysql-rest-api-example/), so we will call our example app the Programming Languages API, which lists popular programming languages.

We can use the free tier of [PlanetScale](https://planetscale.com/), a MySQL-compatible, serverless hyper-scale oriented service. You can view the code of this working app in the [GitHub](https://github.com/geshan/expressjs-structure) repository:

![Github page with Express project](https://blog.logrocket.com/wp-content/uploads/2022/01/GitHub-express-project-structure.png)

In addition to the `src` folder structure seen above, the tests for the project can be executed by running `npm test` on the root, which runs Jest. There are only some tests for the `helper.util.js` file, but that gives a good sense of how to organize the source and the unit test code.

Similar to other Node and Express projects we can run `npm start` to run this project and hit [http://localhost:3000/programming-languages](http://localhost:3000/programming-languages) to see the result. You will need to set up the database correctly, preferably on PlanetScale, and put the correct credentials in the `src/configs/db.config.js` file for it to work properly.

## Conclusion

In this article, we have seen how to provide an opinionated structure to an unopinionated Express framework. The organization really helps to maintain consistency, especially in a larger team.

Consistency in the project structure equates to the predictability of where the code can be expected, which in turn helps in the productivity of the whole team. Always make things easily predictable with a consistent structure to minimize or eliminate the guesswork, and help your team achieve their goals.

---

## [LogRocket](https://logrocket.com/signup/): Full visibility into your web apps

![LogRocket signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)

[LogRocket](https://logrocket.com/signup/) is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

## 200’s only :heavy_check_mark: Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, [try LogRocket](https://logrocket.com/signup/). 

![LogRocket signup](https://blog.logrocket.com/wp-content/uploads/2019/12/network-request-filter-2-1.png)https://logrocket.com/signup/ 

[LogRocket](https://logrocket.com/signup/) is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. [Start monitoring for free](https://logrocket.com/signup/).

[Try it for free](https://logrocket.com/signup/).