AngularJS Best Practices: I’ve Been Doing It Wrong! Part 1 of 3


Three sanity-preserving ideas that will make me and you 10x more productive with real-world AngularJS applications.

This is the first in a three-part series on practical large-scale development with AngularJS. The TL;DR version is at the end of the article.

I’ve been working on a large webapp that uses AngularJS for a few months now. As many developers who pick up new things as they go do, I started with the tutorial (in the state it was a few month ago), adapted the parts of its code I understood into the app, and grew it from there, gradually adding and changing the code, which over time became harder and harder to manage. Now we’re dealing with JavaScript modules that span thousands of lines of code, contain huge controller functions, and in a few places, use such shortcuts for jQuery-Angular interaction that I would not want my grandma to accidentally find on my computer.

But it does not have to be that way. There are pragmatic, practical, achievable ways to maintain our AngularJS projects in a healthy state. All it takes is a little forethought, a bit of discipline and a general preference for sanity rather than madness.

So, this post is sort of a note to myself, but I’ll be glad if it helps anybody else to keep their Angular projects from turning into a mess. If you are seeing too much functionality lumped together into huge modules “for historical reasons”, or struggling through a 1,000-line procedure that manipulates DOM, updates models, and talks to the server at the same time, you know you’ve been doing it wrong, and your code needs restructuring.

Here are the three areas where I’m improving my AngularJS development, with the aid of the latest and greatest tools:

  • Project layout: it’s important how you structure your directories. You are adding a new feature, and you immediately know where its directives, controllers, and models go. You need to fix a bug in a feature you have not touched in a year, and you know exactly where to look.
  • Automatic testing: With Angular, as it turns out, testing is much more enjoyable than it used to be. If you’ve strayed from the righteous path of unit-testing your code (like I did), Angular makes it easy to straighten your ways and get into healthy habits of TDD again.
  • Avoiding bad habits and common mistakes, and taking advantage of the best tools and practices that have been developed by people much smarter than I: more on this later.

Part 1: Directory Layout that Scales with the Project

We need a directory structure that will make it easy to

  • add things as we go,
  • keep the size of our modules manageable,
  • and keep everything in an easy-to-navigate, logical structure.

Here’s one example of a proposed structure: angular-seed project. It is made by the AngularJS team, it includes lots of good things like tests and places for all the essential parts:

  • app/ – all of the files to be used in production
    • css/ – css files
    • img/ – image files
    • index.html – app layout file (the main html template file of the app)
    • js/ – javascript files
      • app.js – application
      • controllers.js – application controllers
      • directives.js – application directives
      • filters.js – custom angular filters
      • services.js – custom angular services
    • lib/ – angular and 3rd party javascript libraries
    • partials/ – angular view partials (partial html templates)
  • config/ – config files for running unit tests with Testacular/Karma
  • scripts/ – handy shell/js/ruby scripts (run unit tests and dev server)
  • test/ – test source files and libraries

However, as your project grows, you’ll add tons and tons of code into controllers, services and directives. Using a file for each of these areas steers you into a direction where you’ll end up with “piles on the floor” – you know your AccountListController is somewhere in the Controllers pile, but it will take you a while to find it. In other words, angular-seed packages your code by layers. Here’s a place for all controllers, here’s a place for data services, etc.

You can make it more usable by using sub-directories for controllers, and so on:

  • controllers/
    • LoginController.js
    • RegistrationController.js
    • AccountListController.js
    • SearchResultsController.js
  • directives.js
  • filters.js
  • services/
    • CartService.js
    • UserService.js
    • AccountService.js

This is much better, since you have a nice place for everything. Now I can easily find where to add new modules or where to find current code that handles Account Lists.

But what if I need to reuse my login controller in another application? I can just copy LoginController.js into the other app’s controllers directory. As soon as I do that and refresh the browser, I see an error: the system does not know what a User object is. Ah yes, I forgot to copy UserService.js into services directory. A more complex feature would also involve some custom directives and filters. And do not forget the tests! It would suck if I copied all that code into another project but forgot to copy its tests from all the subdirectories of tests/unit that correspond to controllers, services, filters and directives of this feature. So many places to remember to look into when reusing code! Yuck! My head hurts already.

