Import Exports Guide
Import/Export Strategy in NX Monorepos
๐ฆ Import/Export Strategy in NX Monorepos
This document explains the standardized index.ts pattern used across our NX workspace.
โ ๏ธ IMPORTANT: We have migrated from public-api.ts to index.ts for all libraries to maintain uniformity.
๐น index.ts - Two-Level Pattern
Level 1: Feature Folder Barrel Files
- Purpose: Local barrel file to re-export symbols inside a folder.
- Location: Inside feature folders (e.g.
services,models,adapters). - Usage:
// libs/storage-system/src/sync/services/index.ts export * from './sync.service'; export * from './cache.service';
Level 2: Library Root Entry Point
- Purpose: Public API file for external consumption.
- Location: At the root of the library (
src/index.ts). - Usage:
// libs/storage-system/src/index.ts export * from './sync/services'; export * from './core/models';
๐น Standard Pattern
| Use Case | File Type | Example Path |
|---|---|---|
| Feature re-exports | index.ts |
src/lib/services/index.ts |
| Library public API | index.ts |
src/index.ts |
๐น Best Practices
- Consistency: Always use
index.tsfor both feature folders and library root entry points. - Avoid Relative Paths: Never use
../../../libs/...- uselibs/...instead. - Type-Only Imports: Use
import typefor TypeScript types when possible. - Entry Point: All libraries use
src/index.tsas the entry point (nopublic-api.ts).
๐ฏ Example: Fixed Import in docs-angular
// Before (failing)
import type { LoadingOverlayConfig } from '@libs-foundational/core-models';
// After (working)
import type { LoadingOverlayConfig } from 'libs/core-models/src/lib/models/loading.types';
Consumers can then import:
import { SyncService } from '@storage-system';
โ Use index.ts freely in subfolders like models, services, or adapters to simplify imports.
3) Distinguishing Angular vs Non-Angular Libraries
Angular Libraries
Generated with @nx/angular:library.
Contain Angular decorators (@Component, @Injectable, @Directive, signals, etc.).
Have a project.json with @nx/angular:package or similar Angular build executor.
Include ng-package.json.
If the library depends on Angular runtime features โ it is an Angular library.
Root entry file: src/index.ts
Only what is exported here is visible externally.
Folder structure
libs/storage-system/ src/ angular/ services/ storage.service.ts index.ts signals/ storage.signal.ts index.ts index.ts ng-package.json project.json tsconfig.lib.json
### Example src/index.ts
```typescript
// libs/storage-system/src/index.ts
export * from './angular/services/storage.service';
export * from './angular/signals/storage.signal';
Correct ng-package.json for Angular libs
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/storage-system",
"lib": {
"entryFile": "src/index.ts"
}
}
Non-Angular Libraries (Plain TS)
Generated with @nx/js:library or manually.
Contain only TypeScript/utility code (no Angular decorators).
No Angular compilation required.
Do not need ng-package.json.
If the library is just TypeScript utilities โ it is a non-Angular library.
Root entry file: src/index.ts
// libs/storage-system/src/index.ts
export * from './sync/adapters/file.adapter';
export * from './sync/models/sync.model';
export * from './sync/services';
This acts as the package entry point.
Folder structure
libs/storage-system/
src/
sync/
adapters/
file.adapter.ts
models/
sync.model.ts
services/
sync.service.ts
index.ts
index.ts
project.json
tsconfig.lib.json
Example index.ts
// libs/storage-system/src/index.ts
export * from './sync/adapters/file.adapter';
export * from './sync/models/sync.model';
export * from './sync/services';
๐ง TypeScript Configuration Requirements
Angular Libraries
- tsconfig.lib.json must include:
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "../../dist/out-tsc", "declaration": true, "types": [], "skipLibCheck": true, "moduleResolution": "node", "allowSyntheticDefaultImports": true, "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true } }
Non-Angular Libraries
- tsconfig.lib.json must include:
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "../../dist/out-tsc", "declaration": true, "composite": true, "types": [], "target": "es2020", "lib": ["es2020", "dom"], "module": "esnext", "moduleResolution": "node", "allowSyntheticDefaultImports": true, "esModuleInterop": true, "skipLibCheck": true } }
๐จ Common Build Issues & Solutions
Issue 1: "Cannot find module '@storage-system'"
Cause: Missing path mappings in tsconfig.base.json
Solution: Add proper path mappings:
{
"compilerOptions": {
"paths": {
"@storage-system": ["libs/storage-system/src/index"],
"@storage-system/*": ["libs/storage-system/src/*"]
}
}
}
Issue 2: "Dynamic imports are only supported when the '--module' flag is set to 'es2020'"
Cause: TypeScript target is too old (ES5)
Solution: Update tsconfig.lib.json:
{
"compilerOptions": {
"target": "es2020",
"lib": ["es2020", "dom"],
"module": "esnext"
}
}
Issue 3: "Decorators are not valid here"
Cause: Missing decorator support
Solution: Add to tsconfig.lib.json:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Issue 4: "Entry point has a circular dependency on itself"
Cause: Library importing from itself Solution: Check imports - avoid circular dependencies by organizing code properly
Issue 5: "Cannot find module '@ux-portal'"
Cause: Missing dependency in project.json and package.json
Solution:
- Add to
project.json:
{
"implicitDependencies": ["ux-portal", "storage-system"]
}
- Add to
package.json:
{
"peerDependencies": {
"@ux-portal": "^1.0.0",
"@storage-system": "^1.0.0"
}
}
๐ Converting Libraries Between Types
Converting Non-Angular โ Angular Library
Update project.json:
{ "targets": { "build": { "executor": "@nx/angular:ng-packagr-lite", "options": { "project": "libs/my-library/ng-package.json" } } }, "tags": ["scope:my-scope", "type:angular"], "implicitDependencies": ["storage-system"] }Create ng-package.json:
{ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", "dest": "../../dist/libs/my-library", "lib": { "entryFile": "src/index.ts" } }Create src/index.ts:
export * from './lib/adapters'; export * from './lib/models'; export * from './lib/services';Update tsconfig.base.json path mapping:
{ "paths": { "@my-library": ["libs/my-library/src/index"] } }
๐ File Organization Best Practices
When to Move Files Between Libraries
- Angular Services/Components โ Move to Angular library
- Plain TypeScript Utilities โ Keep in non-Angular library
- Services using Angular Signals โ Must be in Angular library
Example: Moving outbox.service.ts
// Before: In non-Angular library
import { signal, computed } from '@angular/core'; // โ Error
// After: In storage-system (Angular-aware library)
import { signal, computed } from '@angular/core'; // โ
Works
๐งช Testing Build Issues
Debugging Steps
- Check dependencies:
nx graph - Clear cache:
nx reset - Build dependencies first:
nx build storage-system --skip-nx-cache - Check path mappings: Verify
tsconfig.base.json - Check file exports: Ensure
src/index.tsexports what you need
Temporary Workarounds
If you need to get a build working quickly:
Exclude problematic files in
tsconfig.lib.json:{ "exclude": [ "**/*.spec.ts", "src/lib/directives/**/*", "src/lib/firebase/**/*" ] }Comment out exports in
lib/index.ts:// export * from './directives'; // export * from './firebase'; export * from './services';
๐ฏ Summary
- index.ts โ Used for both local folder barrel files AND library root entry points
- Uniform standard โ All libraries (Angular and non-Angular) use
src/index.tsas entry point - Angular libs require ng-package.json configured with
"entryFile": "src/index.ts" - Non-Angular libs also use
src/index.tsas entry point - Always check TypeScript configuration for proper target, lib, and decorator support
- Update path mappings in tsconfig.base.json when adding new libraries
- Add dependencies to both project.json and package.json
- Use proper library types - Angular features belong in Angular libraries
- โ ๏ธ Legacy
public-api.tsfiles have been migrated - all libraries now useindex.ts
๐จ HISTORICAL NOTE: Nested Library Build Issues (October 2025)
โ Resolved: Storage Library Consolidation
Previous Issue:
Cannot find module '@ux-portal' or its corresponding type declarations.
Historical Context:
- We used to have nested storage libraries:
libs/storage/storage-angular,libs/storage/storage-core, etc. - Had cross-library Angular imports that caused build issues
- Using
@nx/angular:ng-packagr-liteexecutor couldn't resolve path aliases properly
Resolution (October 2025):
All storage libraries have been consolidated into a single libs/storage-system library, eliminating nested structure issues.
What theme-system does (also nested but works):
- Simpler dependency chains
- No cross-Angular library imports
- Or only imports from TypeScript libraries
โ Historical Solution (No Longer Needed)
Previous Workaround (Now Obsolete):
We used custom build scripts to work around nested library issues. This is no longer necessary with the consolidated storage-system library.
Current Approach (Simplified):
// โ
WORKS: Use unified storage-system library
import { StorageService, GgStorage, SyncChange, SyncCursor } from '@storage-system';
import { UxPortalService } from '@libs-ux/ux-portal';
// โ OLD (Don't use): Multiple storage libraries
import { UxPortalService } from 'libs/ux-portal/src/index';
import type { SyncChange } from 'libs/storage/storage-sync/src/index';
import type { GgStorage } from 'libs/storage/storage-core/src/index';
3. Simplify tsconfig.lib.json:
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"declaration": true,
"types": [],
"skipLibCheck": true
},
"angularCompilerOptions": {
"strictTemplates": true,
"fullTemplateTypeCheck": true
}
}
DO NOT override paths in library tsconfig - let it inherit from base.
Decision Matrix for Build Executors
| Scenario | Executor | Import Style | Notes |
|---|---|---|---|
| Simple Angular lib | @nx/angular:ng-packagr-lite |
Aliases (@lib) |
Standard case |
| Nested, no cross-Angular imports | @nx/angular:ng-packagr-lite |
Aliases (@lib) |
e.g., theme-system |
| Nested + cross-Angular imports | Custom build script | Direct paths | e.g., storage-angular |
| TypeScript lib (no Angular) | @nx/js:tsc |
Aliases (@lib) |
Standard case |
Affected Libraries
- โ
Fixed:
storage-angular(custom build + direct imports) - โ
Works:
theme-runtime,theme-styles,theme-dev-tools(ng-packagr) - โ ๏ธ Watch: Future nested libraries with Angular cross-imports
Testing the Fix
# Clean build
yarn nx reset
yarn nx build storage-angular
# Should complete successfully with:
โ
Building storage-angular with custom builder...
โ
Compiling TypeScript...
โ
Copying SCSS files...
โ
Successfully ran target build