Use The Platform

Verge Kit prefers the framework and platform tools already in the project.

Use Astro pages, API routes, Actions, middleware, and config before adding a new local abstraction. Add helpers only when they remove repeated code or protect a real boundary.

D1 First

D1 is the supported runtime database.

Use the local src/db modules from app code. Do not import drizzle-orm/d1 directly in routes, pages, actions, or components.

This keeps future Hyperdrive PostgreSQL or MySQL work isolated to the database adapter layer. The proof modules for those targets are test-only; runtime code still rejects PostgreSQL and MySQL target names.

Config Has A Boundary

Use src/config for source-level app defaults and auth policy that app code imports directly. App identity, default authenticated navigation, protected routes, app roles, permission values, and banned-session copy belong there.

Use wrangler.jsonc as the committed source of truth for non-secret Worker runtime values. Typical values include EMAIL_PROVIDER, EMAIL_FROM, EMAIL_REPLY_TO, BETTER_AUTH_URL, and MAILGUN_DOMAIN.

Use .dev.vars for local secret values and local-only overrides. Use Wrangler secrets for deployed secret values. Do not commit API keys, auth secrets, or provider credentials in wrangler.jsonc.

Server First

Keep auth, database writes, email, and validation on the server.

Use client JavaScript only where it improves a specific interaction.

Validate At The Boundary

Use Zod for request bodies, form input, and action input.

Keep validation close to the route or action that receives external data.

Middleware Owns Auth State

Middleware creates the Better Auth instance, reads the session, and writes:

  • Astro.locals.user
  • Astro.locals.session
  • Astro.locals.isAuthenticated

Pages and routes should read from locals instead of reimplementing session lookup.

Routes Are Public By Default

Middleware loads auth state for every request, but route protection is opt-in. Use src/config/auth.ts when pages or API namespaces should be consistently protected by middleware. Use route-local checks when a page or API handler needs custom redirect or JSON 401 behavior.

Keep Better Auth endpoints under /api/auth public so sign in, sign up, verification, reset, session, callback, and sign-out requests can reach Better Auth before a user has a session.

Roles Are App Policy

The Better Auth admin plugin is installed and configured with admin, moderator, user, and banned roles. App permissions live in src/config/auth.ts, and local checks should use the helpers in src/auth/permissions.ts.

Email Is A Provider

Auth email is rendered once and sent through a provider.

Local development can use console. Workers deployments should use Cloudflare Email, Resend, Mailgun, or another fetch/binding-based provider.

Use sendEmail directly for custom transactional messages. Use createAuthEmailSenderFromEnv for Better Auth verification and reset flows so auth email templates and EMAIL_FROM handling stay centralized.

Initialization Is Operational

Run migrations before seeding users. npm run init:admin creates a verified Better Auth user directly in D1 through Wrangler, selecting local or remote D1 from BETTER_AUTH_URL unless --local or --remote is passed.

Keep The Boilerplate Small

Verge Kit does not include uploads, media processing, full admin CRUD screens, analytics, queues, workflows, or production PostgreSQL/MySQL runtime support yet.

Add those when an application needs them.