# Cloudflare Workers SaaS Template: a Next.js App Router app deployed through Vinext

> This template is a full SaaS starter for Cloudflare Workers that runs a Next.js App Router application on Vite through Vinext, with authentication, D1 and Drizzle, email, Stripe team billing, a public API with OAuth and a remote MCP server, a CMS and a GitHub Actions pipeline. Vinext is Cloudflare's experimental implementation of the public Next.js API on Vite and is not affiliated with Vercel.

**LubomirGeorgiev/cloudflare-workers-nextjs-saas-template** — Cloudflare Workers/Next.js SaaS Template

- Repository: https://github.com/LubomirGeorgiev/cloudflare-workers-nextjs-saas-template
- Website: https://nextjs-saas-template.lubomirgeorgiev.com/sign-up
- Stars: 787 · Forks: 171
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/lubomirgeorgiev-cloudflare-workers-nextjs-saas-template

## What Vinext changes about a Next.js app

The template runs a Next.js App Router application directly on Cloudflare Workers, and the mechanism is Vinext on Vite. Vinext is described as Cloudflare's experimental implementation of the public Next.js API surface on top of Vite.

The goal is that a Next.js app keeps familiar App Router patterns, React Server Components, route handlers and next/* imports while using Vite as the build and dev toolchain instead of the standard Next.js compiler pipeline. For this template, Vinext is the runtime and deployment path, and the scripts in the package manifest are the three commands you need:

```json
    "dev": "vinext dev",
    "build": "vinext build",
    "deploy": "node scripts/check-deploy-site-url.mjs && vinext-cloudflare deploy",
```

So pnpm dev starts the Vinext development server, pnpm build produces the Vinext and Vite production output, and pnpm deploy checks the site URL before handing over to vinext-cloudflare deploy.

Vinext is explicitly not a fork of Next.js and not affiliated with Vercel. That distinction matters for two reasons. The first is licensing and support, since a Vercel-adjacent dependency would carry a different set of expectations. The second is that Vinext is still experimental, so the README says framework-sensitive changes should be verified with pnpm run check:vinext, pnpm run typecheck, pnpm run lint and pnpm run build. The package manifest has a check:vinext script that runs vinext check, and a check:startup script that builds and then runs wrangler check startup against the generated dist server configuration.

The bindings available through cloudflare:workers are listed as D1, KV, R2, Images, Durable Objects and AI, which is the reason to deploy on Workers in the first place.

## Authentication, sessions and the account surface

Authentication is built on Lucia Auth, and the feature list runs through the whole account lifecycle: email and password sign in and sign up, WebAuthn and passkey authentication, Google OAuth for single sign-on, a forgot password flow, a change password screen, email verification, and session management backed by Cloudflare KV.

There is a session listing and management screen, protected routes and layouts, rate limiting for the auth endpoints, and Turnstile captcha integration. The template is unusually complete here, and the interesting part is the choice of Lucia, which is a set of primitives rather than a hosted service, so the session logic lives in the Worker and the sessions sit in KV.

The email side uses the Cloudflare Email Service, with email templates, a preview mode for looking at them without sending, a local email development server, and transactional email for the verification flow. The scripts list has an email:preview entry that runs a preview server for those templates.

The .env.example file shows the shape of the configuration. Cloudflare account and API access come first, with the token needing edit access to every binding because GitHub Actions deploys with it, and then the scopes are spelled out: Cache Purge for the admin CDN purge, Workers Scripts:Read for the zone lookup behind it, and Queues:Edit because Cloudflare puts the queue message endpoints behind Edit and returns 403 otherwise, with the note that queue backlog metrics use the SCHEDULER_QUEUE binding rather than this token. A Cloudflare zone id is optional, because the purge resolves the zone from the Workers domain of SITE_DOMAIN, and setting it lets you drop the Workers Scripts:Read scope entirely.

## Database, validation and the data layer

The database is Cloudflare D1 with Drizzle as the query layer, and the advertised properties are type-safe database operations, automatic migration generation, SQLite for local development, and type-safe queries. The manifest has a db:generate script that runs drizzle-kit generate, and a db:migrate:dev script that applies migrations locally against the named database.

Validation is handled by Valibot and React Hook Form, with type-safe form validation on both sides, server-side validation, client-side validation, input sanitisation, real-time validation and form state management. The same Valibot schemas are reused elsewhere, which is the point of the public API design described below.

The developer experience section lists type-safe environment variables, Cloudflare types generation through wrangler types with an env file, Oxlint configuration, co-located Vitest unit tests, Cloudflare Workers Vitest integration tests, and Vitest with Playwright end-to-end tests. The repository has three separate Vitest configuration files at the root, one each for unit, integration and end-to-end runs, and the scripts section wires them to test:unit, test:integration and test:e2e, with the integration runner going through a node script rather than Vitest directly.

The development scripts also include a clean target that removes the Vite cache directories, the dist output and the worker build directories, which is a hint at how many build outputs the Vinext and Vite pipeline produces.

## Team billing, the public API and the MCP server

The billing section is built around team subscription plans, with per-team plans of Free, Pro and Enterprise defined in code, embedded Stripe Elements for checkout so there is no redirect to hosted pages, and a webhook-driven subscription lifecycle in which Stripe is the source of truth. There are in-app plan changes and cancellation, a Stripe Customer Portal for payment methods, invoices and billing details, plan-based entitlements and feature gating such as seat limits, and a one-command Stripe setup script.

The AI-agent platform section is the most distinctive part. It offers a versioned public REST API built with Hono that reuses the app's own service layer, and an OpenAPI 3.1 document generated from the same Valibot schemas the server validates with. The API reference is server-rendered with client-side search, with no spec-viewer bundle, plus authentication and error-code guides.

Users and teams get API keys with scopes, optional expiry and one-time secret display, and there is an OAuth 2.1 authorization server with PKCE, dynamic client registration and a consent screen. The remote MCP server derives its tools from the OpenAPI document, so there is no hand-written tool list, and there are connect guides for Claude Code, claude.ai, ChatGPT, Cursor, VS Code, Codex, Antigravity and Grok CLI, along with self-service revocation from the settings page and an admin view of registered OAuth apps.

Deriving the MCP tools from the OpenAPI document is the design decision worth pulling out. It means an API change automatically becomes a tool change, and the cost is that the tool surface is exactly as good as the API surface.

## The CMS, the UI and the deployment pipeline

The content management system is config-driven, with collections for blog and docs content, a TipTap editor with markdown paste and copy, tables, code highlighting and alert blocks, a docs navigation builder with managed public URLs, and a media library backed by R2 uploads with alt text editing and featured images. There are tags and categories with entry usage tracking, draft, published, archived and scheduled workflows, version history per entry, KV-backed entry caching with maintenance actions, and full-text docs search. AI-assisted SEO description generation is included, along with blog, docs, sitemap.xml and JSON-LD schema rendering, markdown views for public pages through a .md URL suffix or an Accept: text/markdown header, and an llms.txt index for the API specification, the MCP endpoint and the docs tree.

The interface is Tailwind CSS with Shadcn UI components, dark and light modes, responsive design, loading states, toast notifications, a settings dashboard, a landing page, profile settings and form validation states.

Deployment runs on GitHub Actions, with automatic deployments, environment variable management, database migrations, a comprehensive pipeline, cache purging, type checking, integration tests, end-to-end tests and deploy size tracking. The manifest has a metrics:report script and a metrics:ttfb script that measures time to first byte, and a deploy script that first runs a site URL check and then deploys with vinext-cloudflare deploy.

The repository root is unusually instrumented for a template, with an AGENTS.md, a CLAUDE.md, a .claude directory, a .cursor directory, an .agents directory, an opencode.json and a metrics directory, which tells you the author expects AI coding agents to work in this codebase.

## Conclusion

The Cloudflare Workers SaaS Template fits a team that wants a working SaaS on Workers quickly, with authentication, billing, an API and a CMS already built rather than planned, and that accepts Vite and Vinext instead of the standard Next.js compiler. It does not fit a team that needs the full Next.js feature set, since Vinext is an experimental reimplementation of the public API surface and framework-sensitive behaviour must be checked. Before building on it, run the checks the README names, vinext check, the typecheck, the lint and the build, and plan for the fact that a generated project is your code from the first commit, so upstream template improvements arrive as diffs you have to merge by hand.

## FAQ

### What is Vinext and how does it relate to Next.js?

Vinext is Cloudflare's experimental implementation of the public Next.js API surface on top of Vite, so a Next.js App Router app keeps its App Router patterns, React Server Components, route handlers and next/* imports while using Vite as the build and dev toolchain. It is not a fork of Next.js and is not affiliated with Vercel.

### How do I develop and deploy this template?

`pnpm dev` starts the Vinext development server, `pnpm build` produces the Vinext and Vite production output, and `pnpm deploy` uses vinext-cloudflare deploy to build and deploy the Worker. There is also a deploy:dryrun script that builds and runs wrangler deploy with the outdir and dry-run flags.

### What authentication and session handling does the template use?

Authentication is built on Lucia Auth, with email and password sign in and sign up, WebAuthn and passkey support, Google OAuth single sign-on, forgot and change password flows, email verification, and session management stored in Cloudflare KV. There are session listing and management screens, protected routes and layouts, rate limiting on the auth endpoints and Turnstile captcha integration.

### How does the public API relate to the MCP server?

The versioned public REST API is built with Hono and reuses the app's own service layer, with an OpenAPI 3.1 document generated from the same Valibot schemas the server validates with. The remote MCP server derives its tools from that OpenAPI document rather than a hand-written list, and there are OAuth 2.1 keys with PKCE, dynamic client registration and a consent screen.

### What database and validation stack does the template use?

Cloudflare D1 with Drizzle for the database, with automatic migration generation, SQLite for local development and type-safe queries. Validation is handled by Valibot and React Hook Form with type-safe validation on both the client and the server, input sanitisation and real-time validation.

## Sources

- [Issues](https://github.com/LubomirGeorgiev/cloudflare-workers-nextjs-saas-template/issues)
- [License: MIT](https://github.com/LubomirGeorgiev/cloudflare-workers-nextjs-saas-template/blob/main/LICENSE)
- [LubomirGeorgiev/cloudflare-workers-nextjs-saas-template on GitHub](https://github.com/LubomirGeorgiev/cloudflare-workers-nextjs-saas-template)
- [Project website](https://nextjs-saas-template.lubomirgeorgiev.com/sign-up)
- [README](https://github.com/LubomirGeorgiev/cloudflare-workers-nextjs-saas-template/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lubomirgeorgiev-cloudflare-workers-nextjs-saas-template
