Launch NowDocs

Configuration

Reference for siteConfig, legalConfig and the environment variables validated by lib/env.ts.

Launch Now keeps product identity, legal details and secrets in three places: siteConfig for the product itself, legalConfig for the legal documents, and environment variables validated by lib/env.ts. This page lists every field, its type and default, and the code that reads it.

FileExportPurpose
lib/config/site-config.tssiteConfigProduct name, URLs, metadata, social links.
lib/config/legal.tslegalConfig, findLegalPlaceholders(), types LegalConfig, CookieEntry, CookieCategory, SubprocessorCompany details and settings used to build the /legal documents and the cookie banner.
lib/env.tsenvType-safe, validated environment variables.

siteConfig

siteConfig is the single source of truth for the product identity. The demo values describe Pulse, a placeholder product: replace them with your own.

lib/config/site-config.ts
export const siteConfig = {
  name: "Pulse",
  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",
  },
  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",
  },
}

Good to know: siteConfig reads process.env directly instead of lib/env, so it can be imported from client components, tsx scripts and builds that run with SKIP_ENV_VALIDATION.

name

  • Type: string
  • Default: "Pulse"

Display name. Read by the root metadata and title template (app/layout.tsx), app/manifest.ts, app/opengraph-image.tsx, the JSON-LD (lib/seo/json-ld.ts), createSeoHead (lib/seo/metadata.ts), the docs nav title (lib/layout.shared.ts), Better Auth's appName and the OTP email (lib/auth.ts), newsletter emails (lib/newsletter-actions.ts, features/newsletter/newsletter-composer.tsx), the password-set email (lib/account-actions.ts), legalConfig.product.name, scripts/seed-plans.ts, and user-facing copy in the auth pages, marketing sections, onboarding, changelog, status, error pages and the profile form.

slug

  • Type: string
  • Default: "pulse"

Machine name. Used as:

  • the API key prefix (<slug>_, set as defaultPrefix of the apiKey plugin in lib/auth.ts), also shown as a fallback in features/account/api-keys/api-key-row.tsx;
  • the Stripe price lookup keys (<slug>-pro-monthly, <slug>-ultra-monthly) and the app metadata tag on Stripe products in scripts/stripe-create-products.ts and scripts/stripe-update-features.ts.
Changing slug after you created Stripe products means pnpm stripe:products and pnpm stripe:update-features no longer find the existing prices by lookup key. Existing API keys keep their old prefix.

tagline

  • Type: string

Short pitch. Read by the home page title (app/page.tsx), the Open Graph image and its alt (app/opengraph-image.tsx) and features/marketing/brand.tsx.

description

  • Type: string

Default meta description. Read by app/layout.tsx, app/page.tsx, app/manifest.ts, app/opengraph-image.tsx, lib/seo/json-ld.ts, and createSeoHead when a page passes no description.

url

  • Type: string
  • Default: process.env.NEXT_PUBLIC_APP_URL, or "http://localhost:3000" when unset.

Public base URL. Used as metadataBase and to build absolute URLs in app/layout.tsx, lib/seo/metadata.ts, lib/seo/json-ld.ts, app/sitemap.ts, app/robots.ts, app/changelog/rss.xml/route.ts, and as legalConfig.product.url.

ogImage

  • Type: string
  • Default: "/opengraph-image"

Path of the generated Open Graph image. No code currently reads this field; Next.js serves app/opengraph-image.tsx by file convention.

  • Type: { twitter: string; github: string }

Social profiles. Rendered in the marketing footer (features/marketing/footer.tsx) and added to the Organization JSON-LD sameAs list (empty values are skipped).

supportEmail

  • Type: string | undefined
  • Default: process.env.NEXT_PUBLIC_SUPPORT_EMAIL

When set, the app sidebar shows a Support mailto: link (components/layouts/nav-configs/dashboard.tsx). When unset, the link is hidden.

creator

  • Type: string
  • Default: "@antonio_rnv"

Twitter / X handle used for twitter.creator in app/layout.tsx and createSeoHead.

locale

  • Type: string
  • Default: "en_US"

Open Graph locale in app/layout.tsx and the default locale of createSeoHead.

themeColor

  • Type: string
  • Default: "#09090b"

