Scripts
Every pnpm script defined in package.json, what it runs, its flags, and when to use it.
Launch Now ships its tooling as pnpm scripts in package.json. Scripts that run TypeScript files use tsx and live in scripts/ (or drizzle/migrate.ts). Most of them load your .env file through dotenv/config, so run them from the project root.
Overview
| Script | Runs |
|---|---|
pnpm dev | next dev |
pnpm build | next build |
pnpm build:deploy | pnpm db:migrate && next build |
pnpm start | next start |
pnpm lint | eslint . |
pnpm format | prettier --write on **/*.{ts,tsx,js,jsx,json,md} |
pnpm format:check | prettier --check on the same glob |
pnpm typecheck | tsc --noEmit |
pnpm knip | knip |
pnpm check | pnpm lint && pnpm typecheck && pnpm knip |
pnpm release | release-it |
pnpm release:dry | release-it --dry-run |
pnpm release:patch | release-it patch |
pnpm release:minor | release-it minor |
pnpm release:major | release-it major |
pnpm commit | git-cz |
pnpm db:generate | drizzle-kit generate |
pnpm db:migrate | tsx drizzle/migrate.ts |
pnpm db:baseline | tsx scripts/db-baseline.ts |
pnpm db:push | Prints a message; does nothing |
pnpm db:pull | drizzle-kit pull |
pnpm db:check | drizzle-kit check |
pnpm db:studio | drizzle-kit studio |
pnpm db:export | drizzle-kit export |
pnpm stripe:products | tsx scripts/stripe-create-products.ts |
pnpm stripe:update-features | tsx scripts/stripe-update-features.ts |
pnpm db:seed:plans | tsx scripts/seed-plans.ts |
pnpm resource:generate | tsx scripts/generate-resource.ts |
pnpm db:seed:demo | tsx scripts/seed-demo.ts |
pnpm reset-project | tsx scripts/reset-project.ts |
pnpm legal:check | tsx scripts/legal-check.ts |
pnpm email:dev | email dev |
Development and build
pnpm dev
Starts the Next.js development server (next dev). Use it for local development.
pnpm build
Creates a production build with next build. It does not touch the database.
lib/env.ts validates environment variables at build time. The CI workflow (.github/workflows/ci.yml) sets SKIP_ENV_VALIDATION=1 so the build can run without secrets.
pnpm build:deploy
Runs pnpm db:migrate, then next build. Use it as the build command on your hosting provider so pending migrations are applied before each deploy.
If DATABASE_URL is not set, the migrate step logs a warning and exits with code 0, so the build still runs.
pnpm start
Serves the production build (next start). Run pnpm build first.
pnpm email:dev
Starts the React Email preview server (email dev, from the react-email package). Use it to preview the templates in emails/, such as emails/otp-email.tsx.
Code quality
pnpm lint
Runs ESLint on the whole project (eslint .). It also runs as a pre-commit hook through simple-git-hooks (configured in package.json).
pnpm format
Formats every ts, tsx, js, jsx, json and md file with Prettier, writing changes in place.
pnpm format:check
Checks formatting without writing anything. CI runs this step and fails on unformatted files.
pnpm typecheck
Runs the TypeScript compiler without emitting files (tsc --noEmit). Run it after moving or deleting code, for example after pnpm reset-project.
pnpm knip
Runs Knip to find unused files, exports and dependencies. The configuration is in knip.json: it treats scripts/*.ts and types/**/*.ts as entry points and ignores components/ui/**, components/spectrumui/**, the script templates and .claude/**.
pnpm check
Runs pnpm lint, pnpm typecheck and pnpm knip in sequence and stops at the first failure. Use it before opening a pull request.
Releases and commits
pnpm release
Runs release-it interactively. The configuration in .release-it.json:
- Generates
CHANGELOG.mdfrom Conventional Commits (@release-it/conventional-changelog, presetconventionalcommits). - Commits with
chore: release v${version}and tagsv${version}. - Creates a GitHub release.
- Does not publish to npm.
Good to know: The public /changelog page does not read CHANGELOG.md. It renders features/changelog/changelog-data.ts. See Content.
pnpm release:dry
Runs release-it --dry-run: shows what a release would do without changing anything.
pnpm release:patch
Releases the next patch version (release-it patch), for example 0.0.1 to 0.0.2.
pnpm release:minor
Releases the next minor version (release-it minor).
pnpm release:major
Releases the next major version (release-it major).
pnpm commit
Opens the Commitizen prompt (git-cz) with the cz-git adapter to write a Conventional Commit message. Commit messages are checked by commitlint (@commitlint/config-conventional) through the commit-msg git hook.
Database
drizzle.config.ts points Drizzle Kit at drizzle/auth-schema.ts and writes migrations to drizzle/. It reads DATABASE_URL from .env. See Database schema for the tables.
pnpm db:generate
Compares drizzle/auth-schema.ts with the last snapshot in drizzle/meta/ and writes a new SQL migration in drizzle/. Run it every time you change the schema, then commit the generated files.
pnpm db:migrate
Applies pending migrations from drizzle/ to the database in DATABASE_URL, using drizzle/migrate.ts (the drizzle-orm node-postgres migrator). Applied migrations are tracked in the drizzle.__drizzle_migrations table.
pnpm db:generate
pnpm db:migrateThe script runs with NODE_OPTIONS='--no-network-family-autoselection' and a 30 second connection timeout. If DATABASE_URL is missing, it prints a warning and exits with code 0 instead of failing.
pnpm db:baseline
Marks migrations as already applied on a database whose tables were created outside Drizzle's journal (for example with drizzle-kit push), so that pnpm db:migrate only runs the newer ones.
| Flag | Required | Description |
|---|---|---|
--until <tag> | Yes | The last migration whose changes already exist in the database, for example 0014_cheerful_silhouette. Must match a tag in drizzle/meta/_journal.json. |
--apply | No | Writes the records. Without it, the script is a dry run and only prints the plan. |
pnpm db:baseline --until 0014_cheerful_silhouette
pnpm db:baseline --until 0014_cheerful_silhouette --applyFor each migration up to --until, the script computes the same SHA-256 hash Drizzle's migrator records and inserts it into drizzle.__drizzle_migrations (creating the schema and table if needed). Migrations already recorded are skipped. It ends by listing the migrations the next pnpm db:migrate will run. It requires DATABASE_URL.
pnpm db:push
Does not push anything. It only prints:
Use db:generate + db:migrate instead. Neon does not support drizzle-kit push.pnpm db:pull
Runs drizzle-kit pull to introspect the database and generate a schema from it. Use it to inspect drift, not as part of the normal workflow.
pnpm db:check
Runs drizzle-kit check to validate the consistency of the generated migrations and snapshots.
pnpm db:studio
Opens Drizzle Studio (drizzle-kit studio), a browser UI to browse and edit the database in DATABASE_URL.
pnpm db:export
Runs drizzle-kit export, which prints the SQL for the current schema without touching the database.
pnpm db:seed:plans
Upserts the three plans into the plan table: free, pro and ultra, with their display name, description, monthly price in cents (0, 1000, 5000), features, limits and sort order. Rows are matched on plan.name, so re-running the script updates them and sets active to true.
Edit the plans array in scripts/seed-plans.ts to change what is seeded. Requires DATABASE_URL.
pnpm db:seed:demo
Seeds the shared demo account. It is idempotent: existing rows are reused or updated.
It requires DEMO_EMAIL and DEMO_PASSWORD (at least 8 characters) and exits with an error if either is missing. It creates or updates:
- The demo user (
Demo User, email verified, onboarding completed) with acredentialaccount whose password is hashed with Better Auth'shashPassword. The password is re-synced withDEMO_PASSWORDon every run. - A
Demo Workspaceorganization (slugdemo-workspace) owned by the demo user. - Three fake members (
demo-member-1@example.invalidasadmin, two others asmember). They have no password and cannot sign in. - Two pending invitations that expire 30 days after the run.
The script writes directly to the database instead of calling auth.api.signUpEmail, because public email/password sign-up is disabled and going through auth would create a Stripe customer.
Good to know: pnpm reset-project removes this script and its package.json entry.
Stripe
Both Stripe scripts read STRIPE_SECRET_KEY and use siteConfig.slug from lib/config/site-config.ts to tag products and build price lookup keys (<slug>-pro-monthly, <slug>-ultra-monthly).
pnpm stripe:products
Creates the paid products and monthly USD prices in Stripe:
| Product | Metadata plan | Lookup key | Amount |
|---|---|---|---|
| Pro | pro | <slug>-pro-monthly | 1000 cents |
| Ultra | ultra | <slug>-ultra-monthly | 5000 cents |
It is safe to re-run: a price with the same lookup key is reused, and an active product with matching app and plan metadata is reused. At the end, it prints the lines to copy into your .env:
STRIPE_PRO_PRICE_ID=price_...
STRIPE_ULTRA_PRICE_ID=price_...Run it once per Stripe account (test mode, then live mode).
pnpm stripe:update-features
Finds each paid product through its price lookup key and updates it with a description, Stripe marketing_features, and features and limits JSON strings in the product metadata. Plans with no matching price are skipped with a warning.
Run it after changing the feature lists in scripts/stripe-update-features.ts. Keep them in sync with scripts/seed-plans.ts.
Code generation
pnpm resource:generate
Scaffolds a CRUD resource with the resource-kit generator (scripts/generate-resource.ts). For each resource, it:
- Appends a Drizzle table to
drizzle/auth-schema.ts. - Writes
lib/<name>-config.tsandlib/<name>-actions.ts. - Writes a form sheet and a table in
features/<name>/. - Writes a list page and a
[id]detail page underapp/(app)/<path>/, plus alayout.tsxfor user-scoped, non-admin resources. - Adds an entry to
lib/resource-kit/manifest.json. - Adds a sidebar item in
components/layouts/nav-configs/.
Generated files are formatted with Prettier when it is installed.
| Flag | Description |
|---|---|
--spec <path> | Reads the resource from a JSON spec file instead of prompting. The file can hold one spec, or { "resources": [...] } for several. |
--force, -f | Overwrites files that already exist. Without it, existing files are skipped. |
Without --spec, the script asks for the name, title, scope (user or organization), admin-only flag, path, Lucide icon and fields interactively.
pnpm resource:generate --spec drizzle/resources/org-projects.json
pnpm db:generate
pnpm db:migrateField types are text, textarea, number, boolean, date, json, email, url, select, password and relation. The names id, userId, organizationId, createdAt and updatedAt are reserved, and adminOnly cannot be combined with the organization scope. A relation field fails unless its target table already exists or is generated in the same run. See drizzle/resources/README.md for every spec option.
pnpm reset-project
Turns the starter into a clean slate. It removes the example CRUD resources, the demo pages and the shared demo account:
- Moves these paths to
examples/(kept as reference, excluded from the build):app/(app)/projects,app/(app)/categories,features/projects,features/categories,lib/projects-actions.ts,lib/categories-actions.ts,app/(app)/orgs/[orgSlug]/org-projects,features/org-projects,lib/org-project-actions.ts,lib/org-project-config.ts,drizzle/resources/org-projects.json,app/(app)/(dash)/demo,lib/demo-actions.ts,features/auth/demo-signin-button.tsxandscripts/seed-demo.ts. - Strips every block between
@reset-remove:startand@reset-remove:endcomments in.tsand.tsxfiles underapp,components,features,libanddrizzle. - Replaces files with the clean versions in
scripts/reset/templates/(the originals are copied toexamples/first). - Removes the
db:seed:demoscript frompackage.jsonand theorgProjectentry fromlib/resource-kit/manifest.json.
| Flag | Description |
|---|---|
--dry-run | Prints the plan and changes nothing. |
--yes, -y | Skips the confirmation prompt (for CI). |
--force | Runs even when the git working tree has uncommitted changes. |
pnpm reset-project --dry-run
pnpm reset-projectThe script plans everything before writing, and refuses to run twice: it writes examples/.reset.json and exits if that file already exists. After a reset, it prints the next steps:
pnpm typecheck
pnpm db:generate
pnpm db:migrate
pnpm resource:generateThe migration drops the example tables (categories, projects, org_projects). Skip both database steps on a brand-new database with no data. Then remove DEMO_EMAIL and DEMO_PASSWORD from your .env files and delete examples/ when you no longer need it.
pnpm reset-project. The generated migration drops the example tables and their data.Legal
pnpm legal:check
Loads your .env files the same way Next.js does, then lists every field in lib/config/legal.ts that still holds a TODO placeholder (using findLegalPlaceholders). It exits with code 1 when some remain, so you can use it to gate a release in CI.
pnpm legal:checkSee Legal pages to fill the configuration.