Dify with an external PostgreSQL database

Moving Dify metadata from the bundled db_postgres container to a managed or clustered PostgreSQL, with pool settings, TLS, version choice and backup ownership planned up front.

On this page

Why teams move Dify's PostgreSQL off the bundled container

A platform team moves Dify's metadata database off the bundled container when it needs backups, high availability and audit controls that the default `db_postgres` container does not provide. Dify stores its application metadata, accounts, workflow definitions and configuration in a relational database, and the Compose stack starts PostgreSQL as one of its core services. The environment variable reference lists PostgreSQL as the default metadata database, with MySQL and OceanBase as the other supported options, so the choice is about where the database runs and who operates it, not whether Dify can use it.

Pointing Dify at an external instance moves operational responsibility to your organization. The bundled container gives you a working database for a test or small internal deployment, but nothing in the default stack takes point-in-time recovery backups, fails over to a standby, or retains database logs for your audit window. A managed or clustered PostgreSQL service can supply those features, but you must confirm which ones it provides, who restores data, how long backups are kept and what the recovery targets are. Before you change DB_HOST and related settings, record who owns the database, which upgrade and patch process applies to it, and how Dify's backup procedure covers both the database and the storage it references.

The rest of this page covers the settings, TLS requirements, version choice and backup responsibilities for that move. Confirm the PostgreSQL version your provider supports against the PostgreSQL versioning policy before you select it, because the Dify release you run and the database version you choose both need to stay within support windows.

Connection and database options and when each fits

This table compares four ways to host the PostgreSQL metadata database behind Dify: the bundled container, a managed cloud service, a self-managed primary with a standby, and PgBouncer in front of either. Read each row against your own availability target, staffing and authentication policy, and treat the last column as the first question to answer with your platform team.

OptionWhat it gives youTrade-offWhen it fits
Bundled db_postgres containerZero extra infrastructure, provisioned by the default Compose fileSingle container, no standby, backups and upgrades are entirely your jobEvaluation, proof of concept or a single-workspace test host
Managed cloud PostgreSQLProvider handles patching, storage and often backups and failoverLess control over server settings, extension support and network placement must be confirmedTeams that want backups and failover delegated and can run Dify in the same cloud network
Self-managed primary with standbyHot standby for read-only queries and replication to a second nodeFailover is not automatic in PostgreSQL itself, so external tooling and runbooks are requiredOrganizations that run their own database platform and accept a tested manual or scripted failover
PgBouncer in front of the databasePooled client connections so many Dify processes share fewer server connectionsAdds a component to monitor, and session features and prepared statements must be checked against Dify's driver behaviorLarger Dify deployments with several api and worker replicas opening many connections
Connection pool settingsLimits on total connections per process and per pool, set through Dify's database variablesToo few connections queue requests, too many exhaust the server; tune against measured loadEvery external layout, once the replica count is known
TLS on database connectionsEncrypts traffic between Dify services and PostgreSQL, including the plugin daemon pathCertificates must be issued, rotated and trusted by every client; confirm the plugin daemon's support in your versionAny deployment where the database runs on a network segment you do not fully control
SCRAM-SHA-256 authenticationCurrent default password method, with stronger protection than older optionsRequires the client driver to support SCRAM; confirm compatibility before cutoverRecommended for new external databases
MD5 or trust-style authenticationWorks with older clients and simple setupsMD5 is deprecated in favor of SCRAM, and trust removes authentication entirelyAvoid, except during a short, documented migration window

Choosing a PostgreSQL major version that will stay supported

The version you pick sets how long your Dify metadata database receives security fixes and how much upgrade work lands on your team later. The cards below cover the supported version window, the Dify minimums, and the compatibility check to run before you deploy.

Version 18 is the longest runway

PostgreSQL 18 was first released on September 25, 2025 and is supported until November 14, 2030. For a new external database, it gives the longest window before the next forced major upgrade. It also adds asynchronous I/O and SCRAM-only password guidance, which fits a service that holds application secrets. Confirm that your managed service offers 18 before you commit to it.

Version 17 and 16 for mid-range support

Version 17 is supported until November 8, 2029 and version 16 until November 9, 2028. Either is a reasonable choice when your managed provider offers it as the default or when a platform team has standardized on it. Check the end date against your planned Dify upgrade cycle, since a database that expires sooner forces a second migration project.

Version 14 ends November 12, 2026

Version 14 reaches end of support on November 12, 2026. It still meets the Dify Enterprise minimum of PostgreSQL 14 or later, but a database deployed on it now would need a major upgrade soon after go-live. Avoid choosing 14 for a new build unless a fixed compatibility requirement forces it, and plan the upgrade window before that date if you already run it.

