Skip to main content

How duck-auth compares

WIP

Honest tradeoffs versus NextAuth/Auth.js, Clerk, WorkOS, Lucia, and Better-Auth. What we picked, what we deliberately don't do.

The space

The TypeScript auth space has three archetypes:

  1. Framework-locked - NextAuth / Auth.js. Tightly tied to Next.js (with adapters for others, but the heart is Next).
  2. Hosted control plane - Clerk, WorkOS, Stytch. You don't run the auth runtime; their service does. Per-MAU pricing.
  3. DIY toolkit - Lucia, Better-Auth, custom passport stacks. You own the runtime; the library gives you primitives.

duck-auth is the third type. The pitch: a complete DIY toolkit with batteries included - Lucia's freedom plus Clerk's coverage minus the hosted plane.

Quick table

duck-authNextAuth / Auth.jsClerkLuciaBetter-Auth
FrameworkAny (Express / Hono / Next / Fastify / Koa / Elysia / NestJS / gRPC / Web Fetch)Mostly Next.jsAny (via SDK)AnyAny
Hosted planeNoNoYesNoNo
PricingOSS (MIT)OSS (ISC)<MathMlmathml="<span class=&quot;katex&quot;><span class=&quot;katex-mathml&quot;><math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><semantics><mrow><mn>25OSS (MIT)OSS (MIT)
Sign-in providersPassword + magic-link + 6 OAuth + passkey + API key + SAMLOAuth + email (limited social passkey)OAuth + email + SMS + passkey + SAMLDIYOAuth + email + passkey + magic-link
JWT supportHS256/ES256/RS256/EdDSA + JWKS rotation + DPoP (RFC 9449)No (cookie-only by default)YesNoYes
OIDC issuerYes (discovery doc + JWKS endpoint)NoNoNoNo
SAMLYes (with @node-saml/node-saml)Yes (Auth.js Pro)YesNoNo
MFA factorsTOTP + backup codes + WebAuthn-MFANo (community plugins)TOTP + SMS + backup codes + passkeyDIYTOTP
Multi-tenant orgsYes (built-in orgs facet)NoYesDIYDIY
Compliance presetsGDPR / SOC2 / HIPAA / FIPSNoneSOC2 (managed)NoneNone
strict() boot gateYesNoN/A (hosted)NoNo
Audit logBuilt-in event bus + AuthWebhookDelivererNoneBuilt-inDIYNone
OpenAPI specGenerated from runtimeNoYesNoNo
OpenTelemetryBuilt-in (@gentleduck/auth/telemetry/otel)NoneNoneNoneNone
CLIinit / doctor / keys / migrate / emit-openapiNoneLimitedNoneNone
LicenseMITISCProprietaryMITMIT

What duck-auth is not

Honest list of what we deliberately don't ship:

  • No hosted plane. Every other big-name auth service has one. We don't. If you want a hosted dashboard, billing, organizational invitations as a service, use Clerk / WorkOS / Stytch.
  • No "magic" Next.js integration. Next is one server adapter among nine. duck-auth doesn't auto-generate route handlers, doesn't read app/auth.config.ts, doesn't hijack middleware. You mount what you want.
  • No built-in admin UI. The shape of an admin UI (user search, ban, impersonate, audit log viewer) is too app-specific. We give you the facets (identities, sessions, apiKeys, operations, hijack); you compose the UI.
  • No authorization engine. That's @gentleduck/iam. Keeping them separate is intentional - see the bridging guide.
  • No SMS as a primary factor. SMS is shipped as a magic-link channel and an MFA channel, but we treat it as low-assurance because SIM-swap fraud is rampant. Prefer passkeys or TOTP.

Why duck-auth over NextAuth?

Pick duck-auth if:

  • You serve more than just Next.js apps (Express / Hono / mobile API / etc).
  • You need MFA out of the box (NextAuth doesn't ship it).
  • You need an OIDC issuer (NextAuth can't be one).
  • You need JWT + JWKS + DPoP (NextAuth is cookie-only by default).
  • You want compliance presets (HIPAA / FIPS).
  • You want a strict() boot gate that catches misconfigurations.

Pick NextAuth if:

  • You're 100% Next.js and want zero ceremony.
  • You're already in the Auth.js ecosystem (Vercel, etc).

Why duck-auth over Clerk?

Pick duck-auth if:

  • You can't tolerate the per-MAU pricing at scale (Clerk gets expensive past 50k MAUs).
  • You need on-premise / air-gapped / HIPAA-residency control over your auth data.
  • You want to own session revocation, MFA enrolment, audit logs.
  • You're allergic to vendor lock-in.

Pick Clerk if:

  • You want zero ops burden - let someone else run the auth runtime.
  • You need the polished pre-built UI components.
  • You're under 5k MAUs and want the free tier.

Why duck-auth over Lucia?

Pick duck-auth if:

  • You want batteries included - magic-link, OAuth, passkeys, API keys, channels, OpenAPI, OIDC, OTel - without writing every piece.
  • You want compliance presets.
  • You want a strict() boot gate.

Pick Lucia if:

  • You want absolute minimal surface area and prefer to write every provider, channel, and audit hook yourself.
  • You enjoy assembling the toolkit and want full control.

Why duck-auth over Better-Auth?

Pick duck-auth if:

  • You need SAML, M2M / client-credentials, or the full OIDC issuer.
  • You need 14 typed facets exposed on a single root (vs. flat config).
  • You need an OpenAPI spec generated from the runtime.
  • You need OpenTelemetry instrumentation out of the box.

Pick Better-Auth if:

  • You like its plugin-driven config style.
  • You're already deep in the Better-Auth ecosystem.

A note on maturity

duck-auth is pre-1.0. The surface is ~98% of v1.0 (see STATUS.md), 617 tests pass, but it's younger than NextAuth and Clerk. Expect sharp edges; pin a version. Production users should run AuthEngine.strict({ env: 'production' }) and follow the security guide.