Dependencies
Learn what the 81 runtime dependencies and 26 dev dependencies do, why zsa is patched, and how knip.json and check-unused-deps.ts keep the list from growing dead entries.
package.json declares 81 runtime dependencies and 26 dev dependencies, installed with Bun 1.2.2 (packageManager).
This page groups them by the job they do and names the real versions.
Two guards stop the list rotting. scripts/check-unused-deps.ts fails on a new runtime dependency nothing imports, and knip.json configures a broader unused export and file scan.
Framework and runtime
| Package | Declared version | What it does |
|---|---|---|
next | ^16.1.1 | App Router, route handlers, next build |
react / react-dom | ^19.2.3 | React 19 |
typescript | ^5.9.3 | dev only; tsc --noEmit is the typecheck |
@t3-oss/env-nextjs | ^0.13.10 | typed env parsing in env.ts |
server-only | ^0.0.1 | the marker check-client-bundle-server-only.ts traverses to |
@sentry/nextjs | ^10.40.0 | error reporting |
Database
Prisma is pinned to an exact version across three packages:
@prisma/client 7.4.2
@prisma/adapter-pg 7.4.2
prisma 7.4.2There is no caret on any of them, so a minor release cannot drift the client away from the engine.
Between them they cover the schema, the migrations and the driver adapter over pg.
decimal.js-light (^2.5.1) is the decimal arithmetic behind ~/utils/money.
@types/pg (^8.16.0) supplies types for the adapter's driver.
One inconsistency is worth knowing about. The db:seed script is:
tsx prisma/seed.tstsx is not declared in package.json — it resolves from the environment. The prisma.seed entry in the same file uses:
bun prisma/seed.tsThe two paths to the seed disagree on the runner.
Commerce and payments
stripe (^20.3.1) covers checkout sessions, payment intents and webhook signature verification.
svix (^1.96.1) signs outbound webhooks, and jose (^6.1.3) signs and verifies JWTs.
better-auth (^1.4.19) owns sessions, sign-in and account records.
@upstash/redis (^1.36.0) and @upstash/ratelimit (^2.0.7) are the cache and the rate limiter. checkRateLimit fails open when Redis is unreachable, so an outage does not block sign-in.
AI
The AI layer is on the AI SDK 4 line, with three providers wired and selectable:
ai ^4.3.19
@ai-sdk/react ^1.2.12
@ai-sdk/openai ^1.3.24
@ai-sdk/anthropic ^1.2.12
@ai-sdk/google ^1.2.22
streamdown ^2.3.0
use-stick-to-bottom ^1.1.3streamdown renders streamed markdown; use-stick-to-bottom handles chat scroll anchoring.
UI
Primitives come from radix-ui (^1.4.3), plus two separately versioned packages: @radix-ui/react-collapsible (^1.1.12) and @radix-ui/react-tabs (^1.1.13).
Styling is tailwindcss (^4.1.18, dev) with @tailwindcss/postcss, @tailwindcss/typography and tailwindcss-animate. cva and tailwind-merge (^3.4.0) back cx in ~/utils/cva.
Icons are lucide-react (^0.575.0), compiled into a sprite by scripts/build-icons.ts. Application code imports <Icon />, never lucide-react directly, and the icon-imports discipline rule enforces that.
Tables and forms:
@tanstack/react-table(^8.21.3)react-hook-form(^7.70.0)@hookform/resolvers(^3.10.0)zod(^4.3.5)
The rich-text editor is TipTap 3, which arrives as six packages:
@tiptap/react
@tiptap/starter-kit
@tiptap/pm
@tiptap/extension-image
@tiptap/extension-link
@tiptap/markdownThe other inputs are react-day-picker (^9.13.0), react-colorful, react-phone-number-input, react-dropzone and cmdk.
Motion and charts:
motion(^12.38.0)recharts(^3.6.0)@number-flow/reactcanvas-confettiembla-carousel-react
Drag and drop is @atlaskit/pragmatic-drag-and-drop (^1.7.7) and its hitbox package.
State and URL handling:
nuqs(^2.8.6) for search-param stateswr(^2.3.8) for client fetchingzsa(^0.6.0) andzsa-reactfor server actionssonner(^2.0.7) for toastsnext-themes@mantine/hooks
One entry is not a version range at all: cva is declared as "beta", a dist-tag, so it resolves to whatever the current beta is at install time.
Content, email and media
@content-collections/core, /mdx and /next compile MDX content at build time, with rehype-slug and rehype-autolink-headings in the pipeline.
@react-email/components (^1.0.3) and resend (^6.9.2) are the email templates in emails/ and their delivery. react-email (dev) runs the preview server behind bun run email.
@aws-sdk/client-s3 and @aws-sdk/lib-storage (^3.962.0) provide S3-compatible object storage.
satori (^0.13.2) renders OG images, paired with loadGoogleFont in config/fonts.ts.
sanitize-html (^2.17.5) sanitises HTML and rss (^1.2.2) generates the feeds.
Background work and analytics
inngest(^3.54.0) — crons and domain-event handlers infunctions/@orpc/server/@orpc/shared(^1.13.9) — the narrow/api/rpcsurfaceposthog-js(^1.314.0) — client analytics@atproto/api(^0.15.27) — Bluesky posting for the social modulewretch(^3.0.6) — the HTTP client for outbound integration calls
Utilities
The general-purpose helpers are:
date-fns(^4.1.0)change-casenanoid(^3.3.11)plur@primoui/utils
The no-primoui-formatters discipline rule keeps @primoui/utils out of formatting work that belongs to lib/formatters.ts.
Tooling
@biomejs/biome (^1.9.4) is the formatter and linter.
vitest (^4.0.18) runs the tests, with jsdom (^29.1.1) and vite (^7.3.1).
lefthook (^1.7.0) installs the git hooks, and knip (^5.64.4) is the unused-code scanner.
The remaining dev dependencies support the scripts and the build:
globfs-extranode-html-parserdotenvschema-dtspostcss
The zsa patch
One dependency is patched:
"patchedDependencies": {
"zsa@0.6.0": "patches/zsa@0.6.0.patch"
}patches/ contains that single file.
The reason is a version mismatch in the type definitions: zsa 0.6.0 ships types written against zod 3, and the repository runs zod 4.
The patch rewrites dist/index.d.ts to declare local AnyZodObject and objectUtil.extendShape shims, and to drop the zod-3-only generic parameters from TZodMerge and the instanceofZodType* helpers.
It is a types-only change — no runtime behaviour is altered. Bun applies it on install.
Guarding against unused dependencies
scripts/check-unused-deps.ts runs as bun run lint:deps inside the lint:cleanliness aggregate.
It greps every .ts, .tsx, .mjs and .js file for import specifiers, reduces each to its top-level package name, and compares that set against package.json dependencies. Dev dependencies are out of scope.
Packages consumed by configuration rather than by an import are allowlisted in the script itself:
const ALLOWLIST = [
/^@types\//,
/^tailwindcss$/,
/^postcss/,
/^autoprefixer$/,
/^sharp$/, // next/image runtime
/^@tiptap\/pm$/, // ProseMirror core — required peer of @tiptap/react, imported transitively
]scripts/unused-deps-baseline.txt does not exist in the repository, and the script treats a missing baseline as an empty one.
The check therefore runs at zero tolerance today: every runtime dependency is imported somewhere, and adding one that is not fails the build immediately.
The wider knip scan
knip.json configures bun run lint:knip. Its entry points are:
- the Next.js route conventions
functions/scripts/prisma/instrumentation.tsmiddleware.ts- the config files
The project set it scans covers:
app
components
server
services
lib
hooks
utils
events
typesTests, stories and .d.ts files are ignored, and ignoreDependencies is empty.
Knip is not part of bun run verify or bun run lint — it is run on demand.
Inside the gate, the harness's own check-dead-components.ts, check-orphan-exports.ts and check-dead-server-actions.ts cover dead code.
Before adding a dependency
A runtime dependency has to be imported by real source code, or lint:deps fails on the next run. If it is consumed by configuration instead, it needs an entry in that script's ALLOWLIST, and that entry is the place to record why.
A patched dependency, like zsa, carries a file in patches/ that has to be revisited whenever that package is upgraded.
The question to ask is not whether the package works:
Which file will import it, and what does this repository do on the day it stops being maintained?
Related
Stack
Learn which versions of Next.js, React, Prisma, Tailwind, Better Auth, Stripe and Inngest Litestore runs on, and the architecture decisions behind them.
Harness
Learn about the 25 CI checks that run on your fork, and the 8-guide rule set behind them.
Linting
Learn how Biome formats and lints the codebase, what bun run lint and bun run verify actually run, and which lefthook hooks fire on commit and push.
Config
Learn what each file in config/ controls — site identity, activity logging, AI prompts, themes, color palettes, pricing defaults and the shipping country list.
Linting
Learn how Biome formats and lints the codebase, what bun run lint and bun run verify actually run, and which lefthook hooks fire on commit and push.