Skip to content

Packages

Package selection in TypeScript projects should be intentional. The goal is to use a small set of well-supported packages that fit the framework, deployment model, and team familiarity without creating unnecessary dependency sprawl.

New TypeScript projects should start with a minimal dependency set and add packages only when they materially improve correctness, maintainability, or delivery speed.

Use these defaults unless the project has a clear reason to do otherwise:

  • ESLint for static analysis and code quality rules
  • Prettier for formatting
  • Lefthook for local Git hooks
  • Tailwind CSS for utility-first styling
  • Drizzle as the default ORM for PostgreSQL-backed application development
  • Framework-native UI libraries and patterns before introducing additional abstraction layers

Choosing an alternate package should be a deliberate decision based on product requirements, team familiarity, and long-term maintenance cost.

Before adding a package, evaluate:

  • Whether the framework already provides the needed capability
  • Whether the package is actively maintained and widely adopted
  • Whether it improves correctness, developer experience, or delivery speed enough to justify the dependency
  • Whether it introduces a new runtime, code generation step, or build constraint
  • Whether it fits the team’s existing skills and support model
  • Whether it overlaps with packages already in use

If a package solves a narrow problem but adds significant build, runtime, or maintenance complexity, it is usually the wrong choice.

ESLint and Prettier are the standard baseline for TypeScript repositories.

Use ESLint to enforce code quality, language best practices, accessibility rules where applicable, and framework-specific conventions. Use Prettier to keep formatting automatic and non-negotiable.

Guidance:

  • Run both tools in local development and CI
  • Keep formatting concerns in Prettier and code-quality concerns in ESLint
  • Avoid overlapping or contradictory lint rules when Prettier already owns formatting
  • Prefer a shared repository or organization-level configuration when multiple projects follow the same standards

UI package selection should follow the chosen framework.

React is appropriate for React-based applications such as Next.js projects and should not be added to non-React projects without a strong architectural reason.

shadcn/ui is a good fit for React applications that need accessible, composable UI primitives without adopting a heavy opinionated component framework.

shadcn-svelte serves the same role for Svelte and SvelteKit projects.

Tremor is appropriate for dashboard-style interfaces and internal tools that benefit from prebuilt data visualization and application UI patterns.

Prefer smaller, framework-aligned component libraries over large design systems unless the project genuinely needs the extra surface area.

Tailwind CSS is the default styling utility for TypeScript frontend projects that benefit from rapid, consistent UI development.

Prefer Tailwind when a project needs:

  • A shared design token approach through configuration
  • Fast iteration on layouts and component styling
  • Consistent spacing, typography, and responsive patterns
  • A styling model that works well across component-based frameworks

Motion is appropriate when animation is a meaningful part of the product experience. It should be used intentionally for transitions, gestures, and interactive states, not as default decoration on every page.

ORM selection should be based on project requirements, including type safety, query flexibility, migration workflow, and operational clarity.

Drizzle is the default ORM for new PostgreSQL-backed TypeScript applications. It keeps SQL close to the application, works well with TypeScript types, and generally introduces less abstraction than heavier ORM layers.

Prisma is a reasonable choice when a project benefits from its schema-driven workflow, generated client, and mature ecosystem, and the team is comfortable with its abstraction and migration model.

Regardless of ORM choice:

  • Keep schema changes in version control
  • Understand the SQL being generated or executed
  • Avoid hiding database performance problems behind ORM abstractions
  • Do not treat an ORM as a substitute for database design knowledge

Lefthook is the standard Git hooks tool for TypeScript repositories.

Use Git hooks to run fast, high-signal checks before code is committed, such as formatting, linting, or targeted tests. Hooks should improve consistency without making normal development slow or fragile.

Recommended expectations:

  • Keep hook commands fast enough for regular local use
  • Prefer targeted checks over running the entire test suite on every commit
  • Mirror important checks in CI so enforcement does not depend only on local configuration
  • Store hook configuration in the repository so behavior is consistent across the team

Avoid these common mistakes:

  • Adding multiple packages that solve the same problem
  • Introducing a package for a capability already handled by the framework or platform
  • Choosing a package based on popularity alone without considering maintenance and operational fit
  • Adopting a large dependency for a small utility that can be handled with platform APIs or a few lines of code
  • Mixing competing styling, form, state, or data-access approaches in the same project without a clear reason

Package choices should reduce complexity for the team and the codebase, not create another system to manage.