Skip to content

Instantly share code, notes, and snippets.

@lancejpollard
Created November 28, 2011 01:50
Show Gist options
  • Save lancejpollard/1398757 to your computer and use it in GitHub Desktop.
Save lancejpollard/1398757 to your computer and use it in GitHub Desktop.
What is your folder-structure preference for a large-scale Node.js project?

What is your folder-structure preference for a large-scale Node.js project?

0: Starting from Rails

This is the reference point. All the other options are based off this.

|-- app
|   |-- controllers
|   |   |-- admin
|   |   |   |-- postsController.js
|   |   |   `-- usersController.js
|   |   |-- postsController.js
|   |   |-- sessionsController.js
|   |   `-- usersController.js
|   |-- models
|   |   |-- post.js
|   |   `-- user.js
|   |-- views
|   |   |-- admin
|   |   |   `-- posts
|   |   |       |-- edit.jade
|   |   |       |-- index.jade
|   |   |       |-- new.jade
|   |   |-- layouts
|   |   |   `-- application.jade
|   |   `-- posts
|   |       |-- index.jade
|   |       `-- show.jade
|   `-- helpers
|       |-- admin
|       |   |-- postsHelper.js
|       |   `-- tagsHelper.js
|       `-- postsHelper.js
`-- config
|    |-- application.js
|    |-- locale
|        `-- en.js
|    |-- routes.js
`-- lib
`-- spec
|    |-- helper.js
|    |-- models
|    |   |-- postSpec.js
|    |   |-- userSpec.js
|    `-- acceptance
|        |-- loginSpec.js
|        |-- signupSpec.js
|        `-- postsSpec.js
`-- vendor
|    |-- javascripts
|    |   |-- jquery.js
|    |   |-- underscore.js
|    `-- stylesheets
|        `-- prettyPhoto.css

1: Rails-like, with nested /app folders for client, mobile, etc.

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|   `-- browser
|       |-- controllers
|       |-- models
|       |-- views
|   `-- mobile
|       |-- controllers
|       |-- models
|       |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • lends itself great to progressive enhancement so-to-speak. You start with just /app, and if your app starts growing, you add sub directories.
  • doesn't pollute the top-level directories, which have a pretty uniform convention across apps. However, people do add /themes to the top level, which is just about the same as adding /client to the top-level.

Cons:

  • Now you have /app/models and /app/browser, etc., which isn't a totally clear naming convention -- /app/models is for a subset of code for the server, while /app/browser is a totally different app. It's different than a namespace like /app/models/admin though, which makes sense.

My vote: no

2: A /app/client folder, similar to Rails' /app/assets

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|   `-- client
|       `-- browser
|           |-- controllers
|           |-- models
|           |-- views
|       `-- mobile
|           |-- controllers
|           |-- models
|           |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • The main reason you need these extra folders is for the different clients for the app. So putting them in /app/client conceptually makes a lot of sense. It's easy to reason about.
  • Similar to Rails, which has /app/assets/javascripts instead of /app/client. You don't want to start naming the folder /app/assets because, conceptually, everything is JavaScript, and calling one chunk of JavaScript "assets" and the rest "app" is conceptually jarring.

Cons:

  • You have deeply nested folders for core code, which can be annoying. /app/client/browser/controllers/postsController.js is 4 folders down. But with TextMate and CMD+T, it shouldn't be an issue.

You could also have this structure if you only had 1 client (or just a default client):

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|   `-- client
|       |-- controllers
|       |-- models
|       `-- views

That's pretty clear, and it lends itself to agile development really well.

My vote: ✔

3: More top-level folders

|-- app
|   |-- controllers
|   |-- models
|   |-- views
|-- browser
|   |-- controllers
|   |-- models
|   |-- views
|-- mobile
|   |-- controllers
|   |-- models
|   |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • Minimum folder nesting
  • model/view/controller folders are all at the same level

