Val Town’s three-year journey from Clerk to Better Auth exposes the hidden costs of outsourcing core user infrastructure to third-party auth providers, even those with massive market success, revealing that architectural fit matters more than ease of setup for social, user-centric platforms.

By Tom MacWright, May 6, 2026
In 2023, I wrote about how Val Town moved away from Supabase and toward a more conventional database setup, trading Supabase’s bundled suite of tools for a standalone database on Render and Clerk for authentication. This shift was meant to simplify our stack, but it introduced a series of architectural conflicts that culminated in a second migration, completed a month ago, to Better Auth. The three-year arc of these changes reveals a critical lesson for teams building social, user-centric platforms: even widely adopted, well-funded third-party tools can introduce existential risks when their core assumptions about data ownership and infrastructure dependency clash with your product’s requirements, and the convenience of auth-as-a-service often masks hidden costs that only surface at scale.
The core issue that drove the eventual move away from Clerk was a fundamental mismatch between its architectural model and Val Town’s needs as a social platform where users constantly interact with content and profiles from other members. Clerk’s early positioning, articulated in a 2021 blog post titled “Consider dropping your users table” and a 2023 YouTube video called “DELETE your Users table,” centered on the idea that it could replace your users and sessions tables entirely, handling all user data storage and session management as a managed service. For simple, frontend-heavy applications where users only ever need access to their own profile data, this model works well, as Clerk’s JWT-based auth passes user details directly to the client without requiring database lookups. For a social platform like Val Town, where pages routinely display lists of content from dozens of distinct users, each with associated usernames, avatars, and profile settings, this assumption breaks completely.
Our initial implementation assumed we could load user data from Clerk’s API on demand, using the loadUser option in Clerk’s rootAuthLoader SDK tool, which handled auth for our entire application. This worked flawlessly in development, but in production we immediately hit a critical rate limit: five requests per second for our entire Clerk account, across all users. A single page rendering ten user profiles would trigger ten API calls, meaning we could only serve one such page per second before being throttled. This was a classic footgun, one that Clerk eventually fixed by removing the loadUser option, but it forced us to adopt a convoluted workaround: syncing user data from Clerk to our own database via webhooks, then serving user profiles from our local database instead of Clerk’s API. This introduced new complexity, as we now had two sources of truth for user data, with webhook delays meaning users could exist in Clerk’s system but not in our database for seconds after signup, or have a database row but an incomplete profile if they had not finalized their Val Town username, a required field for our platform. User settings were split between Clerk’s controls, which managed auth strategies like password and social login, and our own database, which stored Val Town-specific preferences like editor settings and notification preferences.
Beyond the users table conflict, Clerk introduced a second, more pernicious issue: it became a single point of failure for all user sessions. Traditional cookie-based session management uses short-lived cookies that refresh periodically against your own sessions table, meaning you retain full control over session validity and can invalidate sessions instantly if needed. Because Clerk handled all session management, Val Town had no sessions table, no ability to invalidate sessions independently, and no way to keep users logged in if Clerk’s infrastructure went down.
Session refresh requests were proxied through Val Town’s subdomains to Clerk’s servers, so every few minutes, every logged-in user’s browser would attempt to refresh their session via Clerk, and if Clerk was unavailable, the user would be logged out, or worse, unable to load any authenticated pages. Clerk’s outages did not just break login and logout flows, they rendered the entire site unusable for everyone, even users who had been logged in for hours. Public uptime data shows Clerk’s reliability between May 2025 hovered between two and three nines, a level of availability that translates to between 43 minutes and 8.76 hours of downtime per month, each incident taking Val Town offline entirely. Before that data was available, we experienced numerous unplanned outages caused solely by Clerk’s downtime, with no ability to mitigate the issue because we had ceded control of session management to a third party.
Given these persistent issues, a reasonable question is why we stayed with Clerk for nearly three years before switching. The answer lies in a combination of product inertia, Clerk’s genuine strengths, and a lack of viable alternatives. Rewriting authentication infrastructure is high-risk, especially for a small team, as errors can introduce critical security vulnerabilities, and we prioritize stability and development velocity over constant stack churn. Clerk also delivered real value: its SDKs for Remix, Fastify, and Express were well-maintained, keeping pace with framework updates that we knew required dedicated engineering effort, and its administration dashboard and anti-abuse tools helped us resolve customer support issues and mitigate spam and scam accounts. For the use cases it targets, Clerk remains an excellent tool: simple to set up, affordable for small teams, and with a polished dashboard that makes user management straightforward. The broader market agrees, as Clerk recently raised $50 million in venture funding, joining Supabase, which raised $100 million at a $5 billion valuation, as a major success story in the auth and backend-as-a-service space. These numbers are proof that Clerk works well for a large segment of developers, just not for those building social platforms with high user data access requirements.
The bar for replacing Clerk was high, as many open source auth solutions were poorly maintained, and other auth-as-a-service providers carried the same risks of vendor lock-in and architectural mismatch. We evaluated WorkOS AuthKit as a close second choice, trusting WorkOS’s track record and finding AuthKit’s implementation slick and reliable, but after bouncing between two vendor-managed auth providers, we prioritized a solution that was open source at its core and could operate independently of any third-party service for core auth and session management. Better Auth checked these boxes immediately: its codebase is high quality, it offers integrations for all our frameworks, and it is designed to be self-hosted, meaning we retain full control over user and session data. Better Auth’s paid add-ons, including its dashboard, are cleverly designed to be stateless, pulling data from our own database via a plugin rather than storing user data on Better Auth’s servers, so even their paid services do not introduce a new single point of failure. The only remaining vendor risk is that Better Auth is primarily developed by a single company, but as open source code, we can audit, modify, or fork the project if needed, a level of control we never had with Clerk.
Migrating to Better Auth was a complex process, and we relied on LLM assistance to manage the two-week transition period where both Clerk and Better Auth cookies were accepted by our endpoints. This allowed users to migrate gradually as they refreshed their sessions, rather than forcing a disruptive one-time switch, but all AI-generated code was manually reviewed, rewritten, and tested extensively, as security-critical code cannot be trusted to automated tools without close human oversight. The final pure-Better Auth implementation is entirely handwritten, and early results have been positive: we no longer depend on a third party for session management, rate limits are set by our own infrastructure and scale with our traffic, and user data is stored solely in our database, eliminating sync delays and split sources of truth. Better Auth also integrates smoothly with Val Town’s code execution environment, and developers can try out the Better Auth starter template to add authentication to their own Val Town projects.
Acknowledging counterarguments to our choice is necessary: Clerk remains a better fit for teams building simple, non-social applications, where the convenience of managed auth outweighs the risks of vendor lock-in, and Better Auth’s relative youth and single-company development model carry risks that Clerk, with its larger team and funding, does not. AuthKit is another strong alternative for teams that prefer a managed service but want a more reliable provider than Clerk, and we would have chosen it if open source control were not a priority. No auth solution is perfect, and the right choice depends entirely on your product’s specific requirements, not just a tool’s market success or ease of setup.
This journey has reinforced a broader lesson about building complex systems: your platform’s reliability is only as high as the reliability of its most critical, non-redundant components, and outsourcing those components to third parties trades short-term convenience for long-term risk. Products can be wildly successful, well-designed, and loved by thousands of users while still being entirely wrong for your specific use case, and the right solution may not exist when you first need it, but emerge later as the ecosystem evolves. For Val Town, Better Auth is the right fit today, but we remain open to future changes as our needs grow and the auth landscape shifts, prioritizing control over our core user infrastructure above all else.

Comments
Please log in or register to join the discussion