Co-authored-by: maria-rcks <maria@kuuro.net> Co-authored-by: Bilal Bakr <62337003+Bil0000@users.noreply.github.com> Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Vitalii Yehorov <vitalyiegorov@gmail.com> Co-authored-by: Jake Leventhal <jakeleventhal@me.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Alex Southwell <saphid@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Nicholas Wasmiller <derped@mineperial.com> Co-authored-by: PB <poilmb@gmail.com> Co-authored-by: Exotic <118054752+extoci@users.noreply.github.com> Co-authored-by: Yash Singh <saiansh2525@gmail.com> Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: Gabriel De Andrade <30420087+gabrielelpidio@users.noreply.github.com> Co-authored-by: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Co-authored-by: scratchyone <scratchywon@gmail.com> Co-authored-by: Dominic Roy <dominic@sdko.org> Co-authored-by: chukfinley <chuk@chuk.dev> Co-authored-by: Primož Ajdišek <bigpod@bigpod.si> Co-authored-by: benthecarman <benthecarman@live.com> Co-authored-by: NaveDanan <nave0712@gmail.com> Co-authored-by: aaditagrawal <103925638+aaditagrawal@users.noreply.github.com> Co-authored-by: Aditya Garud <153842990+yashranaway@users.noreply.github.com> Co-authored-by: Nick Anisimov <n.anisimov.23@gmail.com> Co-authored-by: MacKinley Smith <smithmackinley@gmail.com> Co-authored-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com> Co-authored-by: AKolenda <akole779@mtroyal.ca> Co-authored-by: Guillermo Casanova <75276669+Gigioxx@users.noreply.github.com> Co-authored-by: Otavio Salvador <otavio@ossystems.com.br> Co-authored-by: Shirish Pothi <183252392+shirishpothi@users.noreply.github.com> Co-authored-by: Ishaan Kothari <ishaanko.mail@gmail.com> Co-authored-by: Bob Fowler <bob@rjf.ca> Co-authored-by: Anton Bezdenezhnykh <gamer392@yandex.ru> Co-authored-by: ValeraZSD <48602572+ValeraZSD@users.noreply.github.com> Co-authored-by: Ephraim <ephraim39hr14m@gmail.com> Co-authored-by: Ryan Ilano <ryanilano@users.noreply.github.com> Co-authored-by: Alex <me@pixp.cc> Co-authored-by: maco <gosarmarcel7@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Tristan Knight <admin@snappeh.com> Co-authored-by: PR Batch Tester <agent@local.test> Co-authored-by: oliver <97427849+flamboh@users.noreply.github.com> Co-authored-by: kamkm <99585688+Kamkmgamer@users.noreply.github.com> Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
4.8 KiB
Open source license notices
License notices are generated independently for the client that ships them:
- The web build emits
third-party-licenses.jsonbesideindex.html. The Settings page loads that static file, so the same artifact works in hosted web, the client bundled withnpx t3, and desktop. - The mobile Metro config generates an ignored virtual module before each development, native, or over-the-air JavaScript bundle. Mobile loads and decodes that module only when a license screen opens, so the notice text does not occupy memory during ordinary app startup. It does not need a network request.
Neither path depends on the connected environment or an RPC.
What the build collects
The generator follows installed production and optional dependencies, including dependencies of
workspace packages, and omits first-party @t3tools/* packages. The web manifest starts from the
web, server, and desktop package manifests. The mobile manifest starts from the mobile package
manifest. During the web bundle, the generator also checks emitted module ids to catch a bundled
npm import missing from a package manifest.
The mobile manifest deliberately follows the complete production dependency closure declared by Expo and React Native. That is conservative and can include build tooling that is not present in the final JavaScript bundle, but it avoids dropping a notice when platform bundling changes.
The build fails when a collected package has no distributable license identifier or contains no
license or notice text. Generated notices use license templates from the pinned SPDX License List.
Strict web and EAS builds download a missing template into the gitignored .generated/ cache;
pnpm licenses:sync can warm that cache explicitly. Local web and Metro development do not make a
network request and omit generated rows until the cache exists. This keeps dev startup optional
while preventing incomplete release artifacts.
Custom notices and package overrides
The repository-level third-party-licenses.config.json holds manually maintained exceptions for
all clients. Add an entry to customNotices for adapted icons, fonts, media, native modules, or
another asset that did not come from an npm package:
{
"name": "asset-name",
"license": "CC-BY-4.0",
"generatedNotices": [
{
"licenseId": "CC-BY-4.0",
"preamble": ["Asset by Example Author. Changes: converted to MP3."]
}
],
"sourceUrl": "https://example.com/source",
"bundles": ["assets", "web"]
}
Each generatedNotices item names an SPDX license template and can add copyrights or a short
preamble for attribution and provenance. Multiple items are joined into one row for software
that vendors separately licensed code. Keep noticeFile or noticeFiles only when a vendored
source tree already carries an intrinsic license file that should remain beside it. Paths are
relative to the config file. bundles controls which generated manifests include the entry and
supplies the label shown to users. Use includeInBundles when those differ, such as an optional
server tool that should appear in both client manifests but is not bundled into either client.
Use packageOverrides only when an installed npm archive omits its notice or has incorrect
metadata:
{
"name": "package-name",
"version": "1.2.3",
"generatedNotice": {
"licenseId": "MIT",
"copyrights": ["Copyright (c) 2026 Example Author"]
},
"license": "MIT",
"sourceUrl": "https://example.com/package-name"
}
For packages containing separately licensed code, use generatedNotices with an array of templates instead of generatedNotice. The generator includes every notice in the package row.
version, license, and sourceUrl are optional. Omitting version applies the override to every
installed version of that package. An override can use repositoryUrl instead of name when
several packages from one monorepo share the same notice:
{
"repositoryUrl": "https://github.com/example/project",
"generatedNotice": {
"licenseId": "Apache-2.0"
}
}
The generator also reuses an installed sibling package's notice when both packages declare the same normalized repository and license. A name-and-version override always wins over these repository fallbacks.
The @react-grab/cli override uses the root React Grab repository's MIT license because the CLI's
npm archive omits both its license field and license file. Keep the override until the published
CLI package carries that metadata itself.
Generated mobile files live under apps/mobile/.generated/, while fetched SPDX templates live
under the repository .generated/ directory. Both are ignored. Do not commit or edit them;
updating dependencies or configuration is enough for the next strict build to refresh the output.