Match the Dify minimum for your edition

The Dify Enterprise resources checklist requires PostgreSQL 14 or later, so every version in the supported list qualifies. The Docker Compose deployment bundles its own PostgreSQL container, so the external database requirement is a choice you make for operations, not a version floor you must meet. Record the minimum your edition documents, then select from the supported versions above it.

Confirm Dify compatibility before deployment

Dify's documented minimums do not guarantee that every release has been tested against every PostgreSQL major version. Before you deploy, ask the Dify release notes for your target version and your managed provider which major versions are validated with that Dify build. Pin the database version in your change record so a later managed-service default upgrade does not change it unexpectedly.

How to point Dify at an external PostgreSQL in order

This sequence moves Dify metadata from the bundled db_postgres container to an external PostgreSQL instance, with each step confirmed before the next one starts, ending in a tested restore before go-live.

  1. Provision the instance and database roles

    The database or platform team creates a PostgreSQL instance inside your network, using a major version that is still supported on the PostgreSQL versioning policy at your go-live date. Create a dedicated database and a least-privilege login for Dify, separate from administrative accounts. Confirm the version with a server query and confirm the Dify login can connect from the api and worker hosts but not from anywhere else. Done when both connections succeed and the role owns only the Dify database.

  2. Configure TLS and SCRAM authentication

    Enable TLS on the PostgreSQL server with a certificate issued by your internal certificate authority, and require SCRAM-SHA-256 password hashing for the Dify role rather than MD5. Restrict the host-based access rules so only the Dify hosts can reach the port, and require TLS for those connections. Confirm the setting by checking the stored password hash type for the Dify role and by a client connection that reports an encrypted session. Done when a plaintext or non-SCRAM login attempt is refused.

  3. Set the Dify database variables in the env file

    Edit the env file used by your Docker Compose or Kubernetes deployment to point the metadata database at the external host, port, database name, and Dify role. Set the TLS options that the current environment variable reference lists for the database connection, and set the plugin daemon's database connection values in the same way, since the plugin daemon also stores state in PostgreSQL. Confirm every variable name against the current environment reference for your Dify version, because names change between releases. Keep the password in a secrets store or a restricted file, not in shared configuration. Done when the file reviews cleanly against the reference.

  4. Restart the stack and check schema initialization

    Restart the Dify services so the api, worker, and plugin daemon read the new settings, and stop the bundled db_postgres container from being started by the compose profile or service list you use. Watch the api container logs for database migration output and confirm that migrations complete without errors against the external server. Confirm the bundled container is not on the data path by checking that the external database now holds Dify tables. Done when the api reports a healthy start and the tables exist in the external database.

  5. Verify api, worker and plugin daemon connectivity

    Check each component separately. Open the Dify console and log in, create a test app, and save a draft, which exercises the api and the database write path. Run a background job, such as indexing a small test document in a knowledge base, to confirm the worker reads and writes through the external database. Install or list a plugin to confirm the plugin daemon can reach its storage. Review the server-side connection count and any TLS errors in the logs during these tests. Done when all three checks pass and no connection or certificate errors appear in the logs.

  6. Tune connection pool settings and document them

    Review the connection pool and connection limit settings in the environment reference, and align them with the maximum connections your PostgreSQL instance or connection pooler allows, including PgBouncer if you place one in front of the database. Run a short load test with realistic concurrency from your workflows to confirm the pool does not exhaust connections. Record the final values in your runbook. Done when the load test completes with no connection-limit errors in the api, worker, or database logs.

  7. Run a restore test before go-live

    Take a logical or physical backup of the external database using the method your database team has chosen, then restore it into a separate, empty PostgreSQL instance. Start a second Dify stack against the restored copy, or compare table counts and a sample of app and dataset records, to confirm the backup is usable. Also confirm that the SECRET_KEY and any workspace encryption keys are backed up separately, because a database restore alone does not restore access to encrypted credentials. Record the restore time and the steps. Done when the restored copy passes the record comparison and the recovery runbook is approved by the operations owner.

Who owns backups, point-in-time recovery and upgrades once the database moves

Once Dify's metadata leaves the bundled db_postgres container, the data in that database becomes your responsibility to back up, restore and keep current. The Compose stack will not do this for you. Assign a named owner in your database or platform team before cutover, and agree who runs restores, who approves a restore during an incident and where the backup jobs are monitored. The Dify Docker Compose documentation recommends taking a backup before every upgrade, so that step also belongs to whoever owns the database, not to the application release process. Decide early whether you need continuous archiving with point-in-time recovery, which the PostgreSQL continuous archiving documentation describes, or whether nightly logical dumps are enough for your recovery objectives. Point-in-time recovery needs archived WAL, a base backup and a tested restore procedure, and each of these carries its own storage and retention cost.

