Launch NowDocs

Configuration

Rename the Pulse demo to your product with site-config.ts, and learn where the rest of the project configuration lives.

Launch Now ships as a demo product called Pulse. Its identity (name, tagline, URL, social links) lives in one file, lib/config/site-config.ts, so turning Pulse into your product is mostly a one-file change. This page covers that file, the other configuration files, and how to remove the demo code with pnpm reset-project.

Site config

lib/config/site-config.ts
export const siteConfig = {
  /** Display name, shown in the UI, metadata and emails. */
  name: "Pulse",
  /** Machine name: API key prefix, Stripe lookup keys and product tags. */
  slug: "pulse",
  tagline: "Product analytics for teams that ship every week.",
  description:
    "Pulse turns every click, signup and upgrade into answers your whole team can act on.",
  url: process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000",
  ogImage: "/opengraph-image",
  links: {
    twitter: "https://x.com/antonio_rnv",
    github: "https://github.com/anthonyRanivoarison/app.launch.now",
  },
  /** Public support address (NEXT_PUBLIC_ so the app sidebar can link to it). */
  supportEmail: process.env.NEXT_PUBLIC_SUPPORT_EMAIL,
  creator: "@antonio_rnv",
  locale: "en_US",
  themeColor: "#09090b",
  geo: {
    region: "FR",
    placename: "Paris, France",
    latitude: "48.8566",
    longitude: "2.3522",
  },
}

The file reads process.env directly rather than lib/env.ts, so it can be imported from client components, tsx scripts and builds that run with SKIP_ENV_VALIDATION.

Fields

FieldUsed for
nameEverywhere the product is named: page titles, auth pages, dashboard, marketing sections, onboarding, emails (appName in Better Auth), manifest, Open Graph image, changelog RSS, legal documents.
slugAPI key prefix (pulse_), Stripe price lookup keys (pulse-pro-monthly) and the app metadata on Stripe products.
taglineHomepage title, marketing brand block and Open Graph image.
descriptionDefault meta description, homepage, manifest, Open Graph image and JSON-LD.
urlmetadataBase, sitemap, robots, changelog RSS, JSON-LD and the product URL in legal pages. Set it with NEXT_PUBLIC_APP_URL.
linksSocial links in the marketing footer and the sameAs list in JSON-LD.
supportEmailThe "Support" link in the app sidebar. Hidden when NEXT_PUBLIC_SUPPORT_EMAIL is empty.
creatorTwitter creator in the page metadata.
localeOpen Graph locale.
themeColorBrowser theme color in the viewport and web manifest.
geoGeo meta tags added by createSeoHead in lib/seo/metadata.ts.

lib/seo/config.ts re-exports siteConfig for older imports; the source of truth stays lib/config/site-config.ts.

Rename the product

Update the site config

Change name, slug, tagline, description, links, creator and geo in lib/config/site-config.ts. Use a lowercase slug without spaces, since it becomes part of API keys and Stripe lookup keys.

Recreate the Stripe products

The Stripe scripts build their lookup keys from slug. After changing it, run the product script again so prices exist under the new keys, and copy the printed IDs into .env:

pnpm stripe:products

Plan features that mention the product name come from scripts/seed-plans.ts, so re-run pnpm db:seed:plans as well.

Changing slug on a live product changes the prefix of new API keys and the lookup keys the scripts search for. Existing keys and prices keep working, but decide on the slug before launch.

Replace the brand assets

Replace the icons and images in public/ (favicon.ico in app/, favicon-16x16.png, favicon-32x32.png, apple-touch-icon.png, the android-chrome-* icons, icon.svg, logo_L.svg) and the marketing screenshots in public/marketing/.

Rewrite the marketing copy

The homepage sections in features/marketing/ (hero, features, steps, testimonials, FAQ, pricing, CTA) contain copy written for Pulse. See Marketing.

Legal pages read your company details from lib/config/legal.ts. List what is still missing with:

pnpm legal:check

See Legal.

Other configuration files

next.config.mjs

next.config.mjs
import { createMDX } from "fumadocs-mdx/next"
 
/** @type {import('next').NextConfig} */
const config = {
  reactStrictMode: true,
  async redirects() {
    return [
      {
        source: "/organizations",
        destination: "/orgs",
        permanent: true,
      },
    ]
  },
  experimental: {
    authInterrupts: true,
  },
}
 