Let’s try a different approach. Enter ng-boilerplate, the best AngularJS project template in the world (to my knowledge at the time of this writing). Here’s its version of module layout:

  • build/
  • src/
    • app/
    • assets/
    • components/
    • less/
  • testacular/ (or karma/)
  • vendor/
  • Grunfile.js
  • module.prefix
  • module.suffix
  • package.json

There’s a lot of stuff here, but that’s justifiable: we are talking about huge application scalability, not an introduction-level tutorial. I’ll focus on the main part, our application source, first, and then I’ll go through the essential supporting parts one by one.

Layout of src: feature-based modularization

  • src/
    • app/
      • about/
        • about.js
        • about.tpl.html
      • home/
        • home.js
        • home.less
        • home.spec.js
        • home.tpl.html
      • app.js
      • app.spec.js
    • assets/
    • components/
    • less/
    • index.html

Application-specific code lives under app/. In the boilerplate, the application has two sections, “home” and “about”. Each of the features has its own single directory, which contains everything: Angular module declaration, controllers, routes, templates, styles, and unit tests.

In a larger app, we’ll add more sub-directories for specific controllers, services and directives related to specific features. We’ll probably grow the test suite and place tests into a “tests” directory. But still, all will be contained in one place, so you know where to look for bugs related to the “home” feature, or to add more functionality to it. A feature can be copied for reuse in one operation. This will scale much better than the previous layer-based modularization. The best part of this layout is that any new developer who looks at your code will instantly understand what your application does. And you, looking at your own app a year from now, will not scratch your head and mumble obscenities about the moron who wrote this crap.

The .spec.js files are the unit tests. The build system will scan the directory structure and pick up all the tests automatically.

The .tpl.html files are HTML templates. The rest is not hard to follow if you peek into the source.

Note, again, the app-specific unit tests alongside app.js module. This is logical. This is good. I like it.

Assets contains static files – fonts, images, static style sheets (ng-boilerplate will place here an IE-specific stylesheet to enable Font Awesome for it).

Components is a place for reusable parts of the app – both third party and your own. Every component you place here should be drag-and-drop reusable in any other project; they should depend on no other components that aren’t similarly drag-and-drop reusable.

Less contains all the LESS/CSS sources. If you prefer SASS to LESS, you can replace it and use grunt-sass task to integrate SASS compilation into the Grunt build.

Finally, index.html is the page of our single-page application. In addition to being an HTML5 document and an AngularJS template, it is also a Grunt template (see the following section for details on Grunt), and variables defined in the Gruntfile.js, such as directory names based on the projec name can be used here.

Next, let’s look in more detail at all the other parts that make ng-boilerplate not just a though-through directory layout, but a real kickstarter for projects.


Ng-boilerplate uses Grunt, “The JavaScript Task Runner” as its build system. Grunt automates gathering all assets for distribution, compiling LESS into CSS, linting and minifying JavaScript sources, maintaining the right paths in templates, and running unit tests. It also knows not to include unit tests into production package, and to combine all your JavaScript code into a single file. All these things happen automatically when Grunt is watching your project directory. This is pretty awesome.

Configuration for Grunt is in Gruntfile.js, and custom scripts for it are in build/ directory.

An important advantage that an automatic build system and automatic test suite gives is the ability to build on Travis-CI. The code is automatically tested on multiple browsers as soon as it is pushed to github. If you are working on an open-source project, it’s a sin not to take advantage of this.

Testacular (or Karma)

The creators of AngularJS made their own, truly spectacular, system for running unit tests. I’ll talk about unit tests in more details a bit later. For now, I’ll just say that this is what testacular/ (or karma/) directory is for: test configuration.