Test restores before you need them. A backup that has never been restored into a separate environment running the same Dify version is not yet evidence of recovery. Plan a restore exercise that brings the Dify metadata back, starts the api and worker services against it and checks that workflows, apps and knowledge base records load. Keep the SECRET_KEY value with the backup records, because the Dify environment reference notes that the key signs sessions and encrypts OAuth credentials, so a restored database with a different key will not behave as it did. Confirm how the vector store and file storage are backed up separately, since restoring metadata alone does not restore uploaded documents or embeddings.

PostgreSQL does not provide automatic failover by itself. Its high availability documentation describes hot standby servers and synchronous or asynchronous replication, but the failover documentation states that detecting a primary failure and promoting a standby needs external tools. Choosing those tools, along with how Dify reconnects after a promotion, is a separate design decision with its own owner, test plan and runbook. Ask your database team whether a managed service provides failover for your chosen engine and version, and what the recovery point and recovery time look like in that offering. Major version upgrades add another layer: the PostgreSQL upgrading documentation covers pg_upgrade, dump and restore, and logical replication, and the supported-version table in the versioning policy sets the dates you must plan around. Confirm the Dify release you run supports your target PostgreSQL major version before you schedule that work.

Security controls for the database connection

Moving Dify metadata to an external PostgreSQL server moves the most sensitive records out of the bundled container and onto a network path you must now protect. The controls below cover the connection itself, the database identity Dify uses, the network around it, and the secrets that unlock both.

Encrypt every database connection

Dify's API, worker and plugin daemon all talk to the metadata database, so each connection path needs TLS, not just the API. Confirm which TLS settings the Dify version you run exposes for the plugin daemon connection, and test that a plaintext connection is refused. Ask the PostgreSQL server owner to enforce TLS for the Dify role with a host rule, so a misconfigured client cannot fall back to an unencrypted session.

Require SCRAM over MD5

PostgreSQL 18 deprecated MD5 password authentication in favor of SCRAM, so a new external database should set SCRAM as the password encryption method from the start. Check that the server's password_encryption setting and the pg_hba.conf entry for the Dify role both use SCRAM. Stored MD5 hashes from an older server should be rotated when the role's password is reset during migration.

Choose certificate or LDAP authentication

PostgreSQL documents several methods beyond passwords, including certificate, LDAP, GSSAPI and PAM. Certificate authentication removes a stored password from Dify's environment file, but it depends on the client supporting the certificate and key files in your container layout. LDAP or GSSAPI fits when your directory already governs database access. Confirm with your Dify version which methods its connection string handles before choosing one.

Grant least-privilege database roles

Create a dedicated login role for Dify that owns only the Dify schema and database, and do not reuse the superuser or a shared application account. Keep schema changes under a separate migration role that you run during upgrades, so the runtime role cannot drop tables. Review grants after each Dify upgrade, because new versions can add tables or migrations that need explicit permissions.

Restrict network access to the database

Allow inbound connections to PostgreSQL only from the Dify hosts or the Kubernetes nodes that run its components, using firewall rules and pg_hba.conf host entries together. Keep the database off public subnets and out of any path reachable from model endpoints or user networks. If you use a connection pooler such as PgBouncer, restrict the database to the pooler's address so application traffic has one controlled route.

Keep secrets out of images and logs

Database passwords and SECRET_KEY belong in your secret manager or a host-only env file, never in a Dockerfile, a committed .env, or a published image layer. Changing SECRET_KEY after deployment logs out all users, so generate it once, store it with a documented recovery owner, and plan any rotation as a scheduled user-facing event. Confirm that database credentials are masked in container logs and in any support bundles you share.

Questions teams ask before moving Dify to external PostgreSQL

What does it cost to move Dify to an external PostgreSQL database?

The cost is mostly labor and the infrastructure you already pay for, since no supplied source gives a price for a database move. You pay for the managed or clustered PostgreSQL service (or the hardware and staff to run it), the time to plan and test the cutover, and the people who run it afterward. Ask any quote to split one-time work (design, data move, cutover, restore testing) from recurring work (database hosting, patching, backup storage, on-call). Dify's own pricing page lists Community as free, but that does not cover your database.

How long does an external PostgreSQL migration for Dify take?

