Changelog

All notable changes to OpenStarterKit are documented here. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

πŸ’‘ OpenStarterKit is free and open source (MIT). It ships continuously: pull main to get every update and fix.

v1.5.0Latest

August 8, 2026

πŸ”Ž SEO foundations & runtime. The pages that matter most were the least looked after: the home page and /pricing had no canonical, /pricing had no heading at all, and structured data existed only inside blog posts. This release fixes the foundations every page stands on, moves the supported runtime to Node 24, and clears two broken-link bugs.

Added

  • Canonical URLs on the home page, /pricing, /blog and /docs. Until now only blog posts had one, and it is the protection that matters most when a demo deployment mirrors the site it showcases. All of them are built from NEXT_PUBLIC_APP_URL
  • Structured data for the site, not only for articles: Organization, and FAQPage on the home page generated from the same questions you edit in src/components/landing/faq.tsx, so answering them for your product updates both at once
  • An H1 on /pricing, which had two H2s and no heading of its own: an error for search engines, and a page with no title for anyone using a screen reader. The pricing section takes the heading role on its own page and stays an H2 on the landing, with no visual change
  • A description of its own for /pricing, which until now inherited the site-wide one and repeated the home page in search results
  • NEXT_PUBLIC_SEO_TITLE: the title used in <title> and in search results. Unset, it stays name | tagline. Set it when the words people search for are not the claim you want readers to see, and the tagline keeps its job on the page
  • NEXT_PUBLIC_MAINTAINER_NAME and NEXT_PUBLIC_MAINTAINER_URL: who builds the product, shown on the About page. The section hides when the name is unset, and the URL is optional
  • npm audit in CI, set at critical. It runs last on purpose: a new advisory is not a defect of the commit being tested, so it must never hide the result of lint, tests and build
  • A SEO section in docs/configuration.md, covering what the kit already does on its own and the one variable you have to set in production

Changed

  • Node 24 is the supported runtime, now declared in engines, which the kit never did before. Node 20 reached end of life in April 2026. The code still runs on it, so nothing breaks today: what changed is the version we support and test against
  • TypeScript 6. Not 7, which Next.js does not yet support without an experimental flag that would end up in your project too
  • GitHub Actions updated from v4 to v7, and @types/node, @types/react, @types/react-dom and @types/pg moved up

Fixed

Both of these have been on main since 3 August and are already live on the showcase, but they were never part of a tagged release. If you cloned at v1.4.1 you do not have them, so they are listed here.

  • Relative links on the changelog page returned 404. The docs pages already translated links written for the repository, the changelog page did not, so ./docs/blog.md and ./README.md were dead ends. That logic now lives in src/lib/markdown-links.ts and both pages use it, taking the file's own directory into account: the same href means different things from docs/ and from the root
  • Anchor links landed on the right page and the wrong section. A heading like "Branding & theming" becomes branding--theming on GitHub and branding-theming here. Anchors are now translated for links that stay on the site, and left alone for links that point at GitHub

Notes

  • No database migration. Every new variable is optional, and with none of them set the kit behaves exactly as before
  • Set NEXT_PUBLIC_APP_URL in production. Canonical URLs are built from it, and unset it falls back to localhost, which is worse than having no canonical at all
v1.4.1

August 3, 2026

πŸ”’ Security patch. Auth.js moves up to clear a critical advisory, together with the first weekly batch of dependency updates.

Security

  • Critical advisory in @auth/core (up to and including 0.41.2): a malformed Authorization: Bearer header makes getToken() throw an uncaught exception. Cleared by moving to next-auth@5.0.0-beta.32 and @auth/prisma-adapter@2.11.3, which pin @auth/core@0.41.3 between them, so a single copy is installed instead of two. If you cloned before this release, pull and run npm install
  • npm audit is now clear of every advisory that has a real fix. What remains lives inside Next.js's own dependency tree (postcss, sharp) and clears when Next ships an update, not when you run npm audit fix: see Security

Changed

  • Dependencies updated: Next 16.2.12, React 19.2.8, Prisma 7.9.1, Stripe 22.4.0, Resend 6.18.1, Radix UI and lucide
  • Stripe API version moved from 2026-05-27.dahlia to 2026-07-29.dahlia to match the SDK. If you pinned the previous one deliberately, src/lib/stripe.ts is the line to change back
  • The README no longer advertises "0 High/Critical audit". A count like that is a snapshot that goes stale on its own, so it now describes the practice instead of a number

