Site

pnpm run init is the installation orchestrator. It selects one database provider and one Auth provider for the whole deployment:

DatabaseAuthBusiness dataAuth data
SupabaseSupabase AuthShared Prisma runtime on Supabase PostgreSQLManaged Supabase Auth
SupabaseBetter AuthShared Prisma runtime on Supabase PostgreSQLIsolated authn schema
NeonSupabase AuthShared Prisma runtime on Neon PostgreSQLManaged Supabase Auth project
NeonBetter AuthShared Prisma runtime on Neon PostgreSQLIsolated authn schema on Neon

The four implementations are available to fresh-install tooling and the shared runtime. Startup validates the selected providers, credentials, canonical identity and SQL roles. Separately, pnpm run qa:release requires complete certification evidence in config/database-auth-provider-compatibility.json before a release is approved. Init does not certify a release, and Docker builds do not run that release gate automatically.

Before you run it

Use repository-pinned Node 24.18.1 and pnpm 11.20.0. Prepare a new empty PostgreSQL database. This is not an upgrade or provider-switch workflow. A provider-specific destructive reset is available for a disposable incompatible Supabase or Neon target, but is disabled unless you explicitly arm it for the exact project or branch target.

After activating .nvmrc, run these from the repository root:

bash
corepack enable
pnpm install --frozen-lockfile
pnpm run db:client:generate
pnpm run init

Use an interactive terminal. The wizard collects its configuration through prompts, loads existing local configuration as defaults, and offers to resume an unfinished draft. It does not install dependencies or generate Prisma clients. See Quick Start for Node activation on macOS/Linux and Windows. A hosted fresh install does not require Docker; the disposable local QA runner does.

Have these values ready:

  • direct and pooled administrator URLs for the same fresh database, entered interactively and never written to .env.local;
  • Supabase URL and API keys when Supabase Auth or Supabase Storage is selected;
  • Neon Object Storage credentials, or an AWS S3 IAM role/static credential set, plus region, bucket names and public media base URL when selected;
  • the public application origin;
  • payment, email and optional integration credentials.

For Neon, open the project Connect dialog and keep the same branch, database, and owner role selected. Copy the Direct connection URL first, then enable Connection pooling and copy the Pooled connection URL. The pooled endpoint ID ends in -pooler. Init offers a derived pooled URL as a hidden default. Entry-time prompts retain supplied values; topology validation runs before installation. If the pair is rejected, rerun init, restore the draft and revisit database installation to replace the incorrect hidden value.

Choose a configuration mode

The first prompt separates product setup from optional platform tuning:

ModeUse it whenInteractive scope
Simple (recommended)First project, local foundation, or fastest safe installApp name and URL, Database/Auth pair, B2C/B2B, billing model and currency, admin email, required provider credentials, Neon scheduler choice, fresh database install
AdvancedYou already know the deployment topology and optional servicesThe complete Simple scope plus OAuth, feature gates, email delivery, payment provider, trials, analytics, PWA, scheduler, Storage and connection-budget values

Simple mode uses conservative defaults: magic-link authentication, onboarding enabled, Stripe test mode without requiring credentials, noop email delivery, non-indexable output, and optional analytics/chat/PWA/CDN/referral/affiliate/guest checkout features disabled. Supabase Storage is selected only with Supabase Auth; otherwise Storage defaults to disabled. Existing optional settings, scheduler and Storage provider are preserved when Simple mode is used on a repository that already has .env.local.

Advanced mode offers independent toggles for native product analytics, the activation checklist and AI usage controls. Init writes PRODUCT_ANALYTICS_ENABLED, ACTIVATION_ENABLED and AI_USAGE_CONTROLS_ENABLED explicitly to .env.local. Fresh Simple setup defaults AI usage controls to true and analytics/activation to false; reconfiguration preserves their existing values. These server-only flags are independent of GTM and advertising pixels. See Product insights and AI controls for the maintenance-job step after starting or restarting the app and worker.

Simple mode asks Configure Upstash Redis now? If you answer Yes, it collects the REST URL and masked token. If you answer No, init selects the mandatory in-memory fallback and writes ALLOW_INMEMORY_RATE_LIMIT=true. Advanced mode offers exactly two choices: Upstash Redis or in-memory process-local state. Existing Redis values are offered as defaults and the token is entered without being displayed.

DATABASE_APPLICATION_INSTANCES is a database connection-admission budget. It counts web and worker processes, so init does not use that value to infer the number of request-serving replicas or reject the in-memory choice. In-memory rate-limit counters and LLM circuit state remain independent in every process and reset on restart. Configure Upstash before adding request-serving replicas, cluster workers or serverless instances.