Browser theme color (viewport.themeColor in app/layout.tsx) and the manifest's background_color and theme_color.

geo

  • Type: { region: string; placename: string; latitude: string; longitude: string }

Emitted by createSeoHead as geo.region, geo.placename, geo.position (latitude;longitude) and ICBM meta tags.

legalConfig

legalConfig holds everything the legal documents under /legal need. Any string that still starts with TODO is reported by pnpm legal:check (which exits with code 1) and shown in a warning banner on /legal pages in development. See Legal pages for the workflow.

effectiveDate

  • Type: string (ISO date, YYYY-MM-DD)

Date the current version takes effect. Formatted by formatEffectiveDate() in features/legal/types.ts and shown as the "last updated" date on /legal and each document.

product

FieldTypeDefaultRead by
namestringsiteConfig.nameEvery document, app/legal/page.tsx, the cookie banner.
urlstringsiteConfig.urlNot read by the current documents.
descriptionstringTODOTerms of Service.

company

FieldTypeDefaultNotes
legalNamestringTODORegistered company name, or your full name if sole trader.
legalFormstringTODOFor example SAS, LLC, Ltd. companyName() renders legalName (legalForm) when set.
registrationNumberstringTODOSIREN/RCS, Companies House number, EIN.
registrystringTODOFor example RCS Paris. Empty string if none.
vatNumberstring""Empty if not VAT registered.
shareCapitalstring""Empty if not applicable.
addressstringTODOStreet, postal code, city.
countrystringTODO

The Legal Notice lists all company fields and skips empty ones. companyName() is used by the Terms, Privacy Policy and DPA; address and country also appear in Terms and Privacy.

contact

FieldTypeDefaultRead by
emailstringAPP_CONTACT_EMAIL, else TODOTerms, Legal Notice.
privacyEmailstringAPP_CONTACT_EMAIL, else TODOPrivacy Policy, Cookie Policy, DPA.
supportEmailstringAPP_HELP_EMAIL, else TODORefund Policy (billing and refund requests).
dpoEmailstring""Privacy Policy and DPA. When set, it replaces privacyEmail as the privacy contact.
phonestring""Legal Notice, when set.

publicationDirector

  • Type: string
  • Default: TODO

Person responsible for the content ("Directeur de la publication", required in France). Shown in the Legal Notice.

host

FieldTypeDefault
namestringTODO
addressstringTODO
urlstringTODO

Listed in the Hosting section of the Legal Notice.

jurisdiction

FieldTypeDefaultRead by
governingLawstringTODOTerms.
courtsstringTODOTerms.
supervisoryAuthoritystringTODOPrivacy Policy (GDPR art. 77 complaint authority).

audience

FieldTypeDefaultEffect
customers"business-only" | "business-and-consumers""business-and-consumers"With business-and-consumers, the Terms and Refund Policy include consumer-specific wording (withdrawal rights).
minimumAgenumber16Minimum age in the Terms and the Privacy Policy.
applyGdprbooleantrueIncludes the GDPR section in the Privacy Policy.
applyCcpabooleantrueIncludes the CCPA section in the Privacy Policy.

billing

FieldTypeDefaultEffect
paymentProviderstring"Stripe"Named in Terms, Privacy, Cookie and Refund policies.
currencystring"USD"Terms.
trialDaysnumber0When greater than 0, Terms and Refund Policy mention the free trial.
refundWindowDaysnumber14Days during which a first payment can be refunded on request. 0 means no refunds.

retention

FieldTypeDefaultRead by
backupDaysnumber30Privacy Policy, DPA.
logsDaysnumber90Privacy Policy.

subprocessors

  • Type: Subprocessor[]
lib/config/legal.ts
export type Subprocessor = {
  name: string
  purpose: string
  /** Where the data is processed, e.g. "United States", "EU (Frankfurt)". */
  location: string
  url: string
}

Listed in the Privacy Policy and the DPA. The default list covers Neon (database and object storage), Stripe, Resend, GitHub and Google. The Neon database location is a TODO.

cookies

  • Type: CookieEntry[]
lib/config/legal.ts
export type CookieCategory =
  "essential" | "preferences" | "analytics" | "marketing"
 
export type CookieEntry = {
  name: string
  provider: string
  purpose: string
  duration: string
  category: CookieCategory
}

