licensegate

MIT attribution in a JavaScript bundle

Permissive doesn’t mean no conditions. MIT, ISC, BSD and Apache-2.0 all ask for one thing when you ship their code: keep the copyright notice and the licence text with it. A minified bundle usually loses both.

Install licensegate

This page explains how these licences are commonly read. It is not legal advice; for a product decision with money on it, ask a lawyer who handles open source.

What the permissive licences actually ask

Permissive licences let you use, change and sell the code, including in closed-source products. In return, most of them ask you to keep the author’s notices with every copy you hand out. The exact wording differs:

LicenceThe conditionWhat to ship
MIT“The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.”The copyright line and the licence text
ISCPermission is granted “provided that the above copyright notice and this permission notice appear in all copies.”The copyright line and the licence text
BSD-2-Clause, BSD-3-ClauseRedistributions in binary form must reproduce the copyright notice, the list of conditions and the disclaimer “in the documentation and/or other materials provided with the distribution.” BSD-3 also bars using the authors’ names to endorse your product without permission.The copyright line, conditions and disclaimer
Apache-2.0Section 4: give recipients a copy of the licence, keep the attribution notices, and if the package has a NOTICE file, include its attribution notices in a NOTICE file, in your documentation, or in a display where third-party notices normally appear. Files you modified must say that you changed them.The licence text, plus the contents of the package’s NOTICE file if it has one
0BSD, Unlicense, CC0-1.0No attribution conditionNothing required; listing them is still good practice

None of these licences says the notice must be on screen. They say it must be included or reproduced with what you distribute. That is why most apps solve it with one file, often called THIRD_PARTY_NOTICES.txt, shipped with the app or linked from an About or Legal page.

Why a bundle loses the notices

In node_modules, every package sits in its own folder with its LICENSE file next to the code. A bundler copies the code into your output and leaves the LICENSE files behind. A minifier then strips comments, which removes any licence header that was at the top of a file. What reaches the browser is often your code and theirs, with no notice left.

Bundlers try to keep some of it, but only what is marked:

  • webpack minifies with terser-webpack-plugin, which by default extracts comments matching @license, @preserve, @cc_on or starting with /*! into [file].LICENSE.txt, and removes the rest.
  • esbuild (also used by Vite) keeps legal comments: comments with @license or @preserve, or starting with //! or /*!. When bundling, the default moves them to the end of the file.

Both depend on the package author having put a marked header in the file you import. Many npm packages don’t: their licence lives only in the LICENSE file, which no bundler reads. So an extracted LICENSE.txt is a useful start, not a complete list.

Who needs to care

  • Browser apps and SPAs. The bundle is sent to every visitor, so it is a copy of the code reaching users.
  • Electron, React Native, Capacitor and on-prem builds. These are plainly distributed. App store reviews and enterprise customers often ask for an acknowledgements screen.
  • Libraries that bundle dependencies into their published dist file. The people installing your package receive the bundled code too.
  • Server-only code in a SaaS usually doesn’t trigger these conditions, because nothing is handed over. The AGPL is the exception that reaches network use.

A notices file that holds up

  1. One entry per production package that ends up in what you ship, with name and version.
  2. The package’s copyright line and full licence text, taken from its own LICENSE file rather than retyped.
  3. For Apache-2.0 packages, the contents of their NOTICE file when there is one.
  4. Regenerated on every release, so a dependency added last week is in it.
  5. Reachable by users: served next to the bundle, linked from the footer or About screen, or packaged with the installer.

Build it from your lockfile

npm ci
npx -y https://licensegate.org/dl/licensegate.tgz --mode distributed --prod --notices THIRD_PARTY_NOTICES.txt

--notices writes one entry per production dependency, transitive ones included, with its version, its licence id and the text of the LICENSE or COPYING file found in its folder, followed by its NOTICE file if it has one under node_modules, so run it after the install. --prod leaves out devDependencies such as test runners and build tools, which don’t ship. The same run checks every licence against how you ship, so a GPL package in a desktop app fails the job instead of quietly landing in the notices file.

For an Apache-2.0 package that ships both LICENSE and NOTICE, the entry carries both texts, licence first, as section 4(d) asks (since licensegate 0.4.1). One thing to check by hand: an entry with only a License: line means the package has no licence file, so look up its repository for the copyright line.

In CI, on every release

- run: npm ci
- run: npx -y https://licensegate.org/dl/licensegate.tgz --mode distributed --prod --notices public/THIRD_PARTY_NOTICES.txt

Writing it into public/ (or your framework’s static folder) serves it at a stable URL next to the app. For a browser app on your own servers, --mode saas fits the licence check better; the notices file is the same. If a client or buyer wants proof of what was in the build on a given date, a sealed report covers the same inventory.