const withMDX = createMDX()
 
export default withMDX(config)
  • createMDX() from Fumadocs compiles the MDX files in content/ for /docs and /blog.
  • authInterrupts enables the forbidden() and unauthorized() functions, rendered by app/forbidden.tsx and app/unauthorized.tsx.
  • The redirect keeps old /organizations links working.

proxy.ts

Next.js 16 renamed Middleware to Proxy. The boilerplate uses it for one feature: when a signed-in user chose "Always open the app", visiting / redirects to /dashboard.

proxy.ts
export const config = {
  matcher: [
    {
      source: "/",
      // Must be a literal (statically analyzed); see OPEN_APP_COOKIE.
      has: [{ type: "cookie", key: "open_app", value: "1" }],
      missing: [{ type: "query", key: "stay" }],
    },
  ],
}

The proxy only runs on / when the open_app cookie is set, and it only checks that a session cookie exists; the dashboard validates the session itself. Add ?stay to the URL to see the homepage anyway. The cookie is managed in lib/open-app-preference.ts.

components.json

The shadcn/ui config. Components use the base-nova style (built on Base UI), the neutral base color, CSS variables in app/globals.css and Lucide icons. Aliases point to @/components, @/components/ui, @/lib, @/lib/utils and @/hooks.

Extra registries are declared so you can install their components with the shadcn CLI: @loading-ui, @evilcharts, @blocks-so, @shadcn-space, @spell and @spectrumui.

pnpm dlx shadcn@latest add dialog

See Theming for colors and fonts.

drizzle.config.ts

Points drizzle-kit at the schema (drizzle/auth-schema.ts), the migrations folder (drizzle/) and DATABASE_URL. See Database.

Tooling

FileTool
tsconfig.jsonTypeScript. The @/* alias maps to the project root.
eslint.config.mjsESLint, run with pnpm lint.
.prettierrcPrettier: no semicolons, double quotes, 80 columns, Tailwind class sorting.
knip.jsonKnip, run with pnpm knip, to find unused files and exports.
commitlint.config.jsConventional commits, checked on every commit.
.release-it.jsonReleases. See Deploying.

All the options are listed in Configuration reference.

Start fresh with reset-project

The boilerplate includes example features that you probably do not want in your product: user-scoped projects and categories, organization projects generated by the resource kit, a /demo page and the shared demo account. pnpm reset-project removes them in one go.

pnpm reset-project --dry-run  # only print what would happen
pnpm reset-project            # ask for confirmation, then apply
pnpm reset-project --yes      # no prompt
pnpm reset-project --force    # allow a dirty git working tree

Commit your work first. The script refuses to run on a working tree with uncommitted changes unless you pass --force, and it can only run once: it stops if examples/.reset.json exists.

What it does

  1. Moves these files and folders to examples/, at the same path:
    • 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.tsx, scripts/seed-demo.ts
  2. Replaces the files in scripts/reset/templates/ (the dashboard content and the organization overview) with clean versions. The originals are copied to examples/ first.
  3. Strips every block between @reset-remove:start and @reset-remove:end comments in app/, components/, features/, lib/ and drizzle/.
  4. Edits config: removes the db:seed:demo script from package.json and the orgProject entry from lib/resource-kit/manifest.json.
  5. Writes examples/.reset.json and examples/README.md, then formats the edited files with Prettier.

The whole plan is computed before anything is written, so an error (such as unbalanced markers) leaves the project untouched. The examples/ folder is excluded from TypeScript, ESLint and the build.

After the reset

The script prints the next steps:

pnpm typecheck      # make sure nothing still imports moved code
pnpm db:generate    # creates a migration dropping the example tables
pnpm db:migrate     #   (skip both on a brand-new database with no data)
pnpm resource:generate   # scaffold your own resources

Then remove DEMO_EMAIL and DEMO_PASSWORD from your .env files, and delete examples/ when you no longer need it.

Good to know: You can mark your own demo-only code with the same comments, and it will be removed too:

// @reset-remove:start demo-account
import { DemoSignInButton } from "@/features/auth/demo-signin-button"
// @reset-remove:end