Notes

  • No database migration, no new environment variables
  • The dependency updates arrived as five grouped Dependabot pull requests. Two failed CI, and both were real: the Auth.js split above, and the Stripe API version. This is what the test suite added in 1.4.0 is for
v1.4.0

August 3, 2026

πŸ§ͺ Testing & Trust. The kit now proves itself: unit, integration and end-to-end tests, environment validation that stops a half-configured deployment at boot instead of at the first payment, a health endpoint with a release smoke that catches a deploy serving the previous build, and grouped dependency updates. Public demos reset themselves on a schedule, and the kit ships looking more like an example to rewrite and less like our product.

Added

  • Test suite: Vitest over the logic in src/lib (rate limiter, password policy, the blog, docs and changelog parsers, the environment schema, the pure parts of billing) plus the two routes worth guarding. The Stripe webhook is exercised with real signatures generated by Stripe's own SDK, so a forged, tampered or replayed request is proven never to reach the database writes behind it. 82 tests, npm test. See Tests
  • End-to-end tests: Playwright on the two flows that cost money when they break, signing up and starting a checkout. Chromium only, and deliberately outside npm test and CI, because they need a database and a 115 MB browser binary that a clone should not have to install to run the unit suite. npm run test:e2e
  • Environment validation: a Zod schema checked once at boot from src/instrumentation.ts, reporting every problem at once. It does not make variables mandatory (a fresh clone still starts with nothing but a database): it stops the configurations that are half done, such as a Stripe key with no webhook secret, a Resend key with no sender, half an OAuth pair, or a missing AUTH_SECRET in production. Bypass with SKIP_ENV_VALIDATION="true"
  • Health endpoint: GET /api/health reports the running version, the deployed commit, the environment and whether the deployment is a demo. Uncached by design
  • Release smoke: npm run smoke -- <url> [--expect-version 1.4.0], ten read-only checks against a live deployment, including the version comparison that catches a deploy which reported success while still serving the previous build. Every request is a GET, so it is safe against production
  • Coverage: npm run test:coverage, with the current figures and the reasoning about coverage badges documented in the README
  • Dependabot: weekly npm updates grouped by area (Next, React, Prisma, UI, everything else) so they arrive as a handful of pull requests instead of a dozen, majors one at a time, GitHub Actions monthly. Cadence documented in the README
  • Demo auto-reset: a daily Vercel cron at 04:00 UTC reseeds a public demo so shared accounts stop drifting, behind two independent guards (DEMO_MODE must be "true", CRON_SECRET must match, and an unset secret refuses rather than defaults to open)
  • .vercelignore: keeps .env* and the dependency tree out of CLI deploys. Note that when this file exists Vercel uses it instead of .gitignore, not in addition to it

Changed

  • CI now runs the test suite alongside lint and build, on every push and pull request to main
  • The logo mark ships as a plain hexagon, and the favicon is generated as its miniature so the two always match. The bolt was our symbol, and a clone should not ship wearing it
  • The example landing is smaller on purpose: 6 feature cards instead of 9, 4 FAQ entries instead of 6, each covering a different area. They read better as something to rewrite than as a finished feature list to inherit
  • The dashboard and admin shells now use the same maximum width as the public pages, so cards stop stretching to the full width of a large screen
  • The waitlist copy no longer promises a weekly email, in the app and in the roadmap alike. A cadence written in a welcome email is one the subscriber keeps in their inbox: promise news, then send news
  • SECURITY.md and .github/FUNDING.yml are no longer part of the kit. They pointed at our security contact and our tip jar, which is wrong the moment the repository is yours. Reports about the kit itself go through our security policy; for your app, write your own

Fixed

  • Unknown URLs rendered the sign-in redirect instead of a 404. The proxy went from an allowlist of public routes to a denylist of private ones, so a typo like /doc reaches the router and your 404 page. Nothing is opened up: every private area already gates itself server-side
  • The docs index turned ## DATABASE_URL into "DATABASEURL", on documentation that explains 34 environment variables. Underscores are now stripped only where CommonMark treats them as emphasis. Verified across all 58 real headings: no published anchor changes
  • The admin waitlist table overflowed on mobile, dragging every card off screen with it. It now falls back to cards below md, and the two shell layouts get min-w-0 so a wide child scrolls inside its own container instead of stretching the whole column
  • Demo deployments are no longer indexable: noindex on the demo, an empty sitemap and no Sitemap: line in robots.txt, so a demo cannot compete with the site it showcases
  • The kit's own site listed /terms and /cookies in its sitemap while its footer deliberately hid both, submitting placeholder pages for indexing. Your app still ships all three pages