Init writes UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN and ALLOW_INMEMORY_RATE_LIMIT. Copy the selected values into the deployment platform's runtime environment; docker-compose.yml forwards all three. To fix an existing deployment, update these variables and recreate the app container; database initialization does not need to run again.

Step order

Numbering follows the selected mode without skipped numbers or lettered steps. Advanced adds optional sections and more questions inside the shared sections.

SectionSimpleAdvanced
Configuration mode11
Branding and basic information22
Business model33
Billing and currency (plus payment keys and trial in Advanced)44
Administrator55
Company, contact and social links—6
Features and integrations—7
Email configuration—8
Database and authentication providers69
Authentication settings and credentials710
Object storage811
Background jobs and database connections912
Rate limiting1013
Database installation and reset1114
Review and confirmation1215
Configuration-file generation after installation1316

OAuth choices, OTP, MFA and passkey settings are grouped with authentication. When Supabase Auth and Storage share a project, its credentials are collected once in the authentication section.

Back navigation and unfinished drafts

Every active prompt displays [type :back to go back]. Type :back, including at a hidden secret prompt, to return to the previous wizard section. After all inputs are collected, the review step can return directly to any available Simple or Advanced section before backups or database changes begin. When an earlier section changes, the wizard walks forward again so dependent provider and infrastructure answers are revalidated.

The wizard saves completed sections atomically in a local plaintext file under the operating system's temporary directory. The filename contains only an opaque hash of the repository path. A later pnpm run init detects the unfinished draft and asks whether to resume it or explicitly discard it. Both database-owner URLs are also saved immediately after each URL input, without entry-time format validation. Saved secrets are restored only as hidden prompt defaults; they are never printed. The directory/file request Unix permissions 0700/0600; on Windows, access depends on your temporary directory's ACLs. Protect the draft like a credentials file; it is not encrypted.

Drafts from an older step order retain their answers but restart at configuration mode so the reorganized sections can be reviewed. Press Enter to keep the saved defaults. Drafts saved in the current order resume at the unfinished section.

The draft deliberately excludes generated runtime database URLs, database preflight state, and destructive RESET authorization. A resumed run revisits the database-installation section to review saved owner URLs and collect any reset authorization again. Press Enter to keep either hidden URL. The draft remains after cancellation, validation failure, database failure, or incomplete setup, and is deleted only after database verification and configuration-file generation both finish successfully.

For Neon, a missing pooled default can be generated from a recognized direct URL by adding -pooler to its endpoint ID. Credentials, database and TLS settings are preserved. Press Enter at the pooled prompt to accept it, or paste the pooled connection string from Neon Connect with Connection pooling enabled for the same branch, database and owner role. Supplied values are not rejected or replaced because of their format during entry. If a default cannot be derived, the wizard simply asks you to supply the pooled URL. TLS normalization does not change a direct endpoint into a pooler. The installer still checks URL topology, TLS, credentials and database safety before installation or reset.

What the wizard does

  1. Selects Simple or Advanced configuration.
  2. Collects the mode-appropriate branding, Account model, billing, email and feature configuration.
  3. Selects DATABASE_PROVIDER=supabase|neon and AUTH_PROVIDER=supabase|better_auth.
  4. Collects authentication credentials, then selects and configures disabled, Supabase Storage, Neon Object Storage or AWS S3.
  5. Configures scheduling (supabase_pg_cron, postgres_pg_cron or external_runner), connection limits and rate limiting before database installation and the final review.
  6. Assembles the selected composition from database/manifest.json in memory.
  7. Installs the complete core and CMS batches on the empty database, or attests and reuses a complete credentialless composition left by a later-stage failure.
  8. Attests role attributes and grants before enabling login credentials.
  9. Provisions distinct app_runtime, app_maintenance, app_financial_worker and app_platform_admin credentials. Better Auth also receives auth_runtime_login_v1, which can access only authn.
  10. Configures the selected Auth issuer, proves identity coverage and atomically saves the attested runtime credentials before optional integrations run.
  11. Seeds the durable job catalogue and configures the selected scheduler.
  12. Initializes or attests Supabase Storage buckets when selected. Neon Object Storage and AWS S3 buckets remain operator-provisioned infrastructure.
  13. Saves the completed environment, generates application/workspace configuration and updates the pricing default.

Owner URLs are retained only in the unfinished draft, never in the generated application environment. Existing runtime credentials are preflighted but never silently rotated. Schema installation resumes only when both atomic schema batches are already complete and every operational role remains passwordless and NOLOGIN. A partial, mismatched, populated or already-credentialed target is rejected unless the selected provider's automatic reset is explicitly armed. A configuration-only rerun can instead skip schema installation and preflight the complete existing credential set, as described below.

Optional automatic database reset

