Every six months we audit the open-source libraries we depend on. This article is the 2026 version of that audit — the libraries we use in production across multiple projects, the ones we dropped, and the ones we are watching. It is opinionated, current as of early 2026, and probably useful if you are picking a stack for a new project.

The criteria

For a library to make this list, it has to:

  • Be actively maintained (commits in the last six months).
  • Have a stable, documented API.
  • Have a meaningful user base (not just the maintainer's toy project).
  • Have a sensible licence (MIT, Apache 2.0, BSD — no GPL).

We use dozens of libraries across our projects. The ones below are the ones that show up in every project, or in many projects, with high reliability.

JavaScript / TypeScript

The front-end stack we use is covered in our toolchain article. The libraries beyond that:

  • Vue — the framework. Vue 3 with the Composition API.
  • Pinia — state management. Replaced Vuex as the official recommendation.
  • Vue Router — client-side routing.
  • VueUse — a collection of composables (the Vue equivalent of React's react-use). Useful for the inevitable "how do I do X" cases.
  • vee-validate — form validation with a clean API. Pairs nicely with the form patterns in our Form UX article.
  • Zod — schema validation. The single best way to validate API payloads and form input.

For build tools: Vite for dev server and bundling, Vitest for unit tests, Playwright for end-to-end tests.

Back-end / .NET

For ASP.NET Core projects:

  • Entity Framework Core — the ORM. Covered in our EF Core article.
  • ASP.NET Core Identity — authentication scaffolding. Pair with a JWT library for API auth.
  • FluentValidation — more expressive than data annotations for complex validation.
  • Serilog — structured logging. The default ASP.NET Core logger is fine; Serilog is better for production.
  • BCrypt.Net-Next — password hashing. We have written about the importance of this in our security article.
  • MediatR — the mediator pattern for clean request/handler separation. Useful for larger codebases.

Database and infrastructure

  • PostgreSQL — the default relational database. Always.
  • MongoDB — for document-shaped data. Our usage is covered in detail.
  • Redis — caching, sessions, rate limiting. Small, fast, indispensable.
  • Docker — containerisation. Every project we ship has a Dockerfile.

CSS and design

  • Tailwind CSS — utility-first CSS. Covered in our toolchain article.
  • shadcn-vue — accessible component primitives. Drop in, own the code.
  • Lucide — icon set. Clean, consistent, well-maintained.
  • @vueuse/motion — animation composables. Wraps the Web Animations API in a friendly interface.

Tooling and DX

  • TypeScript — strict mode, end-to-end. We would not start a new project without it.
  • ESLint + Prettier — linting and formatting. The default config is fine; customise minimally.
  • Husky — git hooks for running lint and tests before commits.
  • Linear — issue tracking. Fast, opinionated, joy to use.

What we dropped this year

Some libraries that used to be on this list, but no longer:

  • Lodash. Modern JavaScript has most of what Lodash offers. The remaining bits are tiny enough to write directly.
  • Axios. The native fetch API is good enough for most use cases. We reach for Axios only when we need request cancellation or progress events.
  • Moment.js. Replaced by date-fns (smaller, immutable) or Temporal (the future standard). Moment has been in maintenance mode for years.
  • Vuex. Replaced by Pinia, which is smaller, more typed, and easier to test.

What we are watching

Some libraries we have not adopted yet but are tracking:

  • Effect — a TypeScript library for composable async code. Promising, but the learning curve is steep.
  • Drizzle ORM — a TypeScript-first ORM for SQL. We like the type safety; we are waiting to see ecosystem maturity.
  • tRPC — end-to-end typesafe APIs. Beautiful for greenfield projects, harder to adopt incrementally.
  • Bun — fast JavaScript runtime with built-in tooling. We will start using it once it stabilises.

Adopting any new library is a risk. The discipline is to wait until the library has been stable for at least a year and has a meaningful user base before bringing it into a client project.

The licence question

We use MIT, Apache 2.0, and BSD-licensed libraries without hesitation. We avoid GPL and AGPL for any code that ships to clients — the licence is viral in ways that can be surprising. Most major libraries use one of the permissive licences, so this is rarely a constraint.

Further reading

Our library audit is one part taste and one part evidence. The three sources below provide the data behind our decisions: package-usage data, ecosystem health, and the security posture of the libraries we depend on.

  • npm registry — the npm registry, used here for download counts, package metadata, and the dependency graph behind every JavaScript library we consider.
  • GitHub Octoverse — GitHub’s annual Octoverse report on the open-source ecosystem — language usage, contributor growth, and project health.
  • Snyk State of Open Source Security — Snyk’s annual report on open-source security, with data on vulnerable packages, fix latency, and ecosystem-wide risk trends.
  • clients — the licence is viral in ways that can be surprising. Most major libraries use one of the permissive licences, so this is rarely a constraint.

    How to evaluate a new library

    When considering a new dependency, we ask five questions:

    1. Who maintains it? A company or a foundation is more durable than a single maintainer.
    2. How active is the repo? Recent commits, recent issues, recent releases.
    3. What is the download count? A library with millions of weekly downloads is safer than one with hundreds.
    4. What is the licence? MIT, Apache 2.0, BSD are safe. AGPL is risky for client work.
    5. Can we replace it? If the library disappeared tomorrow, how much code would we have to rewrite? Small, well-isolated dependencies are easier to swap.

    If the answers are good, we add it to the stack. If not, we write what we need ourselves, or wait for a better option to emerge.

    FAQ

    Do you avoid dependencies?

    No. Dependencies are leverage — they let us ship more in less time. The discipline is in choosing dependencies well, not in avoiding them. We use dozens of packages per project; we just audit them carefully.

    How do you keep dependencies up to date?

    Dependabot (GitHub) or Renovate for automated PRs. We review and merge weekly. Major version upgrades get their own planning session because they often have breaking changes.

    What is your take on dependencies in security-sensitive code?

    For crypto, hashing, authentication: prefer the standard library or a single, well-vetted dependency. Do not pull in a fresh new library for password hashing just because it has more stars on GitHub. We have written about this in our security article.

    What about vendoring dependencies?

    Sometimes. For a small set of critical libraries, we check them into the repo so the build does not depend on a registry being up. Not a default practice, but a useful escape hatch.

    Do you use monorepos?

    For projects with multiple deployable services (front-end, back-end, mobile), yes. We use Nx or Turborepo for the tooling. For single-service projects, a regular repo is fine.

    The server-side libraries we use

    For Node.js backends (when we are not using ASP.NET Core):

    • Fastify — fast, low-overhead web framework. We use it when we need a Node API.
    • Prisma — TypeScript ORM. Loved by teams that want full type safety on database queries.
    • jsonwebtoken — JWT signing and verification. Pairs with the patterns in our JWT article.
    • bcrypt — password hashing. See our security article for the context.
    • zod — schema validation. Used at every API boundary.

    For Python projects (occasional)

    Most of our work is in TypeScript or C#. When we do use Python (data science, ML, scripting):

    • FastAPI — modern Python web framework. Type hints, async, automatic OpenAPI docs.
    • Pydantic — data validation. The Python equivalent of Zod.
    • SQLAlchemy — the dominant Python ORM. Mature, well-documented.
    • httpx — modern HTTP client. Async-first, like requests for the async era.

    Observability and ops

    Every production service we ship has:

    • Structured logging. Serilog for .NET, Pino for Node, structlog for Python.
    • Error tracking. Sentry for everything.
    • Uptime monitoring. Better Stack or UptimeRobot.
    • Performance monitoring. Vercel Analytics for front-ends, native APM for back-ends.

    You do not need all of these for a hobby project. For anything that real users depend on, missing any of them is painful. Set them up on day one, not after the first outage.

    The hidden dependencies: services we pay for

    Beyond the code libraries, we pay for several services that make everything work:

    • GitHub for source control.
    • Linear for issue tracking.
    • Figma for design.
    • Sentry for error tracking.
    • Render or Fly.io for hosting.
    • Neon or Supabase for managed PostgreSQL.
    • MongoDB Atlas for managed MongoDB.
    • Cloudflare for DNS and edge.

    These are operational dependencies, not code dependencies. They are just as important to monitor and budget for as the npm packages you install. When picking a vendor, the same evaluation criteria apply: maintenance, community, licence, replaceability.

    The discipline of dependency updates

    Every Monday, one of us spends 30 minutes on dependency updates. Renovate opens PRs; we review and merge. Major version upgrades get their own planning session because they often have breaking changes.

    This discipline prevents the "we are two years behind on everything" problem that plagues many codebases. The cost is small (30 minutes per week); the benefit is enormous (no surprise upgrade sprints, no security holes that linger for months).

    The shape of a healthy dependency list

    A few heuristics we use to judge whether a dependency list is healthy:

    • No abandoned libraries. Anything without a commit in over a year is suspect.
    • No single-maintainer projects at the core. A solo maintainer can disappear. Bus factor matters.
    • No two of the same thing. If you have both Lodash and Ramda, you have made a mistake.
    • No surprises in the security audit. Run npm audit or dotnet list package --vulnerable weekly. The output should be clean.

    A healthy dependency list is small, current, and well-known. An unhealthy one is large, outdated, and surprising. You can feel the difference in every change.

    The discipline is the part that survives every framework rewrite, every version bump, every new paradigm. Audit often, switch carefully, and ship more than you analyse.

    The discipline is the part that survives every framework rewrite, every version bump, every new paradigm. Audit often, switch carefully, and ship more than you analyse.

    The discipline is the part that survives every framework rewrite, every version bump, every new paradigm that comes along. Audit often, switch carefully, and ship more than you analyse. That is the most important takeaway.

    The discipline is the part that survives every framework rewrite, every version bump, every new paradigm that comes along. Audit often, switch carefully, and ship more than you analyse. That is the most important takeaway we can offer.

    Closing thought

    The list above will probably look different in six months. That is fine — the audit is what matters, not the specific libraries. The discipline of asking "is this still the right choice?" is more valuable than any individual recommendation.