Entry Points and Dependencies: How APF Actually Works In short: Secondary entry points are declared by an in a subfolder, and a published package has exactly one . If you have read that each entry point gets its own with its own , that advice does not work and this lesson explains why. A library is only as good as its installation experience. If importing a submit button drags a charting engine into an application's dependency tree, developers stop using the library. There are two separate mechanisms here, and they are constantly confused: entry points , which shape how consumers import, and dependency declarations , which shape what npm installs. Let's do them one at a time. Secondary entry points Angular's Package Format supports importing sub-paths of a package: APF is positive about this — its stated general rule is to use entry points for the smallest sets of logically connected code possible, and it points at Angular Material, which publishes each component separately. It also notes that not every library needs that granularity; a package with one coherent purpose is fine with a single entry point. How they are actually declared A secondary entry point is a folder containing an . That is the whole mechanism. Each secondary is two lines: finds these, builds each entry point, and generates the map in the single published : Look at where is. Once, at the root. The advice that does not work You will find guidance — including in the previous edition of this course — suggesting something like: The idea is appealing: scope the heavy dependency to the entry point that needs it, so consumers who only want the button never see . It does not work, for a reason that has nothing to do with Angular. npm resolves dependencies per published package, not per import path. When you run , npm reads exactly one — the one at the root of the tarball. There is no mechanism by which importing rather than changes what got installed. The install already happened, before anyone wrote an import. So a per-entry-point block is not scoped — it is ignored . Worse, treats a inside an entry point folder as a legacy configuration format and will warn or error on it depending on your version. You end up with a build warning and a dependency declaration that does nothing, which is the worst of both. If a dependency is genuinely optional, npm has an actual feature for it: Now consumers who never import can skip installing without a peer warning. That is the supported way to express "only needed for part of this package". What entry points do and do not buy you Since the dependency-scoping story turns out to be wrong, it is worth being precise about the real benefits. They do not primarily reduce bundle size. With a single entry point and ESM output, a bundler already drops the chart code from an application that only imports the button. That is what tree shaking is. Angular libraries ship as FESM2022 precisely so this works. What entry points genuinely give you: Benefit Why it matters --- --- Import paths that document structure says what you depend on A place to hang optional peer deps Pairs with Independent per area Smaller, clearer promises Better dependency-graph analysis CI can tell which apps use charts Insurance against imperfect tree shaking A side effect in one file cannot pull in the rest That last row is the honest version of the bundle-size argument. Tree shaking is very good but not perfect — a module with side effects at import time, or a with a decorator the bundler cannot prove is unused, can survive. Entry points mean the code was never in the graph at all. Set in your library to help the bundler along; it is the single highest-value line for tree shaking. Peer dependencies Angular's documentation is explicit: Angular libraries should list any dependencies as peer dependencies. The reason is concrete. If were a regular , npm could install a second copy nested under your library. Two copies of Angular means two dependency injection registries, two sets of framework metadata, and errors like for a service that is obviously provided. Peer dependencies say: use the application's copy. The rule generalises: Kind of dependency Where it goes Example --- --- --- Framework the app also uses , Needed only by one entry point + Small, private, no shared state a tiny formatting helper Build and test only , Keep close to empty. Every entry is something you have chosen on your consumers' behalf, and something they will have to audit when it gets a CVE. Wrapping third-party code Chapter 2 made the case for wrapping vendors at the edge. It applies doubly in a library, because your choice propagates to every consumer. Consumers write . Replace Lucide with inline SVG next year and it is a patch release, because never changed. "But I thought splitting entry points was how you keep bundles small" This is the standard justification, and it is not so much false as describing a problem your build system already solved . Walk through what actually…