Notes

  • No database migration in this release
  • Env: new optional CRON_SECRET, only meaningful on a demo deployment
  • New dev dependencies: vitest, @vitest/coverage-v8, @playwright/test
v1.3.0

July 24, 2026

πŸ“ Content & SEO. A file-based blog, technical SEO, a pre-launch waitlist and a spam-safe contact form. The kit now ships agent instructions so your AI assistant is productive on day one, and goes fully brand-neutral so rebranding is one config or env away.

Added

  • Theming and instant rebrand: the kit now ships brand-neutral, with a placeholder name and a clean black + grayscale theme. Make it yours from src/config/site.ts and the color tokens in globals.css, or set the new NEXT_PUBLIC_BRAND_* env vars to change name, logo accent and colors with no code changes. The gradient, glow, Open Graph images and emails all follow your accent automatically. See Configuration
  • Blog: file-based MDX blog at /blog with categories, per-category pages, an RSS feed at /blog/rss.xml, reading time, optional cover images and draft support. Writing a post is a Markdown file and a commit, no database. Six example posts included. See the blog guide
  • Newsletter waitlist: double opt-in signup (Zod + honeypot + per-IP and per-email rate limit), branded confirmation and welcome emails, one-click unsubscribe, optional Resend Audience sync for sending Broadcasts, and an admin view with counts and a CSV export that doubles as the consent record. Powers the Pro pre-launch waitlist on the pricing page. See the newsletter guide
  • Contact form: /contact with Zod validation, a honeypot, per-IP rate limiting and a privacy notice, delivered to the owner via Resend with the sender set as reply-to
  • Technical SEO: sitemap.xml and robots.txt generated from the real routes and blog content, dynamic Open Graph images for pages and posts (next/og), and Article JSON-LD on posts
  • Marketing pages: an /about scaffold and the /contact page, linked from the navbar and footer
  • AI-ready: ships agent instructions for Claude Code, Cursor and Copilot, with AGENTS.md as the single source and .cursor/rules/ and .github/copilot-instructions.md pointing to it
  • Shared rate limiter: checkRateLimit gains a per-IP key helper and now guards the newsletter, contact and signup endpoints

Changed

  • The Pro pricing card now opens the waitlist signup instead of a mailto contact link
  • Blog and Contact added to the navbar and footer navigation

Notes

  • One additive migration: add_newsletter_subscriber; run npx prisma migrate deploy
  • Env: new optional RESEND_AUDIENCE_ID for the newsletter Audience sync (the database list works without it)
  • New dependencies: next-mdx-remote and gray-matter for the blog
v1.2.0

July 16, 2026

πŸ’³ Payments & polish. The billing pillar is complete: one-time payments, multiple tiers, usage-based example. Plus onboarding and a public changelog.

Added

  • One-time payments: Stripe Checkout in payment mode with a new Purchase model, idempotent webhook handling (replay-safe on the PaymentIntent), refund handling via charge.refunded, purchase confirmation email, and invoices enabled on one-time checkouts
  • Multiple pricing tiers: plan cards are driven by the Plan table; monthly and yearly variants of a tier pair up into one card (by slug convention) and the Monthly/Yearly toggle swaps only the price, animated and always shown as its monthly equivalent with a "billed yearly" note; the seed now ships 6 example plans (Starter and Pro in monthly and yearly variants, Lifetime, and an inactive metered example)
  • Usage-based billing example: recordUsage() helper on Stripe Billing Meters, plus a new billing guide covering subscriptions, one-time payments, usage-based metering and local testing
  • Onboarding: a dismissable "Get started" checklist on the dashboard (items derived live from your data) and toasts on return from Stripe Checkout (success and canceled)
  • Public /changelog page: this file rendered on the site with a version badge per release, linked in the navbar (after Docs) and in the footer
  • Demo pricing triad: in demo mode the homepage, /pricing and the in-app billing grid all show the same Starter / Pro / Enterprise triad driven by the Plan table, closed by an example Enterprise "Contact us" card that opens the contact dialog with a pre-filled subject (PlanCards gains a ctaHref mode for public pages and an optional contactCard slot for a sales-led tier)
  • Session revocation: a password reset now invalidates other active sessions within about a minute (sessionVersion claim with a throttled DB check)
  • Entitlement helper: getEntitlement() in src/lib/billing.ts resolves lifetime vs subscription vs free, the pattern to copy for gating your own features

