DeesseJS
  • Enterprise
  • Pricing
DeesseJS logoDeesseJS

Software engineering as a commodity: agents that code, workflows that scale, infrastructure that works. Built with the DeesseJS ecosystem.

Ecosystem

  • Errors
  • DRPC
  • Collections
  • FP

Learn

  • Docs
  • Blog
  • Changelog
  • Knowledge Base

Use cases

  • SaaS apps
  • AI products
  • Landing pages
  • API backends
  • Internal tools

Company

  • About
  • Manifesto
  • Principles
  • Vision
  • Enterprise
  • Delivery
  • Help

Legal & Trust

  • Privacy
  • Terms
  • Cookies
  • DPA
  • Security

Community

  • Open Source Program
  • Github
  • LinkedIn
  • X

Explore

  • Customers
  • Templates
  • Ecosystem
  • Stack
© 2026 DeesseJS. All rights reserved.

Ready to ship?

Read more, or ship with us.

Subscribe to the blog and changelog feeds, install the CLI to scaffold a project in under five minutes, or talk to our delivery team if you need a hand. Same templates, same contracts, same guarantees.

Install the CLIBrowse the registry
Back to blog

Better Auth vs Roll-your-own: the boring option won

We considered Clerk, Lucia, and writing our own. We picked Better Auth because it's the only one an agent can debug at 2am.

by Alex Mercier
2026-06-09
4 min read
Tags
  • engineering

The auth contract is the one that, if you get it wrong, costs you a quarter. We considered four options for the default implementation. We picked Better Auth. Here's the reasoning.

The four options

Clerk. The polished option. Excellent DX. Handles every edge case you haven't thought of. Pricing scales with MAU, which means at our scale it costs more than running the auth ourselves.

Lucia. The opinionated option. Smaller surface area than Clerk. Forces you to own the auth flow end to end. Best for projects that want full control.

Better Auth. The boring option. Newer than the others. Implements the standard set of features (sessions, organizations, OAuth, 2FA) without the polish of Clerk or the minimalism of Lucia.

Roll-your-own. The trap. Write the session table, the password hashing, the email verification, the OAuth flow, the 2FA challenge, the recovery codes, the rate limiting, the audit log. Maintain it forever.

What we actually want

We want auth that:

  • Works on day one.
  • Doesn't cost more than the rest of our stack combined at scale.
  • Is debuggable by an agent at 2am.
  • Has a typed interface at the boundary, so swapping implementations is a config change.

Clerk wins on day one and on polish. It loses on cost at scale and on debuggability — the agent doesn't see what Clerk is doing, because Clerk is a black box.

Lucia wins on ownership and on smallness. It loses on day-one polish — you have to wire more things yourself — and on the agent-debug story, which requires the agent to read more code.

Better Auth wins on debuggability and on being boring. The source is TypeScript. The session table is a normal Postgres table. The OAuth flow is normal HTTP. An agent reading the auth code sees the auth code, not a vendor SDK.

Roll-your-own wins on no one. We considered it. We have done it. We will not do it again.

The cost calculation

For our scale (mid-five-figure MAU), Clerk is roughly $24k/year. Better Auth on the same scale, running on Upstash Redis for session storage, is roughly $200/month for the Redis and $0 for the auth itself. The difference pays for a senior engineer for two months.

If we were at the scale where Clerk's pricing leveled out — say, 100k MAU and a team that didn't want to own auth — Clerk would be the right answer. We're not at that scale, and the auth contract means we can swap if we ever are.

The debuggability argument

This is the part that matters most, and the one that's hardest to make on a slide.

When auth breaks at 2am, the question is: how many layers of indirection between the failure and the line of code I need to fix?

With Clerk, the answer is: many. The failure is in a third-party service. The agent doesn't have access to that service's source. The agent can reason about the failure, but it can't read the code that failed.

With Better Auth, the answer is: zero. The session lookup is a SQL query. The password verification is a function call. The OAuth callback is a route handler. The agent reads the file, sees the bug, fixes it.

We have shipped products where auth broke at 2am. We have shipped products where the agent (or the engineer) had to debug Clerk. We have not shipped a product where the engineer had to debug Better Auth at 2am. The difference is the difference between a vendor and a library.

Where Better Auth is weak

Better Auth is younger than Clerk and Lucia. The plugin ecosystem is smaller. Some integrations (SAML, magic links, advanced MFA) are less polished.

If you need SAML today, Clerk is the right answer. If you need a magic link flow that works in a specific way, Lucia or Better Auth with custom code is the right answer.

We don't need those today. When we do, we'll write the integration or swap. The contract makes the swap a config change.

The boring conclusion

Better Auth is the boring option. It's a library, not a service. It does what the auth contract requires. It doesn't do magic. The agent can read it.

We picked it for the same reason we picked Postgres over a managed database, and Drizzle over Prisma, and Stripe over building our own billing. We pick the option that an agent can debug at 2am, because the agent is the engineer, and the engineer is on call.

The boring options compound. The exciting options compound too, but in the wrong direction.

PreviousFrom npx init to deployed: the first ten minutes of a new projectNextStripe webhooks are not a contract: how we made them one

Related reading

  • 2026-07-21engineering
    Background jobs that don't wake you up at night
    Retries, dead-letter, idempotency. The three patterns every job needs and the mistakes we made so you don't have to.
    David PereiraChief Executive Officer
    5 min read
  • 2026-07-14engineering
    From CLI to MCP: extending the registry without forking it
    Plugins, hooks, and the surface area we expose to MCP servers. Why we picked this over a marketplace.
    Alex Mercier
    5 min read
  • 2026-07-07engineering
    The AGENTS.md file: what we put in it, what we left out
    Our templates include a 200-line AGENTS.md at the monorepo root. Here's the structure, the rationale, and the bits we deleted.
    David PereiraChief Executive Officer
    4 min read