Cons:

  • Having multiple top-level folders, all of which are mvc code, is not conceptually clear. They should be part of one directory (taking us back to #2). Having every folder at the top level be a completely conceptually distinct part of the app (database vs. app vs. config vs. tests) is a clarifying convention.

My vote: second choice, but no

4: Namespaces inside /app

|-- app
|   `-- client
|       |-- controllers
|       |-- models
|       |-- views
|   `-- mobile
|       |-- controllers
|       |-- models
|       |-- views
|   `-- server
|       |-- controllers
|       |-- models
|       |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • Clear, normalized separation of concerns. Everything fits into the same folder structure, instead of having the "default" stuff in /app, and then also nesting components in there.

Cons:

  • For the simple case, you have to create a nested folder.
    • Counterargument: But, you're setup to easily add other clients for the app
  • By not having the default code go in the top level /app, it's not as clear that server code can be used on the client (e.g. using /app/server/models/user.js on the client. it makes sense if it's in /app/models/user.js however.).

My vote: no

5: Top-level /client and /server directories

This breaks convention, but it's an option. Rename /app to /server

|-- client
|   |-- controllers
|   |-- models
|   |-- views
|-- server
|   |-- controllers
|   |-- models
|   |-- views
`-- config
`-- lib
`-- spec
`-- vendor

Pros:

  • Clear: there is a client and server app.

Cons:

  • If you had multiple client apps (browser, mobile, ipad, etc.), you'd end up doing things like #2 or #3.

My vote: no

Which do you prefer?

I prefer folder structure #2.

@vjpr
Copy link

vjpr commented Jan 18, 2014

@mb-dev I am settling on a similar approach. Grouping by functionality is much easier to work with.

@flemay
Copy link

flemay commented Jan 21, 2014

@mb-dev and @vjpr: where do you put your server files in that structure?

@koistya
Copy link

koistya commented Feb 4, 2014

@vanng822
Copy link

don't have big project but here is the structure I use and works really well for me, more or less option 3
https://github.com/vanng822/appskeleton

@fidanov
Copy link

fidanov commented Oct 10, 2014

I prefer something very similar to your first example (the rails inspired). Here is a tutorial about it and below is an example of an app applying it.

|--project
|  |--controllers/
|  |  |--comments.js
|  |  |--index.js
|  |  |--users.js
|  |  helpers/
|  |  |--dates.js
|  |--middlewares/
|  |  |--auth.js
|  |  |--users.js
|  |--models/
|  |  |--comment.js
|  |  |--user.js
|  |--public/
|  |  |--libs/
|  |  |--css/
|  |  |--img/
|  |--views/
|  |  |--comments/
|  |  |--|--comment.jade
|  |  |--users/
|  |  |--index.jade
|  |--tests/
|  |  |--controllers/
|  |  |--models/
|  |  |  |--comment.js
|  |  |--middlewares/
|  |  |--integration/
|  |  |--ui/
|  |--.gitignore
|  |--app.js
|  |--package.json

I've also prepared a small repository on GitHub, which uses the same structure, for any new projects. I will try keep its dependencies up to date.
https://github.com/terlici/base-express

@ssmereka
Copy link

I prefer to group my files by feature, rather than function. So for example group all user related files (controllers, models, tests, and etc.) in a folder. Then that folder can be easily reused in other projects or when making changes it is easier to find the files affected. So for example:

I created a module to allow this type of file structure by dynamically requiring files.
https://github.com/ssmereka/crave

@dschinkel
Copy link

Definitely everyone (even seasoned devs) should first watch Uncle Bob's vid as suggested by mb-dev. Talks about how your top level should not indicate what kind of app it is (Rails, CoffeeScript, etc.). The language shouldn't dominate your project structure at a top level. http://confreaks.tv/videos/rubymidwest2011-keynote-architecture-the-lost-years

@emadb
Copy link

emadb commented Aug 3, 2015

I don't like categorizing files based on their framework role (ie Controllers, Views, ....) but I like divide my files based on their functionality.
So, for example, in an ecommerce app, I end up having a folder all the files of the products, another for the basket management, another for the warehouse and so on.
In this way every modules of the application is separated from the others and it's easier maintain them or even rewrite if necessary.

|--app
|  |--orders/
|  |--basket/
|  |--warehouse/
|  |--common/
|  |--tests
|  |  |--basket/
|  |  |--warehouse/
|  |  |--common/
|  |  |--users.js
| --gruntOrGulp.js
| --README.md

@jpierson
Copy link

As an experienced developer who is new to NodeJS I've been hunting for a reasonable organization structure myself. From my experience working a bit with AngularJS I do prefer grouping by functionality over roll in the framework as others such as @emadb have mentioned. I also have had particular difficulty in parsing which code belongs to the build process, the server side, and the client side parts of the application.

@rkt2spc
Copy link

rkt2spc commented Apr 5, 2017

Grouping files by feature become complicated when many reusing happen. What if 2 features required the same model, in which component should I put the model definition?

@mareksuscak
Copy link

@rocketspacer at that moment you lift it up and make it a shared/common concern

@Randy808
Copy link

Randy808 commented Sep 2, 2017

@autoferrit I see where you put "I vote to have an en[v]ironment variable of some sort for each directory which is an array of paths." but still don't see how it would actually be used. You only separate sites by views, so where would you be able to swap out a models directory? Is it in the server file that a request first hits (the file that includes all the controllers, server config, etc)? Also, do you determine who the client is in that server file? I also don't understand how all the sites would share the same public folder unless each site has their own controller within the app subdirectory of the site. Is that what's happening? I'm fairly new to API architectures and would appreciate any clarification, thanks!!

@demisx
Copy link

demisx commented Sep 18, 2017

+1 for @emadb's organization. Feature based structure is the way to go.

@inancgumus
Copy link

@rocketspacer That means, there's a new concept waiting to go into its own package. And then, separate the dependencies via abstractions.

@rkt2spc
Copy link

rkt2spc commented Jan 30, 2018

@mareksuscak @inancgumus I can't really make a solid project structure out of a vague emerging concept simply because I don't know how to properly name it. How common is common, what should I call the abstraction of login and transaction?
We decided to adopt Microservices and solve this problem at a different level now.

@alamenai
Copy link

@lancejpollard ,what we put in 'spec' folder ?

@nbaua
Copy link

nbaua commented Mar 13, 2019

@lancejpollard ,what we put in 'spec' folder ?

Test cases

@bomzj
Copy link

bomzj commented May 8, 2019

Feature Folders is the way to go for any size of project!

@danmandel
Copy link

I don't think there's any optimal answer between grouping by function vs grouping by feature, it seems to just come down to personal preference. It would be nice if there was an IDE setting or global tool that devs could install to make swapping between folder structures as easy as a 1-line change in a config file.

@mytharcher
Copy link

mytharcher commented Sep 9, 2019

My principal:

  • Any folder should match the concept of dimension, so /<feature> and /test should not be placed under same folder.
  • Node.js project should not combine both client and server codes, unless you need SSR, so I will not need to concern about the mixed project folders.

And my further consideration is that sometime (I can say more than half) my services code can't always match to the model (database tables) / controller (routes). Because controller sometimes needs to handle webhooks which not match to model, and services may also for third-party integration logics. So I prefer the function rather than feature.

While the architecture will evolve into micro services in future, function layer first will not become more complex.

Something I am confused is when I divide the function, how my main app logic folder should be named? Like src / lib / main / app? Another confusion is should I just place the main logic layer folders under project root? Such as controllers / services / model / test ... etc.

I have read about the guideline of golang project layout, and agreed with their idea about the /src:

Some Go projects do have a src folder, but it usually happens when the devs came from the Java world where it's a common pattern. If you can help yourself try not to adopt this Java pattern. You really don't want your Go code or Go projects to look like Java :-)

So my practice now has been summarized into a repository here: express-bootstrap. Any discussion or idea will be welcome.

@lancejpollard
Copy link
Author

Here is my current system.

@vish9812
Copy link

vish9812 commented Feb 28, 2020

Feature based structure seems the way to go!

Here is my app

|--src 
|  |--core  
|  |  |--orders
|  |  |--basket
|  |  |--common
|  |--infrastructure
|  |  |--auth/
|  |  |--logger/
|  |--utils
|  |  |--config
|  |  |--crypto
| --package.json
| --index.js
| --README.md

@nashid
Copy link

nashid commented Jun 24, 2020

@Vishch - you don't give a clear separation of tests. All the tests go to the tests folder?

@vish9812
Copy link

vish9812 commented Jun 25, 2020

@nashid yes the tests should go in their respective feature folders

@vikrantsingh47
Copy link

@nashid yes the tests should go in their respective feature folders

should the routes also go in their respective feature folders?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment