Next.jsReactSaaSStarter

bachs-nextjs-saas — Next.js SaaS Template

By bachsdev

A local development subscription template built on Next.js App Router and the Bachs SDK, demonstrating hosted checkout, webhook verification, access control and a customer billing portal.

Explore the design

Compare the page layouts and mobile experience. Open any screenshot for a closer look.

2 previews
Desktop homepage1 / 2
Desktop captureTop of page

Actual browser screenshot from the verified demo.

All pages & views 2

Screenshots show visual appearance; interactive behavior may differ.

Recorded 2026-10-16View source

What stands out

A quick read of the recorded project description.

01

Uses the official @bachs/sdk for hosted checkout, product setup, customer portal and webhook verification

02

The checkout API maps plans server-side and saves persistent operation keys, ignoring client-side price and product IDs

03

The webhook route uses the SDK to verify the raw request body and event envelope, and lib/webhooks.ts skips duplicate and older events

04

lib/store.ts commits state together with processed event IDs to a local file using serialized, atomic replacement

05

Provides npm run verify to run unit/route tests, TypeScript checks, production build and HTTP smoke tests

06

Includes AGENTS.md, CLAUDE.md and a standalone Bachs skill file for AI-assisted development

Template Details

This is a Next.js App Router starter template for demonstrating Bachs monthly and annual subscription flows, using the official @bachs/sdk for checkout, product setup, customer portal and webhook verification. The README explicitly states that it is a local development starter template: all visitors share one demo user, billing data is stored in a local JSON file, and authentication and storage must be replaced before deployment; the demo authentication rejects live API keys. The template includes modules such as the checkout API, webhook handling, access control, customer portal session creation and a success page, and provides verification scripts for unit tests, type checking, production build and HTTP smoke tests. The README also records that a manual sandbox check passed on October 9, 2026, but subsequent billing cycle renewals have not been verified.

Next.jsSaaSStarter

Is it right for your project?

Use Cases

  • Experience the complete Bachs subscription checkout, webhook-activated access and customer billing portal flow in a local sandbox
  • Use as a reference project for learning how to integrate Next.js App Router with the Bachs SDK
  • Use as a starting point for building your own SaaS subscription features by replacing authentication, storage and plan configuration
  • Use the built-in tests and verification scripts to check signature, renewal recovery, cancellation and concurrent event handling in the subscription lifecycle

Suitable For

  • Developers who need to understand how Bachs subscription integration works
  • Teams that want to build Next.js SaaS subscription features starting from a local development template
  • People who need a reference implementation for webhook verification, access control and idempotent checkout handling

Getting started & customization

Use these recorded setup notes alongside the repository instructions for your chosen version.

  1. 1

    Requires Node.js 22 or later, a sandbox API key and the Bachs CLI; the key needs products:write, payments:write and customers:write permissions

  2. 2

    After running npm ci, copy .env.example to .env, set BACHS_API_KEY, then run npm run setup:products and put the two printed product IDs into .env

  3. 3

    In a second terminal run npm run listen, copy the printed whsec_ key to BACHS_WEBHOOK_SECRET, then run npm run dev

  4. 4

    Bachs rejects localhost and private IP checkout redirect URLs, so local development does not set a redirect by default; if automatic return is needed, use a public deployment or tunnel and set CHECKOUT_SUCCESS_URL and CHECKOUT_CANCEL_URL

  5. 5

    Each new listen session generates a new signing key, so update .env and restart the app; do not paste keys into chat or commit .env

Read repository instructions

License & source material

Usage conditions & limitations

Free to use · keep license notice

This entry covers the free version under the MIT license in the public repository; the free scope is the code of this version and does not mean external services or third-party assets are free.

Must comply with when using

  • Free use, modification, commercial use and distribution of this version's code are allowed.
  • When distributing copies or substantial portions of the code, retain the original author's copyright notice and the complete MIT license notice.
  • The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.

Additional costs & items to verify

  • Demo images, fonts, icons and other third-party assets must be checked against their respective licenses and cannot be judged solely by the code's MIT license.
  • External services such as domains, hosting, databases, payments or AI may incur additional charges.
  • This is a local development starter template: all visitors share one demo user, and billing data is stored in a local JSON file.
  • Authentication and storage implementations must be replaced before deployment.
  • The demo authentication rejects live API keys, so it cannot be used directly in production.
  • The current 0.0.1 package on npm is only a placeholder; the SDK implementation is packaged in vendor/.
  • Requires Node.js 22 or later, a sandbox API key and the Bachs CLI.
  • The API key needs products:write, payments:write and customers:write permissions.
  • Bachs rejects localhost and private IP checkout redirect URLs even in the sandbox.
  • Each new listen session generates a new signing key; after restarting the listener, update .env and restart the app.
  • Do not paste keys into chat, and do not commit the .env file.
  • When investigating a lost checkout response, stop the app before editing the local .data/store.json file.
  • The smoke tests use dummy keys and fixed API responses and do not perform real Bachs payments.
  • Subsequent billing cycle renewals have not been verified; lifecycle tests use fixed events and cannot prove a real second charge.
  • The local serialization in lib/store.ts only works for a single Node.js process and cannot coordinate multiple instances or serverless storage.
  • The starter template's tests only target the shared demo identity; you must add your own session, authorization and deployment tests.
  • Going live requires creating production products, setting BACHS_ENVIRONMENT=production, using production API URLs and live keys.
View Original Text Basis

Permission is hereby granted, free of charge

Original License Text

**This is a local development starter.** Every visitor shares one demo user,

Original README

and billing data lives in one local JSON file. Replace authentication and the

Original README

store before deploying. Demo authentication refuses live API keys.

Original README

vendor/ so npm ci works before its npm release. The current npm 0.0.1

Original README

You need Node.js 22 or later, a [sandbox API key](https://docs.bachs.io/authentication),

Original README

The key needs `products:write`, `payments:write`, and `customers:write`.

Original README

Bachs refuses localhost and private-IP checkout redirect URLs, even in sandbox.

Original README

Each new `listen` session has a new signing secret. Update `.env` and restart

Original README

the app when you restart the listener. Do not paste keys into chats or commit

Original README

`checkouts` in `.data/store.json`. Stop the app before editing that local file.

Original README

The smoke test uses dummy keys and fixture API responses. It makes no real

Original README

A subsequent billing-cycle renewal remains unverified. Lifecycle tests above

Original README

- Replace `lib/store.ts` with a transactional database. Its local serialization

Original README

- Add your app's session, authorization and deployment tests. This starter's

Original README

Create products in production, set BACHS_ENVIRONMENT=production, use the production API URL and live key, and

Original README
https://github.com/bachsdev/bachs-nextjs-saas/blob/main/LICENSEhttps://github.com/bachsdev/bachs-nextjs-saas/blob/main/README.md

Compiled by DeepSeek based on repository license and README ·2026-10-09. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.

Project checks & description sources

Template Information

Source platforms
GitHub
Documentation and maintenance reference score
More documented · 85 / 100
Technologies
Next.js · React
Website type
SaaS · Starter
How this score is calculated

Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.

What to verify for this project

Repository update recorded
2026-10-09
Screenshot last checked
2026-10-16

A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.

The catalog identifies Next.js as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.

Use a selection guide →

How this description was prepared

AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.

Review declaration: codex-user-requested-batch-review-20261017 · 2026-10-16

Inspect the recorded source material

SHA-256: c8c48b0d73b53905c513962052f1efc5fb5ce6f3fac7a5cc142a839e69815208

2026-10-09T19:52:15.773Z

Source file / repository
# Bachs Next.js SaaS starter

A Next.js App Router starter for monthly and yearly [Bachs](https://bachs.io)
subscriptions using the official [Bachs SDK](https://github.com/bachsdev/bachs-node): hosted checkout, access from verified webhooks, and customer
billing through the Bachs customer portal.

Follow the [SaaS subscriptions walkthrough](https://docs.bachs.io/build/use-cases/saas-subscriptions)
for the payment flow and the [Build with AI subscription workflow](https://docs.bachs.io/build/ai#sell-subscriptions)
for a prompt that adapts it to your app.

**This is a local development starter.** Every visitor shares one demo user,
and billing data lives in one local JSON file. Replace authentication and the
store before deploying. Demo authentication refuses live API keys.

## SDK dependency

This starter imports @bachs/sdk for checkout, product setup, the customer
portal and webhook verification. The tested SDK implementation is packaged in
vendor/ so npm ci works before its npm release. The current npm 0.0.1
package is a placeholder. See [package provenance and the npm transition](vendor/README.md).

## Run in sandbox

You need Node.js 22 or later, a [sandbox API key](https://docs.bachs.io/authentication),
and the [Bachs CLI](https://docs.bachs.io/cli/overview#install).
The key needs `products:write`, `payments:write`, and `customers:write`.

```bash
npm ci
cp .env.example .env
# Set BACHS_API_KEY in .env, then:
npm run setup:products
```

On Windows PowerShell, use `Copy-Item .env.example .env` instead of `cp`.
Copy the two product IDs printed by the setup script into `.env`. You can also
create the recurring products in the Bachs dashboard and save their IDs there.

In a second terminal:

```bash
npm run listen
```

Copy the `whsec_` secret it prints into `BACHS_WEBHOOK_SECRET` in `.env`,
then start the app:

```bash
npm run dev
```

Open http://localhost:3000, click **Subscribe**, and complete the sandbox
checkout using its test controls. Subscription webhooks activate access.
Return to http://localhost:3000 after paying to see access activate. Click
**Manage billing** to open the portal.

Bachs refuses localhost and private-IP checkout redirect URLs, even in sandbox.
The starter leaves checkout redirects unset for local development. If you
want an automatic return, use a public deployment or tunnel and set
`CHECKOUT_SUCCESS_URL` and `CHECKOUT_CANCEL_URL` in `.env`. `APP_URL` remains
the app's own URL; the CLI forwards webhooks without a public webhook URL.

Each new `listen` session has a new signing secret. Update `.env` and restart
the app when you restart the listener. Do not paste keys into chats or commit
`.env`.

## How it works

| File | Responsibility |
| --- | --- |
| `app/api/checkout/route.ts` | Maps the plan on the server, reserves a persistent operation key, and creates checkout. Client prices and product IDs are ignored. |
| `app/api/webhooks/bachs/route.ts` | Uses SDK webhooks.constructEvent to verify the raw body and event envelope, then processes the event. |
| `lib/webhooks.ts` | Saves subscription state; skips duplicates and older events. |
| `lib/store.ts` | Commits state and processed-event IDs together in a serialized, atomic local file replacement. |
| `lib/access.ts` | Decides access. The default gives a grace period while a renewal is past due. |
| `app/api/billing/portal/route.ts` | Creates a fresh session for the demo user's saved Bachs customer. |
| `app/billing/success/page.tsx` | Reads stored access and waits for the webhook; never grants access. |
| `lib/bachs.ts` | Maps app inputs to the official SDK; the SDK handles transport, typed responses and uncertain errors. |

### When a checkout response is lost

The starter saves a checkout attempt before calling Bachs. A repeated click
reuses a confirmed, unexpired checkout. A timeout, 5xx, or failure to save the
response leaves the attempt awaiting confirmation and blocks another POST.

Check the checkout or subscription in Bachs and allow its webhook to arrive.
Keep the stored operation key while investigating. Only after confirming the
original checkout had no effect should you clear that user's entry in
`checkouts` in `.data/store.json`. Stop the app before editing that local file.
In a production implementation, replace this manual step with an authenticated
reconciliation process following the [idempotency guide](https://docs.bachs.io/guides/idempotency).
Do not delete the store or generate a replacement key just because a response
was lost.

## Verification

```bash
npm run verify
```

This runs:

1. Unit and route tests for signatures, secret rotation, checkout and portal
   ownership, access, renewal recovery, cancellation, duplicate and concurrent
   events, failed persistence, and uncertain checkout recovery.
2. TypeScript checks.
3. A production build.
4. HTTP smoke checks against the built Next.js server and a local Bachs API
   fixture, with isolated billing data.

The smoke test uses dummy keys and fixture API responses. It makes no real
Bachs payment. Run the sandbox checkout above to verify a real integration.
CI runs the same gates on Node.js 22 and 24 without secrets.

A manual SDK-backed sandbox check on October 9, 2026 also passed: hosted
checkout and the first payment, a real signed subscription event forwarded
through the CLI after replay, stored access activation, and the signed-in
demo customer's billing portal. The user submitted the simulated card payment.
A subsequent billing-cycle renewal remains unverified. Lifecycle tests above
use fixture events; they are not evidence of a real second charge.

To run an individual gate:

```bash
npm test
npm run typecheck
npm run build
npm run test:smoke  # requires npm run build first
```

## Make it yours

- Replace `lib/auth.ts` with authenticated users and protect billing routes.
- Replace `lib/store.ts` with a transactional database. Its local serialization
  applies to one Node.js process; it cannot coordinate multiple instances or
  serverless storage. Preserve atomic event completion and stale-event checks.
- Set your plans in `lib/plans.ts` and create matching Bachs products. Prices
  displayed in the app should match those products.
- Choose the access policy in `lib/access.ts`.
- Configure the [customer portal](https://docs.bachs.io/guides/customer-portal/overview#configuring-the-portal)
  for card updates and plan switching if needed.
- Add your app's session, authorization and deployment tests. This starter's
  tests exercise a shared demo identity.

## Go live

After replacing the demo components, follow the
[go-live checklist](https://docs.bachs.io/build/use-cases/saas-subscriptions#go-live-checklist).
Create products in production, set BACHS_ENVIRONMENT=production, use the production API URL and live key, and
register the five subscription/invoice events in `npm run listen` on your
production webhook endpoint. Its signing secret differs from the local one.
Production subscriptions are not shared with sandbox.

## Building with an AI assistant

`AGENTS.md` explains the project and checks; `CLAUDE.md` points to it.
[Build with AI](https://docs.bachs.io/build/ai) has three complete workflows
and an optional Bachs skill.

The shared [Bachs skill](skills/bachs/SKILL.md) covers payments, subscriptions and
marketplaces. You can use it in any app, independently of this starter.

For Claude Code, copy skills/bachs/SKILL.md into your app at
.claude/skills/bachs/SKILL.md, then use /bachs followed by what you want to
build. For another tool that supports Agent Skills, install the same file using
its instructions. Prefer no installation? Copy one of the three prompts from
Build with AI; each includes the rules it needs.

## License

MIT. See [LICENSE](LICENSE).
Report a correction

Explore similar templates

Compare previews and descriptions within the same stack and category.