skip to content

With the Angular CLI, what does `ng generate library` add to a workspace, and what must happen before an app in that workspace can import it?

level: juniorimportance: must knowfreq 55%

answer

  1. a second project, not a folder
  2. a different builder for build
  3. ng-package.json and public-api.ts
  4. tsconfig paths point at dist

basics

~20 s

ng generate library adds a library project under projects/ with its own ng-packagr build target, ng-package.json, package.json and public-api.ts, and maps the library name to dist/<name> in tsconfig paths. Apps import the built output, so build the library first.

solid answer

~40 s

`ng generate library ui-kit` (alias `ng g lib`) creates `projects/ui-kit` and registers it in `angular.json` with `projectType: "library"` and a `build` target on `@angular/build:ng-packagr`, whose `defaultConfiguration` is `production`. The folder gets `ng-package.json` (output `dest` and `lib.entryFile`), a `package.json` declaring `@angular/core` and `@angular/common` as `peerDependencies`, `tsconfig.lib.json` plus `tsconfig.lib.prod.json`, and `src/public-api.ts` exporting a starter standalone component. It also adds `ng-packagr` as a dev dependency and a path mapping `"ui-kit": ["./dist/ui-kit"]` to the root `tsconfig.json`. That mapping points at the build output, not the source, so an app can only `import { UiKit } from 'ui-kit'` after `ng build ui-kit` has run; during development `ng build ui-kit --watch` keeps the output fresh.

code

bash · 3 lines
bash
ng generate library ui-kit
ng build ui-kit --watch
ng serve

go deeper

for a junior

Recall that ng g lib creates a separate project with its own build, and that the app imports the built dist output by package name.

for a middle

Explain the files it writes, the ng-packagr builder, the production default configuration and why the tsconfig mapping targets dist rather than source.

for a senior

Show you have run a multi-project workspace: the watch-build workflow, fresh-clone errors, and why mapping to source hides bugs consumers would hit.

for a principal

Weigh a workspace library against a separately published package: release coupling, versioning and who owns breaking changes.

## What the schematic adds `ng generate library <name>` (short form `ng g lib <name>`) runs the Angular CLI's **library schematic**. It does not create a folder of shared files inside your application; it creates a **second project** in the same workspace, with its own build, test and output. By default the project lands under the workspace's `newProjectRoot`, which is `projects` in a workspace created by `ng new`. For `ng g lib ui-kit` you get: | Path | Purpose | |---|---| | `projects/ui-kit/ng-package.json` | ng-packagr's configuration: the output folder (`dest`) and the entry file (`lib.entryFile`) | | `projects/ui-kit/package.json` | the package manifest that ships: name, version, `peerDependencies` on `@angular/core` and `@angular/common`, `tslib` as a dependency | | `projects/ui-kit/src/public-api.ts` | the public surface: everything consumers may import | | `projects/ui-kit/src/lib/ui-kit.ts` | a starter standalone component with the `lib` selector prefix | | `projects/ui-kit/tsconfig.lib.json` | TypeScript settings for development builds | | `projects/ui-kit/tsconfig.lib.prod.json` | the production override, which sets `compilationMode: "partial"` | | `projects/ui-kit/tsconfig.spec.json` | settings for the library's unit tests | ## The workspace entry The schematic also edits `angular.json`. The new project has `projectType: "library"` and a `build` target that uses **`@angular/build:ng-packagr`**, not the `@angular/build:application` builder an app uses. Its `defaultConfiguration` is `production`, which points the builder at `tsconfig.lib.prod.json`; a `development` configuration points at `tsconfig.lib.json`. A `test` target is added too, using the unit-test builder with Vitest by default in CLI 22. Outside the project folder it: - adds `ng-packagr`, `@angular/compiler-cli`, `@angular/build` and `typescript` as dev dependencies if they are missing; - adds a **path mapping** to the root `tsconfig.json`: `"ui-kit": ["./dist/ui-kit"]`; - adds project references to the library's `tsconfig.lib.json` and `tsconfig.spec.json`. ## How an application finds the library An app in the same workspace imports the library by its package name, exactly as it would after an `npm install`: ```ts import { Component } from '@angular/core'; import { UiKit } from 'ui-kit'; @Component({ selector: 'app-root', imports: [UiKit], template: `<lib-ui-kit />`, }) export class App {} ``` That import resolves through the `tsconfig` path mapping, and the mapping points at **`dist/ui-kit`, the build output**. So the order matters: 1. `ng build ui-kit` builds the library into `dist/ui-kit` (in production mode, because of `defaultConfiguration`). 2. `ng serve` or `ng build` for the app then resolves `ui-kit` to that folder. 3. While you edit both at once, run `ng build ui-kit --watch` in a second terminal so each change is rebuilt incrementally. On a fresh clone, an editor shows `ui-kit` imports as missing until the library has been built once. That is expected, not a broken install. ## Why the mapping points at dist, not at the source The application builder and ng-packagr are **different build pipelines**. The Angular documentation is explicit that the same TypeScript can produce different JavaScript in a built library than in a built application, and that an app should only map to the **built library**, never to the library's `.ts` source. Pointing paths at `projects/ui-kit/src` would compile the library as if it were app code: it would hide mistakes that consumers of the published package would hit, such as a symbol that `public-api.ts` forgot to export. ## Options worth knowing | Option | Default | Effect | |---|---|---| | `--prefix` | `lib` | selector prefix for components generated in the library | | `--entry-file` | `public-api` | name of the public API file | | `--standalone` | `true` | `false` also generates an NgModule and exports it | | `--skip-ts-config` | `false` | skip the root path mapping | | `--project-root` | under `projects/` | put the library somewhere else | | `--test-runner` | `vitest` | `karma` for the older runner | The documentation also shows that a library-only workspace can start from `ng new my-workspace --no-create-application`, and warns against an `ng-` name prefix, which Angular reserves; `ngx-` is the community convention. ## Common mistakes - Importing from `projects/ui-kit/src/...` with a relative path instead of the package name. - Expecting `ng serve` for the app to build the library; it does not. - Deleting the `tsconfig` mapping and wondering why the name no longer resolves.

  • Why does the generated build target default to the production configuration?
    `defaultConfiguration: "production"` makes a plain `ng build ui-kit` use `tsconfig.lib.prod.json`, which sets `compilationMode: "partial"` and drops declaration maps. That is the output you publish. `--configuration development` uses `tsconfig.lib.json` and a full compilation, which is fine inside the workspace but not for publishing.
  • Your app's `ng serve` reports that it cannot find module 'ui-kit' right after a fresh clone; what is wrong?
    Usually nothing is misconfigured: the path mapping points at `dist/ui-kit`, and `dist` is not committed. Run `ng build ui-kit` once (or with `--watch`) before serving the app. If it still fails, check that the root `tsconfig.json` still carries the mapping and that `dest` in `ng-package.json` matches it.
  • How would you name a library you plan to publish to a public registry?
    Avoid an `ng-` prefix, which the Angular documentation reserves for the framework's own packages; the `ngx-` prefix is the convention for Angular-specific libraries. A scoped name such as `@acme/ui-kit` also works: the schematic then creates `projects/acme/ui-kit`, outputs to `dist/acme/ui-kit` and maps `@acme/ui-kit` in `tsconfig`.

saying these in an interview costs you the question

  • A library is just a shared folder the app compiles as its own source.
  • ng serve for the app builds the library automatically.
  • The tsconfig path mapping should point at the library's src folder.
  • Libraries use the same application builder as apps.
  • An import error after cloning means the library was generated incorrectly.