After collecting the two administrator URLs, init asks whether it may automatically reset an incompatible non-empty Supabase or Neon target. The safe default is No. Choosing Yes is not sufficient: the next prompt names the detected project or branch target and you must type RESET exactly. This authorization applies only to the database identified by the matching direct and pooled URLs and to this wizard run.

If the first install check returns DATABASE_COMPOSITION_DATABASE_NOT_EMPTY, the wizard runs the selected provider's repository-owned reset batch over the direct PostgreSQL connection and retries the fresh install exactly once. It does not call supabase db reset. Their scopes differ:

ProviderDestructive scopePreserved infrastructure
SupabaseUnschedules every cron.job, recreates public, drops private/authn, and deletes every Supabase Auth user in auth.usersProvider roles, managed extensions and object storage
NeonDeletes in-scope non-extension application objects and data in public, private and authn; unschedules only exact application cron commands for the current database and ownerThe public schema, managed Auth helpers and pg_session_jwt, extensions, native roles, unrelated cron jobs, external Auth users and object storage

Only composition-declared roles are removal candidates. When a complete existing operational credential set passes preflight, init preserves those logins for reactivation after schema attestation. Protected dependencies or unrecognized objects cause refusal; review the diagnostics or use a new empty database. See SQL Sources & Installation for the exact reset batches. This is a destructive fresh-install recovery mechanism, not an upgrade mechanism and not a production-data migration. If any reset assertion fails, the transaction rolls back and the wizard stops without a second reset attempt.

File safety and reruns

Before any database credential can change, the wizard asks for confirmation and creates recovery copies for every existing managed file:

  • .env.local.backup
  • config/app.ts.backup
  • config/workspace.ts.backup
  • config/pricing.ts.backup
OutputActual change
.env.localAtomic replacement with managed configuration, generated non-owner credentials and preserved custom keys
config/app.tsRegenerated application configuration
config/workspace.tsRegenerated for B2B; not rewritten for B2C
config/pricing.tsUpdates defaultCurrency when the file exists; does not create provider products or replace the plan catalogue

Backups use fixed filenames and a later run can overwrite them. Retain a separate private recovery copy before another attempt when those backups are still needed. Configuration files are written individually; only .env.local replacement is atomic. Do not copy .env.example over the generated environment.

The regenerated .env.local carries forward custom variables that are not part of the managed .env.example contract. Managed variables are regenerated from the selected configuration, so retired provider secrets are not copied into a new provider block.

Rerunning init is a configuration regeneration workflow, not a database upgrade or provider-switch workflow. Review the backups before accepting generated file changes. For a completed installation, keep the same providers and answer No to Install this composition into a fresh database now? Init preflights the complete existing operational credentials before regenerating files; it does not reinstall schemas, reseed jobs or update database settings such as admin_email on this path. Review any corresponding operator changes separately.

Recovery depends on the last successful stage:

StateRecovery
Both schema batches complete, operational roles still passwordless and NOLOGINResume the draft and installation; the installer attests and reuses those batches.
Operational credentials attested and saved, later job/Storage/file stage failedPreserve .env.local and backups. Inspect and complete the failed stage; skipping installation only checks credentials and does not replay unfinished integration work.
Database setup completed, final config-file generation failedResume the retained draft; it selects the existing-credential preflight path before regenerating files.
Partial, mismatched or incompatible schemaUse a new empty database or the explicitly authorized provider-specific reset; init is not an upgrade tool.

Invalid menu and yes/no responses are rejected and asked again. If database installation or credential attestation fails, the command exits non-zero and does not continue to the success summary. If the operator deliberately skips database installation without a complete preflighted credential set, files may be generated for later completion but the command still exits non-zero.

On installation failure, the wizard reports the failing stage and whether the automatic reset was not started, completed, or started without confirmed completion. Authorizing RESET does not mean a reset has run. When available, the error report includes the PostgreSQL SQLSTATE, a recognized cause, SQL batch, and numeric error location; raw SQL, provider messages and credentials stay hidden. Keep this diagnostic block when reporting a failure. A generic DATABASE_COMPOSITION_INSTALL_FAILED alone cannot identify the cause. Inspect the target before retrying and do not authorize another reset just to obtain more diagnostics.

Conditional configuration

Supabase API variables are required only when AUTH_PROVIDER=supabase or STORAGE_PROVIDER=supabase. Neon Object Storage and AWS S3 require the S3-compatible server credential set described in Environment Setup. Better Auth requires a same-origin BETTER_AUTH_URL, a high-entropy secret, and its isolated database credential. All four application database URLs are required with either database provider, including DATABASE_FINANCIAL_WORKER_URL for isolated credit-ledger operations.

Remove retired IDENTITY_DATABASE_* and IDENTITY_COMPLIANCE_DATABASE_* variables from existing secret stores. Canonical identity uses the shared application transaction context; GDPR maintenance uses app_maintenance.

