A production-ready SaaS starter template built with Astro 5, Better Auth, Stripe, Prisma, and Tailwind CSS.
- 🔐 Authentication — Email/password + GitHub + Google via Better Auth
- 💳 Stripe Billing — Checkout, subscriptions, customer portal, and webhooks
- 📊 Dashboard — Responsive sidebar layout with stat cards
- 🗃️ Prisma ORM — SQLite by default, swap to Postgres/MySQL in one line
- 🎨 Tailwind CSS — Utility-first styling with custom brand colors
- ⚡ Astro 5 SSR — Server-side rendered with Node.js adapter
- 🛡️ Middleware — Session auth on every request
- 📄 TypeScript — End-to-end type safety
# Clone the repo
git clone https://github.com/kszongic/astro-saas-starter.git
cd astro-saas-starter
# Install dependencies
npm install
# Set up environment
cp .env.example .env
# Edit .env with your Stripe keys and auth secret
# Set up database
npx prisma db push
npx prisma generate
# Start dev server
npm run devOpen http://localhost:4321.
src/
├── components/ # Reusable UI components
│ ├── PricingCard.astro
│ ├── Sidebar.astro
│ └── StatCard.astro
├── layouts/ # Page layouts
│ ├── Base.astro
│ └── Dashboard.astro
├── lib/ # Server utilities
│ ├── auth.ts # Better Auth config
│ ├── db.ts # Prisma client
│ └── stripe.ts # Stripe client + plans
├── pages/
│ ├── api/
│ │ ├── auth/[...all].ts # Auth API routes
│ │ └── stripe/
│ │ ├── checkout.ts # Create checkout session
│ │ ├── portal.ts # Customer portal redirect
│ │ └── webhook.ts # Stripe webhook handler
│ ├── auth/
│ │ ├── login.astro
│ │ └── register.astro
│ ├── dashboard/
│ │ ├── index.astro # Overview with stats
│ │ ├── billing.astro # Subscription management
│ │ └── settings.astro # Account settings
│ └── index.astro # Landing page
├── middleware.ts # Session middleware
└── env.d.ts # Type declarations
prisma/
└── schema.prisma # Database schema
| Variable | Description |
|---|---|
DATABASE_URL |
Prisma database URL (default: SQLite) |
BETTER_AUTH_SECRET |
Random secret for auth sessions |
BETTER_AUTH_URL |
Your app URL |
STRIPE_SECRET_KEY |
Stripe secret key |
STRIPE_PUBLISHABLE_KEY |
Stripe publishable key |
STRIPE_WEBHOOK_SECRET |
Stripe webhook signing secret |
STRIPE_PRICE_PRO_MONTHLY |
Stripe Price ID for monthly plan |
STRIPE_PRICE_PRO_YEARLY |
Stripe Price ID for yearly plan |
GITHUB_CLIENT_ID |
GitHub OAuth app client ID |
GITHUB_CLIENT_SECRET |
GitHub OAuth app client secret |
GOOGLE_CLIENT_ID |
Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret |
Change the provider in prisma/schema.prisma:
datasource db {
provider = "postgresql" // or "mysql"
url = env("DATABASE_URL")
}- Create products and prices in the Stripe Dashboard
- Copy the Price IDs to
.env - Set up a webhook endpoint pointing to
/api/stripe/webhook - Listen for:
customer.subscription.created,customer.subscription.updated,customer.subscription.deleted
npm run build
node dist/server/entry.mjsFROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx prisma generate && npm run build
EXPOSE 4321
CMD ["node", "dist/server/entry.mjs"]MIT — use it for anything.