{"id":17644544,"url":"https://github.com/wesleygrimes/angular-routing-best-practices","last_synced_at":"2025-08-09T21:13:38.470Z","repository":{"id":38793625,"uuid":"172571814","full_name":"wesleygrimes/angular-routing-best-practices","owner":"wesleygrimes","description":"Angular Routing - Best Practices for Enterprise Applications","archived":false,"fork":false,"pushed_at":"2023-01-07T03:22:08.000Z","size":1745,"stargazers_count":42,"open_issues_count":30,"forks_count":14,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-30T17:44:42.417Z","etag":null,"topics":["angular","best-practices","routing","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wesleygrimes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-25T19:36:40.000Z","updated_at":"2025-03-05T20:40:40.000Z","dependencies_parsed_at":"2022-09-17T13:51:29.894Z","dependency_job_id":null,"html_url":"https://github.com/wesleygrimes/angular-routing-best-practices","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wesleygrimes%2Fangular-routing-best-practices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wesleygrimes%2Fangular-routing-best-practices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wesleygrimes%2Fangular-routing-best-practices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wesleygrimes%2Fangular-routing-best-practices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wesleygrimes","download_url":"https://codeload.github.com/wesleygrimes/angular-routing-best-practices/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251738209,"owners_count":21635773,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","best-practices","routing","typescript"],"created_at":"2024-10-23T10:06:52.272Z","updated_at":"2025-04-30T16:02:01.209Z","avatar_url":"https://github.com/wesleygrimes.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://ultimatecourses.com/topic/angular/ref/wes.grimes/\" title=\"Ultimate Courses\"\u003e\u003cimg src=\"https://ultimatecourses.com/assets/img/banners/ultimate-angular-github.svg\" alt=\"Ultimate Courses\" /\u003e\u003c/a\u003e\n\n![](https://wesleygrimes.com/assets/post_headers/routing.jpg)\n\n## Before We Get Started\n\nThis article is not intended to be a tutorial on routing in Angular. If you are new to Routing in Angular then I highly recommend you check out one of the the following resources:\n\n- [Ultimate Courses](https://bit.ly/2WubqhW)\n- [Official Angular Docs](https://angular.io/guide/router)\n\n## Background\n\nThe following represents a pattern that I've developed at my day job after building several enterprise Angular applications. While most online tutorials do a great job laying out the fundamentals, I had a hard time locating articles that showed recommended conventions and patterns for large and scalable applications.\n\nWith this pattern you should have a clean and concise organization for all routing related concerns in your applications.\n\n## Prerequisites\n\nFor context, this article assumes you are using the following version of Angular:\n\n- Angular v7.2.6\n\n---\n\n## Best Practice #1 - Create a top-level Routes array file\n\n\u003e The official [Angular docs recommend](https://angular.io/guide/router#refactor-the-routing-configuration-into-a-routing-module) creating a full-blown `app-routing.module.ts` for your top-level routing. I have found this extra layer to be unnecessary in most cases.\n\n\u003e HOT TIP: Only register top-level routes here, if you plan to implement feature modules, then the child routes would live underneath the respective `feature.routes.ts` file. We want to keep this top-level routes file as clean as possible and follow the component tree structure.\n\nLet's go with the following approach:\n\n1. Create a new file named `app.routes.ts` in the root `src/app` directory. This file will hold our top-level `Routes` array. We will come back later throughout the article and fill this in. For now, let's scaffold it with the following contents:\n\n   ```typescript\n   import { Routes } from '@angular/router';\n\n   export const AppRoutes: Routes = [];\n   ```\n\n2. Register `AppRoutes` in the `app.module.ts` file.\n\n   - Import `AppRoutes` from `app.routes.ts`.\n   - Import `RouterModule` from `@angular/router`.\n   - Add `RouterModule.forRoot(AppRoutes)` to your `imports` array\n\n   Your updated `app.module.ts` will look similar to the following:\n\n   ```typescript\n   import { NgModule } from '@angular/core';\n   import { BrowserModule } from '@angular/platform-browser';\n   import { RouterModule } from '@angular/router';\n   import { AppComponent } from './app.component';\n   import { AppRoutes } from './app.routes';\n\n   @NgModule({\n     declarations: [AppComponent],\n     imports: [BrowserModule, RouterModule.forRoot(AppRoutes)],\n     providers: [],\n     bootstrap: [AppComponent]\n   })\n   export class AppModule {}\n   ```\n\n## Best Practice #2 - Create a feature-level Routes array file\n\nIn similar fashion to how we constructed the `app.routes.ts` we will create a `feature.routes.ts` to list out the individual routes for this feature module. We want to keep our routes as close to the source as possible. This will be in keeping with a clean code approach, and having a good separation of concerns.\n\n1. Create a new file named `feature/feature.routes.ts` where `feature` matches the name of your `feature.module.ts` prefix. This file will hold our feature-level `Routes` array. Keeping in mind that you would replace `Feature` with the actual name of your module, let's scaffold it with the following contents:\n\n   ```typescript\n   import { Routes } from '@angular/router';\n\n   export const FeatureRoutes: Routes = [];\n   ```\n\n2. Register `FeatureRoutes` in the `feature/feature.module.ts` file. We will make use of the `RouterModule.forChild` import so that these routes are automatically registered with lazy loading.\n\n   - Import `FeatureRoutes` from `feature.routes.ts`.\n   - Import `RouterModule` from `@angular/router`.\n   - Add `RouterModule.forChild(FeatureRoutes)` to your `imports` array\n\n   Your updated `feature/feature.module.ts` will look similar to the following:\n\n   ```typescript\n   import { CommonModule } from '@angular/common';\n   import { NgModule } from '@angular/core';\n   import { RouterModule } from '@angular/router';\n   import { FeatureRoutes } from './feature.routes';\n\n   @NgModule({\n     declarations: [],\n     imports: [CommonModule, RouterModule.forChild(FeatureRoutes)]\n   })\n   export class FeatureModule {}\n   ```\n\n   An example of a `feature.routes.ts` file with child route(s) may look like the following:\n\n   ```typescript\n   import { Routes } from '@angular/router';\n   import { FeatureOneComponent } from './feature-one.component';\n   import { FeatureSpecificCanActivateGuard } from './_guards';\n\n   export const FeatureOneRoutes: Routes = [\n     {\n       path: '',\n       pathMatch: 'full',\n       redirectTo: 'feature-one-component'\n     },\n     {\n       path: 'feature-one-component',\n       component: FeatureOneComponent,\n       canActivate: [FeatureSpecificCanActivateGuard]\n     }\n   ];\n   ```\n\n## Best Practice #3 - Add Lazy Loaded Features to top-level Routes file\n\n\u003e Lazy loading is the concept of deferring load of code assets (javascript, styles) until the user actually needs to utilize the resources. This can bring large performance increases to perceived load times of your application as the entire code set doesn't have to download on first paint.\n\n\u003e Angular provides a nice way to handle this with the `loadChildren` option for a given route. More information can be found in the [official Angular docs](https://angular.io/guide/router#lazy-loading-route-configuration).\n\nOnce you've created your `app.routes.ts` and `*.routes.ts` files, you need to register any feature modules that you want to load lazily.\n\n### Per Feature Module...\n\nUpdate the `AppRoutes` array in the `app.routes.ts` file to include a new route the feature:\n\n```typescript\nimport { Routes } from '@angular/router';\n\nexport const AppRoutes: Routes = [\n  {\n    path: 'feature',\n    loadChildren: './feature/feature.module#FeatureModule'\n  }\n];\n```\n\nBy adding the above route to the array, when the user requests `/feature` in the browser, Angular lazy loads the module using the path given and then automatically registers any routes defined in the `feature.routes.ts` `FeatureRoutes` array using the `RouterModule.forChild` import.\n\nFor each additional feature module, you would add another item to the `AppRoutes` array. If you have multiple features, it might look something like the following:\n\n```typescript\nimport { Routes } from '@angular/router';\n\nexport const AppRoutes: Routes = [\n  {\n    path: '',\n    pathMatch: 'full',\n    redirectTo: 'feature-one'\n  },\n  {\n    path: 'feature-one',\n    loadChildren: './feature-one/feature-one.module#FeatureOneModule'\n  },\n  {\n    path: 'feature-two',\n    loadChildren: './feature-two/feature-two.module#FeatureTwoModule'\n  }\n];\n```\n\n## Best Practice #4 - Keep Router Guards Organized\n\nHere are a few tips to keep your router guards organized. These are just guidelines, but I have found them to be very helpful.\n\n### Name Your Guards Well\n\nGuards should use the following naming convention:\n\n- File Name: `name.function.guard.ts`\n- Class Name: `NameFunctionGuard`\n\nEach part being identified as:\n\n- `name` - this is the name of your guard. What are you guarding against?\n- `function` - this is the function your guard will be attached to. Angular supports `CanActivate`, `CanActivateChild`, `CanDeactivate`, and `Resolve`.\n\nAn example of an Auth Guard that is attached to the `CanActivate` function would be named as follows:\n\n- File Name: `auth.can-activate.guard`\n- Class Name: `AuthCanActivateGuard`\n\n### Group under `_guards` folder\n\nOrganize all top-level guards under a folder named `src/app/_guards`. I have seen apps dump guards in the top level directory and this is messy, especially if you end up with more than a few guards.\n\n### Use Barrel Exports\n\n\u003e The jury is still out on whether or not using barrel exports is officially considered a \"best practice\" or even supported by the Angular style guide. However, I am a big fan of the clean organization this provides. This method is offered as a suggestion.\n\nMake sure that `src/app/_guards` has a nice and clean `index.ts` barrel export. Barrel exports are simply `index.ts` files that group together and export all public files from a directory. An example is as follows:\n\n```typescript\nexport * from './auth.can-activate.guard';\nexport * from './require-save.can-deactivate.guard';\n```\n\nWithout Barrel Exporting:\n\n```typescript\nimport { AuthCanActivateGuard } from 'src/app/_guards/auth.can-activate.guard';\nimport { RequireSaveCanDeactivateGuard } from 'src/app/_guards/require-save.can-deactivate.guard';\n```\n\nWith Barrel Exporting:\n\n```typescript\nimport {\n  AuthCanActivateGuard,\n  RequireSaveCanDeactivateGuard\n} from 'src/app/_guards';\n```\n\nAn example application with a `_guards` directory would look as follows:\n\n![](https://wesleygrimes.com/assets/post_headers/routing_directory.png)\n\n### Organize Feature-Specific Route Guards\n\nIf you have guards that are _only_ used in a particular `FeatureRoutes` array, then store these routes underneath a folder named `_guards` underneath your feature folder. Make sure to follow the same naming conventions defined above, as well as barrel exporting.\n\n- Place guards under a folder named `_guards` underneath your feature folder\n- Make sure to create a barrel export `index.ts` for clean importing\n\nAn example feature directory with `_guards` would look as follows:\n\n![](https://wesleygrimes.com/assets/post_headers/routing_feature_directory.png)\n\n## Finished Application Structure\n\nA completed application structure should look something like the following:\n\n![](https://wesleygrimes.com/assets/post_headers/routing_completed_structure.png)\n\n---\n\n## Example GitHub Repository\n\nI have created a demonstration repository on GitHub. Feel free to fork, clone, and submit PRs.\n\n[https://github.com/wesleygrimes/angular-routing-best-practices](https://github.com/wesleygrimes/angular-routing-best-practices)\n\n## Conclusion\n\nIt's important to remember that I have implemented these best practices in several \"real world\" applications. While I have found these best practices helpful, and maintainable, I do not believe they are an end-all be-all solution to organizing routes in projects; it's just what has worked for me. I am curious as to what you all think? Please feel free to offer any suggestions, tips, or best practices you've learned when building enterprise Angular applications with routing and I will update the article to reflect as such. Happy Coding!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwesleygrimes%2Fangular-routing-best-practices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwesleygrimes%2Fangular-routing-best-practices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwesleygrimes%2Fangular-routing-best-practices/lists"}