The vendor/ folder contains libraries that are either foundational or necessary for the build processes to succeed. There is no automatic processing of anything in this directory during build process – if you wish to add a new library, you must add whatever logic is necessary to the Grunt build file. The documentation for this section contains an example of how to add jQuery to the vendor files.

Goodies: Bootstrap, Fonts, LESS

As a front-end developer, you are probably already familiar with these tools. We already use them in most projects – why not save time by making them part of the project template?

In the next part of the series, I’ll talk about automated testing with AngularJS, using the ng-boilerplate project template.

TL;DR (but really, read the whole three articles – it’s worth it)

  • Use ng-boilerplate as a template for your projects.
  • Learn to use unit-testing and end-to-end testing with Angular, and make it your religion. Use testacular/karma and Jasmine. It will save you months and years of development. Use end-to-end tests in addition to unit tests. Borrow test practices from good AngularJS applications.
  • Acquire new Angular habits, and avoid old habits that do not translate into AngularJS world.

Also see: AngularJS for jQuery Developers, I’ve Been Doing It Wrong (part 2)


Creative Commons License

This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.


  1. capaj

    Do you know Bower? If you do, I would like to hear your excuse why it was not included in this post…

    • Vlad Orlenko

      Thanks for the pointer capaj! I’ll check it out. For some reason, I have not used it before.

    • x

      ng-boilerplate is set up to use bower

  2. Lior

    thanks for this article. This definitely addresses the subject from a build/folder structure perspective.

    The biggest deficiency of Angular, in my view, for large scale MVC apps, is the lack of on-demand loading of Controller and Models. On the View front, [ui-router]( leads the way for dynamic loading – that’s why its such a great project. i’m trying to think how to address the M and C and whether it could be done within ui-router

    This, by the way, is related to the second biggest deficiency: server-side rendering. the new [Rendr]( project of backbone.js shows the need of bootstrapping from pre-rendered HTML. [connect-prerenderer]( shows a nice full-page-based bootstrapping idea, but for public facing sites, where some areas are personalized (i.e. login/Not Lior? link), we need the ability to load some directives on demand while keeping others bootstrapped from the html snapshot

    • Vlad Orlenko

      I am actually going to mention ui-router and angular-ui in the third part of the series. Thanks for the other two links!

    • benhschwartz

      when it comes to large scale web apps, ui-router does seem promising. Vlad: I’d be interested to hear your take on how mapping drag-and-drop reusable components into a state hierarchy might play out (e.g. sections in a portal that share a common ancestor state.)

      if you’re interested, my own evangelizing of ui-router:

      • Vlad Orlenko

        @benhschwartz, thanks for the ui-router article, I really enjoyed it.

        About drag-and-drop portal-like UI: you’re talking about reconfiguring routes on the fly, right? I haven’t really thought about this. Is it easy to modify routes and states at runtime? Does it cause bad side-effects?

      • Ben Schwartz (@benhschwartz)

        I meant drag-and-drop the way you used it earlier (modular component that doesn’t know how your application is going to use it.)

        What I’d like to see is the ability to encapsulate a feature/section of your application (including its associated state tree) in a module, but enable applying a state from your main application as the root for your future module.


        • Vlad Orlenko

          Encapsulate a module together with its routes? That’s a neat idea, sort of like Django apps have their own urls module.

    • Lior

      Thanks for the exact pointer! this is very good. I hope 2.0 will be here soon 🙂

  3. Patrick

    You said to use e2e tests religiously, but ng-boilerplate doesn’t support e2e tests yet.

  4. petedrinnan

    ng-boilerplate is a lifesaver! I’ve been looking for something like that for a week. Will use this at the next AngularJS meetup in Ottawa. Thx.

  5. Matt Alexander

    What’s the purpose of the Coding Horror logo being there?

  6. veeracs

    I also suggest having a common directory alongside the app directory (in the src directory), which has services, directives, filters, etc. that’ll be shared across all application components.

  7. Evgeniy OZ

    Your second variant looks more understandable and predictable in files navigation than last one.

  8. Mohammad

    Here is a pretty easy to use angular seed with a cleaner directory layout and modules loaded asynchronously with RequireJS. The most important part is, it loads controllers in a per-demand basis, meaning: there is no overhead in loading bunch of unnecessary controllers before you need. Definitely, give it a try.

  9. Gam Boi

    Is there any reason what so ever for using plural for folder names?
    Why controllers? controller sounds much more appropriate to me.


  10. aastudio

    Those great three articles should be nicely printable (which they aren’t :))

    • Bill Garrison

      Looks like 2 and 3 redirect to the home page…any ideas where i can find them now?

      • Brett g Porter

        Sorry — looks like things work okay now — try again?

  11. kannan

    Is there any limitations for number of lines in controller and function ..?

  12. Aravind

    Excellent piece of writing.
    I’m creating a foundation layer to scale my angular webapp and everything sits right inside a web2py framework.

    I’ve two concerns here :

    1) Is it safe to put the views inside the static folder which is kinda public folder?
    2) And ngbp is serving the html’s as javascript strings if I understood correctly. Can you please throw some lights about this? How much boost can we get out of this approach?


  1. AngularJS for jQuery Developers | Art & Logic Blog - [...] See also: I’ve Been Doing It Wrong! [...]
  2. AngularJS Best Practices: I’ve Been Doing It Wrong! Part 2 of 3 | Art & Logic Blog - [...] with AngularJS. The TL;DR version is at the end of the article. If you have not read the first…
  3. AngularJS Best Practices: I’ve Been Doing It Wrong! Part 3 of 3 | Art & Logic Blog - [...] The TL;DR version is at the end of the article. If you have not read the first two parts…
  4. AngularJS学习资源列表 | 天天三国杀 - […] AngularJS Best Practices: I’ve Been Doing It Wrong! (3 Part Series) […]
  5. AngularJS - Beginners guide / Yoosuf Muhammad - […] [AngularJS Best Practices: I’ve Been Doing It Wrong! (3 Part Series)] ( […]
  6. Structuring AngularJS Code | Parroty's Blog - […] AngularJS Best Practices: I’ve Been Doing It Wrong! Part 1 of 3 […]
  7. AngularJS Best Practices | Jony Zaman - […] Here it is: AngularJS Best Practices Article […]
  8. AngularJS best practices i’ve been doing it wrong. | 做人要豁達大道 - […] […]
  9. Learning AngularJS: Helpful Info Sources | .NET, Silverlight, and Prism - […] […]
  10. Useful AngularJS resources for beginners | ben powell | ben powell - […] AngularJS Best Practices: I’ve been doing it wrong! Part 1 of 3 is a guide to developing large-scale web…
  11. 2013: Greatest Hits | - […] AngularJS Best Practices: I’ve Been Doing It Wrong! Part 1 of 3 […]
  12. Fighting AngularJs | my / thoughts >> / dev / null - […] http://www.alproduction.local/blog/2013/05/ive-been-doing-it-wrong-part-1-of-3/ […]
  13. AngularJS | Pearltrees - […] AngularJS Best Practices: I’ve Been Doing It Wrong! Part 1 of 3 | […]
  14. Databases the SQL [see-kwuhl] - […] Doing Angular JS Right http://www.alproduction.local/blog/2013/05/ive-been-doing-it-wrong-part-1-of-3/ […]
  15. AngularJS | Pearltrees - […] order. This post is intended to be the first post to read when starting to learn AngularJS. AngularJS Best…
  16. Come scegliere il giusto framework javascript MVC? - […] http://www.alproduction.local/blog/2013/05/ive-been-doing-it-wrong-part-1-of-3/ http://www.alproduction.local/blog/2013/05/angularjs-best-practices-ive-been-doing-it-wrong-part-2-of-3/ http://www.alproduction.local/blog/2013/05/angularjs-best-practices-ive-been-doing-it-wrong-part-3-of-3/ […]