No supplied source gives a duration, so treat any number you hear as unverified. The schedule depends on how much metadata exists, how many environments need the change, how long your backup and restore tests take, and how many approval gates your change process requires. A proof of concept on a copy of production data usually shortens the cutover window. Ask for a written plan with separate phases for design, rehearsal, cutover and post-cutover checks.

What does the customer team need to provide for this work?

You need to provide a database owner, a network path from the Dify api and worker containers to the database, and a decision on PostgreSQL version. The Enterprise resources checklist names PostgreSQL 14 or later as a requirement, and PostgreSQL 14 is listed as supported until November 12, 2026, so plan for a newer major version. You also need a maintenance window, access to your secrets store for credentials, and a restore environment where backups can be tested.

Can our internal team move Dify to external PostgreSQL without a partner?

Yes, if your team already runs PostgreSQL and understands Dify's Compose or Kubernetes layout. The hard parts are not the environment variables but the data cutover, connection tuning, TLS, and proving that a restore works. Teams without recent PostgreSQL operations experience often choose a fixed-scope engagement for design and rehearsal, then run the cutover themselves. DeployOpen plans, implements and documents this work in your infrastructure under a written scope.

What drives the effort of a Dify database move up or down?

Three factors drive most of the effort. First, migration of existing data: a fresh install is simple, while a populated Dify instance with apps, knowledge bases and workflow history needs a tested dump, restore and row-count check. Second, high availability design: a single primary with a managed backup policy is less work than a primary with hot standbys, synchronous or asynchronous replication, and an external failover tool, since PostgreSQL does not detect primary failure or promote a standby by itself. Third, backup testing: point-in-time recovery needs archived WAL and a restore drill, which takes more time than taking a dump.

What recurs after go-live when Dify uses an external PostgreSQL database?

After go-live, you keep paying for database hosting, storage, backups and monitoring, and someone must own minor and major PostgreSQL upgrades. PostgreSQL releases minor versions at least once every three months, and minor updates replace executables and restart the server. Major versions are supported for five years, so you need a planned major upgrade path, using pg_upgrade, dump and restore, or logical replication. Recurring work also includes restore tests, connection pool review and access reviews for database credentials.

How do Dify upgrades change when the metadata database is external?

Dify upgrades still follow the upgrade guide for the target release on the GitHub Releases page, and the Docker Compose docs recommend a backup before every upgrade. With an external database, that backup is no longer the bundled container's volume, so your backup must cover the external PostgreSQL instance and be restorable. Check .env.example for new variables after each upgrade, and confirm that Dify migrations run against your database user with the privileges they need. Minor Dify releases arrive roughly monthly, so schedule database and application changes separately.

Who is responsible for backups of the external PostgreSQL database?

You are responsible for backups, not the Dify project. Once metadata lives in your database, the bundled container's volume no longer protects it, so the database owner must set up base backups, WAL archiving for point-in-time recovery, retention rules and encryption. Test restores on a schedule and record the results. Confirm with your auditors which evidence they will ask for, since DeployOpen prepares controls and evidence but does not issue audit reports or certifications.

How DeployOpen scopes and delivers an external PostgreSQL move for Dify

DeployOpen plans, implements, documents and supports self-hosted open-source platforms inside your own infrastructure, including the move of Dify metadata from the bundled database container to an external PostgreSQL service. Each move starts from a written scope that covers connection handling, TLS, version choice, backups and handover to your operations team.

How we scope

  • Inventory the current Dify version, the bundled db_postgres container and every service that reads metadata today
  • Agree the target PostgreSQL service, major version, hosting model and network path in writing before work starts
  • Define who owns backup, restore testing, patching and major version upgrades after handover
  • Confirm connection pool limits, TLS requirements and the plugin daemon connection with your database team

How we build

  • Prepare a staging Dify environment pointed at the external PostgreSQL service and load a copy of metadata
  • Configure the connection settings, certificate trust and pool parameters, then verify each Dify service connects
  • Run a timed migration rehearsal and record the cutover steps, rollback point and required downtime
  • Test an application workflow, knowledge base query and a restore from backup before production cutover

How we hand over

  • Deliver the written configuration, variable reference and network diagram for your operations team
  • Provide a runbook covering backup schedule, restore procedure, upgrade steps and version support dates
  • Document the responsibility split between your database owners and the Dify operators for each recurring task
  • Walk through failure scenarios with your team so they can act without DeployOpen present

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer after handover
  • Review each Dify minor release and the PostgreSQL minor releases that affect your deployment
  • Retest backups and connection settings after infrastructure changes, with findings reported in writing
  • Quote follow-up work from a new written scope so changes stay visible and approved

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.