BoilerplateHub

Nuxt + Turso + Better Auth + Stripe

Nuxt with Turso, Better Auth and Stripe is for a Vue app deployed close to its users. SQLite replicas serve reads locally while a single primary holds sessions and subscription state. It suits a read-dominated or content-heavy product that still charges a recurring fee.

Nuxt TursoBetter AuthStripe

Database

Turso

Turso under Nuxt makes sense when reads should happen near the visitor and Nitro is deployed to more than one region. Put Better Auth's tables and the Stripe mirror in one primary database, use replicas for the read-heavy product data, and make writes explicitly go upstream. SQLite's small footprint also means a local file during development behaves like production, which removes a whole class of environment-only bugs from the loop.

Authentication

Better Auth

Better Auth talks to Turso through a SQLite adapter, so sessions are rows alongside everything else and validating one is a fast local read when a replica is nearby. That is the argument for this pairing rather than a hosted identity vendor. Server middleware resolves the session per request, and because Nuxt's auto-imports do not reach into server code, the auth server instance stays where it belongs instead of drifting into a component.

Payments

Stripe

Stripe keeps the billing brain, and in a distributed read setup you want precisely one place where subscription state is written: the primary. Webhooks should hit a region-pinned handler that writes upstream rather than any replica-backed route. Merchant of record duties remain yours, so tax handling is a decision to make deliberately before the first international sale rather than in the week an accountant asks about it.

What to watch out for

The Stripe Node SDK expects Node primitives, so deploying Nitro to a non-Node edge preset in order to sit near your replicas is exactly where this stack breaks. Either keep the checkout and webhook routes on a Node preset, or configure the SDK's fetch-based HTTP client explicitly. The mismatch never appears locally, because the development server is always Node, so it surfaces first in production.

Boilerplates close to this stack

Matched on Nuxt plus the parts of this stack our catalog tags. Each card shows which pieces actually line up, so you can see how much you would still wire yourself.

A CLAUDE.md for this stack

The rules that matter for this combination specifically, including who owns entitlement state. Adapt the commands to your repository before committing it.

CLAUDE.md
# CLAUDE.md

This project is a Nuxt SaaS on Turso, Better Auth and Stripe.

## Stack

- Framework: Nuxt
- Database: Turso
- Auth: Better Auth
- Payments: Stripe

## Boundaries

- Never edit a migration that has already run. Write a new one.
- Never hardcode Stripe price or product identifiers in components. They belong in config.
- Never trust a client-supplied user id. Read the session from Better Auth on the server.
- Treat webhook handlers as idempotent. The same event will arrive twice.

## Entitlements

- Stripe is the source of truth for what a customer paid for.
- The database mirrors that state; it never decides it.
- Any check for "can this user do X" reads the mirrored entitlement, not a live API call.

## Before you say a change is done

- The app builds.
- Tests pass.
- No secret, key or webhook signing secret appears in a committed file.

Related stacks