Changed

  • Checkout API hardened: valid requests require an active Plan price, and users with an active subscription or lifetime purchase get a clear error pointing to the Customer Portal instead of a second checkout
  • The demo banner now stays pinned above the navbar while scrolling, so the "jump into the app" call to action is always visible on the demo
  • Upgrade button requires an explicit price and surfaces errors as toasts
  • Copy polish across the landing, dashboard, auth and legal pages

Fixed

  • Mobile menu: hash links now scroll to the section instead of bouncing
  • CSS mask uses the standard property alongside the -webkit- prefix

Notes

  • Two new migrations (both additive): add_one_time_payments and add_session_version_and_onboarding; run npx prisma migrate deploy
  • Env: new STRIPE_STARTER_PRICE_ID, STRIPE_LIFETIME_PRICE_ID, STRIPE_METERED_PRICE_ID; removed NEXT_PUBLIC_STRIPE_PRO_PRICE_ID (price IDs never needed to be public)
  • Sessions issued before this release stay valid: the new session claim is backfilled without logging anyone out
v1.1.0

July 10, 2026

πŸ” Auth expansion & docs. Four ways to sign in, one account. Plus a real documentation set.

Added

  • Magic link sign-in: passwordless one-time links by email (Resend), branded with the same template as the transactional emails, valid 15 minutes
  • Email + password: production-grade credentials with signup, email verification via magic link, bcrypt hashing (cost 12), generic errors (no user enumeration), rate limiting
  • Password reset: full forgot/reset flow with single-use SHA-256-hashed tokens, 30-minute expiry
  • Account linking: automatic linking across Google/GitHub/email (verified-email providers), plus a "Sign-in methods" card in Settings to connect/disconnect providers and set or change the password, with a lock-out guard
  • Auth pages: new /signup, /verify-request, /forgot-password, /reset-password
  • Documentation: new docs/ folder (getting started, configuration, authentication, deployment), rendered on the site at /docs with sidebar navigation; the Markdown files are the single source of truth

Changed

  • Login page now offers email + password and magic link alongside OAuth (hidden in demo mode)
  • Settings page shows the real linked providers instead of a hardcoded label

Notes

  • New dependency: bcryptjs (pure JS, no native build steps)
  • New migration: add_password_auth (User.passwordHash + PasswordResetToken); run npx prisma migrate deploy
  • JWT sessions are unchanged; sessions issued before a password reset stay valid until expiry (documented in docs/authentication.md)
v1.0.0

June 25, 2026

πŸš€ First public release. The complete, production-ready SaaS core, free & open source.

Added

  • Framework: Next.js 16.2 (App Router, Turbopack) + TypeScript strict
  • Styling: Tailwind CSS v4 with native CSS variables + dark mode (system detection + persist)
  • Auth: Auth.js v5 with Google & GitHub OAuth, route protection, session management
  • Database: Prisma 7 + PostgreSQL schema (User, Account, Session, Plan, Subscription, Project) with driver adapter
  • Payments: Stripe Checkout, Customer Portal, and webhooks (Stripe API 2026-05-27)
  • User dashboard: overview, billing with Stripe invoice history, profile settings (Zod-validated server actions)
  • Projects: example single-tenant CRUD resource (schema, server actions with ownership checks, list/detail/forms)
  • Admin panel: user list with search & pagination, MRR/users/subscriptions metrics, role management
  • Emails: Resend transactional emails (welcome, subscription confirmation, cancellation)
  • Design system: Radix-based components (Button, Card, Badge, Input, Table, dialog, dropdown, tabs, tooltip…) + cn utility
  • Landing page: Hero, tech stack strip, Features, Pricing, FAQ, Footer
  • Security: security headers, SECURITY.md, and a CI workflow (lint + build)
  • Attribution: optional "Built with OpenStarterKit" badge, removable via env flag
  • DX: 1-click Vercel deploy button, complete README, .env.example, dev-only credentials login
  • License: MIT (use in unlimited projects, commercial included)

Notes

  • Production build: 0 TypeScript errors, 0 ESLint errors, 14 routes
  • Stack chosen best-of-breed with no vendor lock-in: every component is swappable