Installation
Set up Launch Now locally, from cloning the repository to signing in to your first account.
This page walks you through running Launch Now on your machine: install the dependencies, configure the environment, create the database tables, seed the plans and start the development server.
System requirements
Before you start, make sure you have:
- Node.js 22. This is the version the CI workflow uses (
.github/workflows/ci.yml). - pnpm 12.4.1. The version is pinned in the
packageManagerfield ofpackage.json. If you have Corepack enabled (corepack enable), the right version is picked up automatically. - A PostgreSQL database. Neon works out of the box, as does any local or hosted Postgres.
- A Stripe account in test mode, and optionally the Stripe CLI to receive webhooks locally.
- A Resend account to send sign-in codes and other emails.
- An S3-compatible bucket for avatars and logos (Cloudflare R2, AWS S3, MinIO…).
- GitHub and Google OAuth apps for social sign-in.
Good to know: The environment is validated at startup, and every service above has required variables. See Environment variables for what each one does and how to get it.
Set up the project
Clone the repository
Clone the repository into a new folder and move into it:
git clone https://github.com/anthonyRanivoarison/app.launch.now.git my-saas
cd my-saasInstall dependencies
pnpm installpnpm-workspace.yaml allows the build scripts of esbuild, simple-git-hooks and unrs-resolver
to run. simple-git-hooks installs the Git hooks defined in package.json: pnpm lint before each
commit and commitlint on each commit message.
Create your .env file
Copy the example file and fill in real values:
cp .env.example .envUse .env rather than .env.local: the database and Stripe scripts load variables with
dotenv/config, which only reads .env.
At minimum, set DATABASE_URL, BETTER_AUTH_SECRET, the Resend, OAuth, S3 and Stripe keys.
Generate the auth secret with:
openssl rand -base64 32The full list is in Environment variables.
Run the database migrations
Create the tables by applying the SQL migrations in drizzle/:
pnpm db:migrateThis runs drizzle/migrate.ts, which uses Drizzle's migrator against DATABASE_URL.
Do not use pnpm db:push. It is disabled on purpose and only prints a message: Neon does not
support drizzle-kit push. Change the schema, then run pnpm db:generate and pnpm db:migrate.
Create the Stripe products
With STRIPE_SECRET_KEY set to a test key, create the Pro and Ultra products and their monthly
prices:
pnpm stripe:productsThe script is idempotent: it looks prices up by their lookup key (pulse-pro-monthly and
pulse-ultra-monthly, built from siteConfig.slug) and only creates what is missing. At the end it
prints the price IDs to copy into .env:
=== Copy these into your .env ===
STRIPE_PRO_PRICE_ID=price_...
STRIPE_ULTRA_PRICE_ID=price_...A plan without a price ID is not offered for checkout, so set both.
Seed the plans
Insert the Free, Pro and Ultra plans into the plan table. The pricing page and the Stripe plugin
read them from there:
pnpm db:seed:plansIt upserts by plan name, so you can run it again after editing scripts/seed-plans.ts.
Seed the demo account (optional)
If you set DEMO_EMAIL and DEMO_PASSWORD (at least 8 characters), you can create a shared demo
account:
pnpm db:seed:demoThis creates a verified demo user, a "Demo Workspace" organization owned by it, three fake members and a few pending invitations. When both variables are set, the sign-in page shows a demo sign-in button, and destructive actions (deleting the account, changing the password, leaving or deleting the organization…) are blocked for that account.
Skip this step for a real product. pnpm reset-project removes the demo account code entirely.
Forward Stripe webhooks (optional)
To test checkout locally, forward Stripe events to the webhook route with the Stripe CLI:
stripe listen --forward-to localhost:3000/api/webhook/stripeCopy the whsec_... signing secret it prints into STRIPE_WEBHOOK_SECRET, then restart the dev
server.
Start the development server
pnpm devOpen http://localhost:3000. You should see the Pulse marketing homepage.
Sign in for the first time
Go to /auth/signup and create an account with an email one-time code, GitHub or Google. New
accounts land on /auth/onboarding, then on /dashboard.
Public password sign-up is disabled (emailAndPassword.disableSignUp in lib/auth.ts): the password
flow only exists for the shared demo account. Your users sign in with a code sent by email or with
OAuth.
Good to know: Sign-in codes are sent through Resend. Until you verify a domain in Resend, it only delivers to the address of your own Resend account, so sign up with that address first.
Make yourself a platform admin
The admin panel at /admin is only available to users whose role column is admin. For the first
admin, set it directly in the database, for example with Drizzle Studio:
pnpm db:studioOpen the user table, set role to admin on your user and reload the app. From then on, you can
promote other users from the admin panel.
Useful scripts
| Command | What it does |
|---|---|
pnpm dev | Start the Next.js dev server. |
pnpm check | Run ESLint, the TypeScript compiler and Knip. |
pnpm format | Format the code with Prettier. |
pnpm db:generate | Generate a migration from changes to drizzle/auth-schema.ts. |
pnpm db:migrate | Apply pending migrations. |
pnpm db:studio | Open Drizzle Studio to browse the database. |
pnpm email:dev | Preview the React Email templates in emails/. |
pnpm legal:check | List legal config fields that still hold a TODO. |
pnpm resource:generate | Scaffold a CRUD feature from a spec. |
pnpm reset-project | Remove the demo code and start from a clean slate. |
See Scripts for the full reference.