Skip to content

Instantly share code, notes, and snippets.

@lancejpollard
Created November 28, 2011 01:50
Show Gist options
  • Select an option

  • Save lancejpollard/1398757 to your computer and use it in GitHub Desktop.

Select an option

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.

@flemay

flemay commented Jan 21, 2014

Copy link
Copy Markdown

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

@koistya

koistya commented Feb 4, 2014

Copy link
Copy Markdown

@vanng822

Copy link
Copy Markdown

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

fidanov commented Oct 10, 2014

Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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

emadb commented Aug 3, 2015

Copy link
Copy Markdown

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
Copy Markdown

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

rkt2spc commented Apr 5, 2017

Copy link
Copy Markdown

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
Copy Markdown

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

@Randy808

Randy808 commented Sep 2, 2017

Copy link
Copy Markdown

@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

demisx commented Sep 18, 2017

Copy link
Copy Markdown

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

@inancgumus

Copy link
Copy Markdown

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

@rkt2spc

rkt2spc commented Jan 30, 2018

Copy link
Copy Markdown

@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
Copy Markdown

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

@nbaua

nbaua commented Mar 13, 2019

Copy link
Copy Markdown

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

Test cases

@bomzj

bomzj commented May 8, 2019

Copy link
Copy Markdown

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

@danmandel

Copy link
Copy Markdown

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

mytharcher commented Sep 9, 2019

Copy link
Copy Markdown

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
Copy Markdown
Author

Here is my current system.

@vish9812

vish9812 commented Feb 28, 2020

Copy link
Copy Markdown

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

nashid commented Jun 24, 2020

Copy link
Copy Markdown

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

@vish9812

vish9812 commented Jun 25, 2020

Copy link
Copy Markdown

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

@vikrantsingh47

Copy link
Copy Markdown

@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