{
  "schema_version": 2,
  "id": "develop/ai/featureform/register-providers/postgresql",
  "title": "Register a PostgreSQL provider",
  "url": "https://redis.io/docs/latest/develop/ai/featureform/register-providers/postgresql/",
  "summary": "Register PostgreSQL storage and compute with Redis Feature Form.",
  "tags": [],
  "last_updated": "2026-08-25T13:17:04-07:00",
  "page_type": "content",
  "content_hash": "9b6c2b9d945b37e4253db1c197bad472eb6bb1c04ef3415ce3e8e73d2181b994",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Register a `postgres` provider when Redis Feature Form should discover PostgreSQL tables, run structured query language (SQL) transformations, or materialize training sets and feature-view data in PostgreSQL.\n\nThe provider fills the `offline-store` and `compute` roles. It doesn't provide online serving. A serving feature view also needs a supported `online-store` provider."
    },
    {
      "id": "distinguish-data-from-feature-form-state",
      "title": "Distinguish data from Feature Form state",
      "role": "content",
      "text": "A PostgreSQL data provider holds or computes customer feature data. It is separate from a PostgreSQL state backend that stores Feature Form's control-plane state. Use separate databases, credentials, and schemas for these purposes unless your deployment has another isolation policy."
    },
    {
      "id": "before-you-begin",
      "title": "Before you begin",
      "role": "content",
      "text": "Make sure you have:\n\n- A Feature Form [workspace](https://redis.io/docs/latest/develop/ai/featureform/manage-workspace).\n- A PostgreSQL hostname and database reachable from the Feature Form server.\n- A PostgreSQL username and password.\n- A [secret provider](https://redis.io/docs/latest/develop/ai/featureform/register-providers#configure-secret-providers) for the password reference.\n- Permission to read the required source tables and create managed outputs.\n\nThe Python example uses this workspace-scoped provider client:\n\n[code example]"
    },
    {
      "id": "register-postgresql",
      "title": "Register PostgreSQL",
      "role": "content",
      "text": "**Python:**\n\n[code example]\n\n**ff CLI:**\n\n[code example]\n\n\n\nThe environment reference is resolved by the Feature Form server. Replace it with a reference to another registered secret backend when appropriate.\n\nThe current public provider supports password authentication. Don't assume that internal or database-specific identity authentication methods are available through `ff`."
    },
    {
      "id": "choose-connection-security",
      "title": "Choose connection security",
      "role": "content",
      "text": "The Python `ssl_mode` field and the `--pg-ssl-mode` CLI option accept:\n\n- `disable`\n- `allow`\n- `prefer` (default)\n- `require`\n- `verify-ca`\n- `verify-full`\n\nThe public registration contract doesn't accept explicit client-certificate or root-certificate fields. Configure the required trust material in the Feature Form deployment environment."
    },
    {
      "id": "grant-workload-permissions",
      "title": "Grant workload permissions",
      "role": "content",
      "text": "The registration health check connects to PostgreSQL and queries its version. It proves connectivity and authentication, but it doesn't prove that later workloads can read or write their tables.\n\n| Workload | Required capability |\n| --- | --- |\n| Discover or read an existing table | Connect and `SELECT` on the referenced table |\n| Run transformations | Read source tables and create managed schema and table objects |\n| Replace managed outputs | Create, rename, update, insert into, and drop managed tables |\n| Materialize training sets or feature views | Read inputs and create or update the corresponding managed outputs |\n\nFeature Form-managed transformation tables use the `ff_transforms` schema through the documented gRPC registration path. The server creates the schema when required. This path doesn't expose a custom managed-schema value."
    },
    {
      "id": "understand-supported-workloads",
      "title": "Understand supported workloads",
      "role": "content",
      "text": "| Capability | Support |\n| --- | --- |\n| Existing PostgreSQL datasets | Supported |\n| Full SQL transformations | Supported |\n| Incremental SQL transformations | Supported |\n| Training-set materialization | Supported |\n| Feature-view batch computation | Supported with a separate online provider |\n| Direct dataframe reads | Supported |\n| Spark reads through Java Database Connectivity (JDBC) | Supported |\n| Online serving | Not supported |"
    },
    {
      "id": "verify-registration",
      "title": "Verify registration",
      "role": "content",
      "text": "[code example]\n\nIn Python, use `providers.get(\"<postgres-provider-name>\")` or `providers.list()`."
    },
    {
      "id": "update-safely",
      "title": "Update safely",
      "role": "content",
      "text": "| Field | Update behavior |\n| --- | --- |\n| Database | Immutable |\n| Host and port | Requires `force=True` or `--force` |\n| Username, password reference, and `ssl_mode` | Mutable |\n\nBefore a forced update or deletion, review datasets, transformations, training sets, feature views, and other references to the provider. The usage check doesn't detect every indirect reference."
    },
    {
      "id": "troubleshoot-registration",
      "title": "Troubleshoot registration",
      "role": "errors",
      "text": "| Symptom | What to check |\n| --- | --- |\n| Authentication is required | Supply both `username` and `password_secret` in Python, or both `--pg-username` and `--pg-password-secret` with the CLI |\n| Password resolution fails | Confirm the secret provider, workspace, and canonical reference syntax |\n| Connection is refused or times out | Check Domain Name System (DNS), routing, port, PostgreSQL host-based authentication, connection security, and credentials from the Feature Form server network |\n| Registration succeeds but a transformation fails | Grant the required source-table and `ff_transforms` permissions |\n| A dataset table isn't found | Check the provider database and the dataset's schema and table location |\n| A custom schema setting has no effect | Use `ff_transforms`; the documented gRPC registration path doesn't expose a managed-schema option |"
    }
  ],
  "examples": [
    {
      "id": "before-you-begin-ex0",
      "language": "python",
      "code": "import featureform as ff\n\nclient = ff.Client.from_env()\nproviders = client.providers(\"<workspace-id>\")",
      "section_id": "before-you-begin"
    },
    {
      "id": "register-postgresql-ex0",
      "language": "python",
      "code": "from featureform.types import EnvSecretRef, PostgresConfig, ProviderType, SSLMode\n\nproviders.register(\n    name=\"<postgres-provider-name>\",\n    provider_type=ProviderType.POSTGRES,\n    config=PostgresConfig(\n        host=\"<postgres-host>\",\n        port=5432,\n        database=\"<database-name>\",\n        username=\"<username>\",\n        password_secret=EnvSecretRef(name=\"PG_PASSWORD\"),\n        ssl_mode=SSLMode.REQUIRE,\n    ),\n)",
      "section_id": "register-postgresql"
    },
    {
      "id": "register-postgresql-ex1",
      "language": "bash",
      "code": "ff provider register <postgres-provider-name> \\\n  --workspace <workspace-id> \\\n  --type postgres \\\n  --pg-host <postgres-host> \\\n  --pg-port 5432 \\\n  --pg-database <database-name> \\\n  --pg-username <username> \\\n  --pg-password-secret env:PG_PASSWORD \\\n  --pg-ssl-mode require",
      "section_id": "register-postgresql"
    },
    {
      "id": "verify-registration-ex0",
      "language": "bash",
      "code": "ff provider get <postgres-provider-name> --workspace <workspace-id>\nff provider list --workspace <workspace-id>",
      "section_id": "verify-registration"
    }
  ]
}
