# Database Options (/self-host/advanced/database-options)

> Configure SQLite or PostgreSQL database for Pangolin



Pangolin supports two database options: SQLite for simplicity and PostgreSQL for production deployments.

<CardGroup cols="2">
  <Card title="SQLite (Default)" icon="database">
    * No configuration required
    * Easy to use and portable
    * Built into the main image
    * Perfect for development
  </Card>

  <Card title="PostgreSQL" icon="database">
    * Production-ready database
    * Better performance at scale
    * Requires separate image
    * Advanced configuration options
  </Card>
</CardGroup>

## SQLite [#sqlite]

By default, Pangolin uses SQLite for its ease of use and portability.

**Docker Image**: `fosrl/pangolin:<version>`

<Note>
  No configuration is required to use SQLite with Pangolin.
</Note>

## PostgreSQL [#postgresql]

You can optionally use PostgreSQL for production deployments.

**Docker Image**: `fosrl/pangolin:postgresql-<version>`

### Configuration [#configuration]

Add the following section to your Pangolin configuration file:

```yaml title="config.yml"
postgres:
  connection_string: postgresql://<user>:<password>@<host>:<port>/<database>
```

<Warning>
  Replace the placeholders with your actual PostgreSQL connection details.
</Warning>

### Docker Compose Example [#docker-compose-example]

This example sets up PostgreSQL with health checks to ensure the database is ready before Pangolin starts:

```yaml title="docker-compose.yml"
name: pangolin
services:
  pangolin:
    image: fosrl/pangolin:postgresql-latest # Don't use latest in production
    container_name: pangolin
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - ./config:/app/config
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
      interval: "10s"
      timeout: "10s"
      retries: 15

  # ... other services ...

  postgres:
    image: postgres:17
    container_name: postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    volumes:
      - ./config/postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
```

<Warning>
  This example is not necessarily production-ready. Adjust the configuration according to your needs and security requirements.
</Warning>

<Note>
  Do not use `latest` tags in production. Use specific version tags for stability.
</Note>

### Read Replicas [#read-replicas]

Pangolin can distribute read queries across one or more PostgreSQL read replicas while always sending writes to the primary database. This is useful for scaling read-heavy workloads.

<Note>
  Replicas are chosen at random for each read query (not round-robin). Writes (`insert`, `update`, `delete`) always go to the primary database. A small number of time-sensitive reads (where the app must see its own recent writes) are also routed directly to the primary database regardless of replicas being configured.
</Note>

#### Using the Configuration File [#using-the-configuration-file]

Add a `replicas` array under `postgres` in your `config.yml`, with one entry per replica:

```yaml title="config.yml"
postgres:
  connection_string: postgresql://<user>:<password>@<primary-host>:<port>/<database>
  replicas:
    - connection_string: postgresql://<user>:<password>@<replica-host-1>:<port>/<database>
    - connection_string: postgresql://<user>:<password>@<replica-host-2>:<port>/<database>
```

#### Using Environment Variables [#using-environment-variables]

You can instead provide replica connection strings with the `POSTGRES_REPLICA_CONNECTION_STRINGS` environment variable, as a comma-separated list. This must be used together with `POSTGRES_CONNECTION_STRING` for the primary database - the two env vars replace the entire `postgres.connection_string` / `postgres.replicas` config as a unit.

```bash title=".env"
POSTGRES_CONNECTION_STRING=postgresql://<user>:<password>@<primary-host>:<port>/<database>
POSTGRES_REPLICA_CONNECTION_STRINGS=postgresql://<user>:<password>@<replica-host-1>:<port>/<database>,postgresql://<user>:<password>@<replica-host-2>:<port>/<database>
```

```yaml title="docker-compose.yml"
services:
  pangolin:
    image: fosrl/pangolin:postgresql-latest # Don't use latest in production
    environment:
      POSTGRES_CONNECTION_STRING: postgresql://<user>:<password>@<primary-host>:<port>/<database>
      POSTGRES_REPLICA_CONNECTION_STRINGS: "postgresql://<user>:<password>@<replica-host-1>:<port>/<database>,postgresql://<user>:<password>@<replica-host-2>:<port>/<database>"
```

<Note>
  The same pattern applies to the optional dedicated logs database: `postgres_logs.replicas` in the config file, or the `POSTGRES_LOGS_REPLICA_CONNECTION_STRINGS` environment variable (comma-separated) alongside `POSTGRES_LOGS_CONNECTION_STRING`.
</Note>

See the [`postgres.replicas` reference](/self-host/advanced/config-file#database-configuration) for the full config schema, and the [Environment Variables reference](/self-host/advanced/config-file#environment-variables) for all supported variables.