Read by the Cookie Policy (which adds tracker wording when any cookie is analytics or marketing) and by the cookie consent dialog (features/cookie-consent/cookie-consent.tsx), which groups cookies by category and clears first-party cookies of a category the user declines. Defaults: better-auth.session_token, better-auth.last_used_login_method, better-auth.two_factor, cookie_consent, open_app (all essential) and sidebar_state (preferences).

Add an entry here whenever you add a cookie or a third-party script.

findLegalPlaceholders()

function findLegalPlaceholders(value?: unknown, path?: string): string[]

Walks legalConfig and returns the dotted paths (for example company.address or subprocessors[0].location) of every string starting with TODO. Used by scripts/legal-check.ts and the /legal pages.

Environment variables

lib/env.ts validates environment variables with @t3-oss/env-nextjs and Zod. Import env from @/lib/env in server code instead of reading process.env:

import { env } from "@/lib/env"
 
const from = env.EMAIL_FROM

Set SKIP_ENV_VALIDATION to any non-empty value to skip validation (for example in CI builds). Copy .env.example to .env to start.

Server variables

VariableSchemaUsed by
DATABASE_URLURL, requireddrizzle/db.ts, drizzle/migrate.ts, drizzle.config.ts, scripts/db-baseline.ts
BETTER_AUTH_SECRETstring, min 32 chars, requiredBetter Auth; also signs newsletter confirmation tokens (features/newsletter/newsletter.server.ts). Generate with openssl rand -base64 32.
BETTER_AUTH_URLURL, requiredBetter Auth baseURL; links in invitation, notification and newsletter confirmation emails.
RESEND_API_KEYstring, requiredlib/email.ts
RESEND_AUDIENCE_IDstring, optionalNewsletter. The feature is off when unset.
EMAIL_FROMstring, requiredDefault sender, for example "Pulse <hello@example.com>".
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRETstring, requiredGitHub OAuth in lib/auth.ts.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRETstring, requiredGoogle OAuth in lib/auth.ts.
AWS_ENDPOINT_URL_S3URL, requiredS3-compatible storage endpoint (lib/storage.ts).
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYstring, requiredStorage credentials.
AWS_REGIONstring, requiredStorage region (auto in .env.example).
STRIPE_SECRET_KEYstring, requiredlib/stripe.ts and the Stripe scripts.
STRIPE_WEBHOOK_SECRETstring, requiredStripe webhook verification in lib/auth.ts.
STRIPE_PRO_PRICE_ID, STRIPE_ULTRA_PRICE_IDstring, optionalMap the pro and ultra plans to Stripe prices. A plan without a price ID is skipped. Printed by pnpm stripe:products.
DEMO_EMAILemail, optionalShared demo account. Destructive actions are refused for this user.
DEMO_PASSWORDstring, min 8 chars, optionalDemo account password. The demo sign-in button shows only when both demo variables are set.
APP_CONTACT_EMAILemail, optionallegalConfig.contact.email and privacyEmail.
APP_HELP_EMAILemail, optionallegalConfig.contact.supportEmail; support address in the password-set email.
APP_NOREPLY_EMAILemail, optionalSender for notification and account emails, falling back to EMAIL_FROM.
APP_ONBOARDING_EMAILemail, optionalDeclared in the schema but not read by the current code.

Client variables

VariableSchemaUsed by
NEXT_PUBLIC_APP_URLURL, requiredsiteConfig.url, the Better Auth client baseURL (lib/auth-client.ts), trustedOrigins in lib/auth.ts, the newsletter confirm redirect.

Not validated

VariableUsed by
NEXT_PUBLIC_SUPPORT_EMAILsiteConfig.supportEmail. Optional, read directly from process.env.
SKIP_ENV_VALIDATIONDisables validation in lib/env.ts.

Add a variable

Declare it in the schema

Add it to server (or client, with the NEXT_PUBLIC_ prefix) and to runtimeEnv:

lib/env.ts
export const env = createEnv({
  server: {
    // ...
    MY_API_KEY: z.string().min(1),
  },
  runtimeEnv: {
    // ...
    MY_API_KEY: process.env.MY_API_KEY,
  },
})

Document it

Add the variable to .env.example with a placeholder value.

Set it everywhere

Add it to your local .env and to your hosting provider's environment.