Scheduler and jobs

The durable jobs and job_runs tables are common to every composition. supabase_pg_cron stores the internal runner secret in Supabase Vault and uses pg_net to invoke /api/jobs/run. postgres_pg_cron installs pg_cron and schedules a fixed, secret-free SQL command that inserts a pending job_runs occurrence; run pnpm jobs:worker with the application so those occurrences execute through the TypeScript handler registry. It requires no Jobs API URL, JOBS_SECRET_KEY, pg_net, or Vault. external_runner calls /api/jobs/run on schedule with the Bearer secret. None of these schedulers replaces the durable queue.

For supabase_pg_cron or external_runner, the scheduler must be able to reach the configured HTTP origin; a hosted scheduler cannot call localhost. postgres_pg_cron has no HTTP reachability requirement, but its application worker must stay running.

With postgres_pg_cron, init writes COMPOSE_PROFILES=postgres-pg-cron so the repository's Docker Compose topology supervises critical and background workers alongside the web application. For direct local development, run pnpm jobs:worker in another terminal. Include all worker processes in DATABASE_APPLICATION_INSTANCES; init raises the Neon native-scheduler default to at least three for the Compose topology. Advanced mode accepts explicit budgets, which must still match the processes you deploy.

For self-hosted PostgreSQL, install the pg_cron extension binary, add pg_cron to shared_preload_libraries, set cron.database_name to the target application database, and restart PostgreSQL before running init. Do not configure pg_net or Vault for postgres_pg_cron.

On Neon, exposing the extension in the catalogue is not enough. cron.database_name must be configured through the Neon endpoint API with the exact database name used by the owner URLs. This setting is not exposed in the Console's compute editor. When installation detects the mismatch, the wizard offers optional API preparation in both Simple and Advanced modes:

  1. Enter your Neon project ID and a hidden Neon API key with access to that project.
  2. The wizard derives the compute ID and database name from the direct owner URL, then reads the API to verify the matching primary compute and branch.
  3. Review the target and explicitly approve updating cron.database_name and restarting that compute. Approval defaults to No. Active sessions will be disconnected; an idle compute is started instead, with normal compute charges.
  4. The wizard preserves unrelated Postgres settings, waits for API operations, reads back the result, then retries the installer once. PostgreSQL's active setting is checked again before schema SQL or any approved reset can run.

The project ID is saved in the temporary draft. The API key and restart approval are never saved; a later run requests them again. Declining sends no API mutation. API reads have bounded retries; update/start/restart requests are never automatically repeated after a failure or uncertain timeout. If an attempt stops, inspect the compute before retrying: a setting update or restart may already have completed. No schema reset is performed to repair this prerequisite. Manual API setup remains available if you do not want to supply an API key to init.

Compute size, plan, and scale-to-zero settings are not changed. Scheduled jobs only run while the compute is active; use an always-active compute for continuous scheduling. The wizard explains this prerequisite and lets you choose external_runner instead in both Simple and Advanced modes. That alternative requires an external scheduler calling the authenticated /api/jobs/run endpoint; it does not disable background jobs or start an external scheduler for you.

Before installing schemas or resetting a target, the installer checks extension availability and, when readable by the owner, the configured cron database. A mismatch stops before destructive SQL with DATABASE_COMPOSITION_INSTALL_PG_CRON_DATABASE_MISMATCH (or DATABASE_COMPOSITION_RESET_PG_CRON_DATABASE_MISMATCH). If restricted server settings cannot be read, the full SQL installation still validates the scheduler; the extension's own P0001 mismatch is translated into credential-safe guidance. Resetting application schemas cannot repair a compute-level cron setting.

After init

  1. Review the generated files and the wizard's remaining setup items. It does not create an Auth user, configure hosted OAuth/redirect settings, create payment products/webhooks, or provision external schedulers and S3-compatible buckets.
  2. Run pnpm run dev, open the configured origin (port 3777 by default), and check /api/health for HTTP 200. Restart an existing Next.js process after environment changes. Start the worker when the selected scheduler needs it.
  3. Configure Brevo or Mailjet and a verified sender before inbox sign-in tests. Simple mode's noop sends nothing and prints delivery metadata, not sign-in links. The disposable QA runner has its own guarded email recorder.
  4. Register through the application using the configured admin email. Init stores app_settings.admin_email; verified identity and the administrator check own promotion. A successful health probe does not verify Auth or billing.
  5. Add selected-provider test/sandbox catalogue bindings and webhook secrets, then run pnpm run check:payment-catalog before the billing checks.
  6. Run pnpm run qa:release before publishing. Runtime startup and Docker builds do not read release evidence. Do not edit the compatibility manifest to bypass missing certification.

See SQL Sources & Installation, Environment Setup, and Database/Auth Operations.