Ban External Imports

This constraint is only available for projects using ESLint.

You may want to constrain what external packages a project may import. For example, you may want to prevent backend projects from importing packages related to your frontend framework. You can ban these imports using bannedExternalImports property in your dependency constraints configuration.

A common example of this is for backend projects that use NestJS and frontend projects that use Angular. Both frameworks contain a class named Injectable. It's very easy for a developer to import the wrong one by mistake, especially when using auto-import in an IDE. To prevent this, add tags to define the type of project to distinguish between backend and frontend projects. Each tag should define its own list of banned external imports.

.eslintrc.json
1{ 2 // ... more ESLint config here 3 4 // @nx/enforce-module-boundaries should already exist at the top-level of your config 5 "@nx/enforce-module-boundaries": [ 6 "error", 7 { 8 "allow": [], 9 // update depConstraints based on your tags 10 "depConstraints": [ 11 // projects tagged with "frontend" can't import from "@nestjs/common" 12 { 13 "sourceTag": "frontend", 14 "bannedExternalImports": ["@nestjs/common"] 15 }, 16 // projects tagged with "backend" can't import from "@angular/core" 17 { 18 "sourceTag": "backend", 19 "bannedExternalImports": ["@angular/core"] 20 } 21 ] 22 } 23 ] 24 25 // ... more ESLint config here 26} 27

Another common example is ensuring that util libraries stay framework-free by banning imports from these frameworks. You can use wildcard * to match multiple projects e.g. react* would match react, but also react-dom, react-native etc. You can also have multiple wildcards e.g. *react* would match any package with word react in it's name. A workspace using React would have a configuration like this.

.eslintrc.json
1{ 2 // ... more ESLint config here 3 // @nx/enforce-module-boundaries should already exist at the top-level of your config 4 "@nx/enforce-module-boundaries": [ 5 "error", 6 { 7 "allow": [], 8 // update depConstraints based on your tags 9 "depConstraints": [ 10 // projects tagged with "type:util" can't import from "react" or related projects 11 { 12 "sourceTag": "type:util", 13 "bannedExternalImports": ["*react*"] 14 } 15 ] 16 } 17 ] 18 19 // ... more ESLint config here 20} 21

Whitelisting external imports with allowedExternalImports

If you need a more restrictive approach, you can use the allowedExternalImports option to ensure that a project only imports from a specific set of packages. This is useful if you want to enforce separation of concerns (e.g. keeping your domain logic clean from infrastructure concerns, or ui libraries clean from data access concerns) or keep some parts of your codebase framework-free or library-free.

.eslintrc.json
1{ 2 // ... more ESLint config here 3 4 // @nx/enforce-module-boundaries should already exist at the top-level of your config 5 "@nx/enforce-module-boundaries": [ 6 "error", 7 { 8 "allow": [], 9 // update depConstraints based on your tags 10 "depConstraints": [ 11 // limiting the dependencies of util libraries to the bare minimum 12 // projects tagged with "type:util" can only import from "date-fns" 13 { 14 "sourceTag": "type:util", 15 "allowedExternalImports": ["date-fns"] 16 }, 17 // ui libraries clean from data access concerns 18 // projects tagged with "type:ui" can only import pacages matching "@angular/*" except "@angular/common/http" 19 { 20 "sourceTag": "type:ui", 21 "allowedExternalImports": ["@angular/*"], 22 "bannedExternalImports": ["@angular/common/http"] 23 }, 24 // keeping the domain logic clean from infrastructure concerns 25 // projects tagged with "type:core" can't import any external packages. 26 { 27 "sourceTag": "type:core", 28 "allowedExternalImports": [] 29 } 30 ] 31 } 32 ] 33