---
title: "Database Backend Selection"
description: "Choose DB_BACKEND_MODE — PostgreSQL-primary, Firebase-full, or Supabase Postgres for your Ring clone"
locale: "en"
---
# Database Backend Selection

  Production Ring clones use **`DB_BACKEND_MODE=k8s-postgres-fcm`** — PostgreSQL for application data, Firebase Admin **only for FCM push** when configured. Legacy `DATABASE_MODE` is removed. Pick a mode before first boot.

  
- **[Backend modes (architecture)](/docs/architecture/backend-modes-and-databases.md)** — Adapters, FCM vs Firestore, `DB_HYBRID_MODE`

  
- **[Database migrations](/docs/getting-started/migrations.md)** — `schema.sql` + kingdom migration order

  
- **[Quick Start](/docs/customization/quick-start.md)** — First clone with Postgres

```mermaid
flowchart TD
  Start([New Ring clone])
  Start --> Q1{Production v1.6 features?}
  Q1 -->|Yes| PG[Postgres-primary]
  Q1 -->|Firestore prototype only| FB[firebase-full]
  PG --> Q2{Who runs Postgres?}
  Q2 -->|You / k3s / VPS| K8S[k8s-postgres-fcm]
  Q2 -->|Supabase hosted| SUP[supabase-fcm]
  K8S --> Mig[schema.sql + migrations]
  SUP --> Mig
```

## The three modes

| `DB_BACKEND_MODE` | Application data | Firestore for DB? | Push |
|-------------------|------------------|-------------------|------|
| **`k8s-postgres-fcm`** | PostgreSQL (self-hosted, k3s, Docker) | **No** | FCM + Apple when configured |
| **`supabase-fcm`** | PostgreSQL on Supabase | **No** | Same FCM pattern |
| **`firebase-full`** | Firestore paths | **Yes** | Full Firebase stack |

Implementation: `lib/database/backend-mode-config.ts`, `lib/database/DatabaseService.ts`, `lib/database/BackendSelector.ts`.

> **Info**
> **ConnectPlatform** ([connect-brand.com](https://connect-brand.com)) is realtime collaboration — **not** a `DB_BACKEND_MODE` adapter. See [Tunnel protocol](/docs/features/tunnel-protocol.md).

## Setup by mode

  OSS self-host, k3s, Ringdom handoff, PaymentConductor, News Kingdom, `data/schema.sql` v4.

Set mode and connection in `.env.local`:

{`DB_BACKEND_MODE=k8s-postgres-fcm
DB_HOST=localhost
DB_PORT=5432
DB_NAME=ring_platform
DB_USER=ring_user
DB_PASSWORD=your_password
DB_SSL=false`}

Optional: `DB_POOL_SIZE`, `DB_TIMEOUT`, `DB_RETRIES`.

Provision PostgreSQL **14+** (18 recommended locally) — Docker `docker-compose.dev.yml`, Homebrew bootstrap, or your cluster.

Apply schema and migrations:

{`export DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
./scripts/run-migration.sh`}

Full order: [Database migrations](/docs/getting-started/migrations.md).

**FCM (optional):** set `NEXT_PUBLIC_FIREBASE_*` + service account from `env.local.template`. App data stays on Postgres.

> **Success**
> Managed Postgres without operating k8s — same SQL schema as other production clones.

Create Supabase project; note URL + service role key.

{`DB_BACKEND_MODE=supabase-fcm
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_KEY=your_service_role_key`}

Apply [migrations](/docs/getting-started/migrations.md) against Supabase Postgres connection.

Optional: `NEXT_PUBLIC_TUNNEL_TRANSPORT=supabase` for Realtime — orthogonal to `DB_BACKEND_MODE`.

> **Warning**
> Prototyping only — PaymentConductor and most v1.6 features expect PostgreSQL.

Create Firebase project (Firestore, Auth, Storage as needed).

{`DB_BACKEND_MODE=firebase-full
AUTH_FIREBASE_PROJECT_ID=your-project-id
AUTH_FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\\n..."
AUTH_FIREBASE_CLIENT_EMAIL=firebase-adminsdk@...`}

No `data/schema.sql` on Firestore — plan migration to `k8s-postgres-fcm` before scale.

## What not to use

| Legacy / invalid | Replacement |
|------------------|-------------|
| `DATABASE_MODE=firebase_only` / `postgresql_only` | `DB_BACKEND_MODE` values above |
| `npm run db:migrate` / `db:backup` | `./scripts/run-migration.sh`, `pg_dump` |
| `DB_HYBRID_MODE` as primary switch | `DB_BACKEND_MODE` — see architecture page |

## Changing modes later

Export data from source (Firestore export or `pg_dump`).

Provision target Postgres; apply [migrations](/docs/getting-started/migrations.md).

Update `DB_BACKEND_MODE` and connection secrets on staging.

Smoke-test auth, store, payments, news before production cutover.

**Pre-launch checklist (Postgres-primary):**

- [ ] `DB_BACKEND_MODE` set — app starts clean
- [ ] `data/schema.sql` + kingdom migrations applied
- [ ] Backups configured (`pg_dump`, CNPG, provider snapshots)
- [ ] FCM vars only if push required
- [ ] `004_payment_transactions.sql` if using payments

`DatabaseService` keeps app code backend-agnostic — **data** still migrates deliberately. Auth tables: `lib/auth/postgres-adapter.ts`. Validate config: `validateBackendModeConfig()` in `backend-mode-config.ts`.

  
- **[Environment config](/docs/deployment/environment.md)** — Secret groupings and locale vars

  
- **[Payment integration](/docs/customization/payment-integration.md)** — Requires Postgres ledger

  
- **[Quick Start (new clone)](/docs/customization/quick-start.md)** — One deployment per customer — Ringdom pattern
