Getting started

From git clone to a running app in about 5 minutes.

You need: Node 24 or newer, git, and a PostgreSQL database (Neon has a free tier).

A terminal runs git clone, npm install and npm run dev, then the app opens at localhost:3000
Steps 1 and 2 on a fresh clone: the page that opens lists what is left.

1. Clone and install

Terminal
git clone https://github.com/openstarterkit/nextjs-saas-starter-kit.git
cd nextjs-saas-starter-kit
npm install

GitHub down, or not on GitHub? The same repository is mirrored on GitLab, with the same commits and tags:

Terminal
git clone https://gitlab.com/openstarterkit/nextjs-saas-starter-kit.git

Recent versions of npm end the install by listing scripts they skipped, from Prisma and unrs-resolver, and suggest npm approve-scripts. That is expected: npm no longer runs a dependency's install scripts unless you allow them, and the kit does not need these two. The step that matters, prisma generate, runs from the kit's own postinstall. There is nothing to approve.

2. Start it

Terminal
npm run dev

Open http://localhost:3000. There is no database yet, so the page lists the steps left and marks the one you are on. It appears in development only, until the database is ready.

3. Create a database, then fill .env.local

Create a PostgreSQL database and copy the connection string it gives you. On Neon that is the pooled one, and it ends with ?sslmode=require: change that to ?sslmode=verify-full, the stricter mode, or Node prints an SSL warning at every start.

Terminal
cp .env.example .env.local      # Command Prompt on Windows: copy .env.example .env.local

Two values are enough for the first run:

.env.local
DATABASE_URL="postgresql://..."   # the connection string from your database
AUTH_SECRET="..."                 # any random value; generate one with the command below
Terminal
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"

Paste what it prints between the quotes of AUTH_SECRET.

Leave DIRECT_URL as it is: the kit does not read it, and it ships in the example only because some hosts set it for you.

Everything else (OAuth, Stripe, email) can wait: the kit degrades gracefully and each feature turns on when its variables are set. The full reference is in Configuration.

4. Create the tables

Terminal
npx prisma migrate deploy   # applies the committed migrations
npx prisma db seed          # six example plans, one inactive (edit prisma/seed.ts later)

Both read .env.local, the same file the app reads.

5. Sign in

Restart npm run dev and open the site again. Click Sign in: in development the login page has a Dev Login (Admin) button, which needs no OAuth app and lands you in the dashboard as an admin.

6. Next steps

  • Real sign-in methods (Google, GitHub, magic link, email + password): Configuration and Authentication
  • Payments and webhooks: the Stripe section of Configuration
  • Make it yours: your brand lives in src/config/site.ts and src/components/logo.tsx; swap those two files and the whole app (metadata, navbar, footer, emails, legal pages) follows
  • Ship it: Deployment

7. Your own code, in TypeScript or JavaScript

The kit is written in strict TypeScript, and that is where its checks live: the sign-in, billing and database code you build on is typed and tested. Your own code doesn't have to be. The pages and components you add can be plain JavaScript, .js or .jsx files next to the kit's .ts ones. They import the kit's components, prisma and the rest as they are, and npm run build, npm run lint and npx tsc --noEmit pass with them, because the kit's tsconfig.json has allowJs.

JSX
// src/app/(dashboard)/dashboard/reports/page.jsx
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { prisma } from "@/lib/prisma"

export default async function ReportsPage() {
  const plans = await prisma.plan.count()
  return (
    <Card>
      <CardHeader>
        <CardTitle>Plans</CardTitle>
      </CardHeader>
      <CardContent>{plans}</CardContent>
    </Card>
  )
}

The page sits in the dashboard, so it is already behind sign-in. When a file grows, rename it to .tsx: TypeScript starts checking it and your editor shows what to fix. Nothing else changes.

Star on GitHub

Bookmark it with a

Need help?