apps/docs/content/guides/platform/upgrading.mdx
Supabase ships fast and we try to add all new features to existing projects wherever possible. In some cases, access to new features require upgrading or migrating your Supabase project. It is recommended to upgrade Postgres version to get access to the latest features and fixes.
For scaling your compute size, refer to the Compute and Disk page.
The process remains the same for Postgres major and minor version upgrades, as other features and services are also upgraded at the same time.
<Admonition type="note">Free projects will move to the latest minor version when their paused project is restored. Paid projects can't be paused.
</Admonition>The upgrade process is as follows:
pg_upgrade.A Supabase project is deployed with a GP3 disk type by default, which will give ~100Mbps when upgrading. Changing the disk type (or increasing IOPS/Throughput) will reduce the time to upgrade.
Using the size of your database, you can use this metric to derive an approximation of the downtime window necessary for the upgrade. During this window, you should plan for your database and associated services to be unavailable.
When upgrading, a notification will inform you about what is blocking the upgrade process. You need to follow the pre-requisites for the upgrade to successfully complete:
pg_upgrade does not support upgrading of databases containing reg* data types referencing system OIDs. You need to modify the data to not use reg* data types before upgrade.Newer versions of services can break functionality or change the performance characteristics you rely on. If your project is eligible for an upgrade, you will be able to find your current service versions from within the Supabase dashboard.
Breaking changes are generally only present in major version upgrades of Postgres and PostgREST. You can find their respective release notes at:
If you are upgrading from a significantly older version, you will need to consider the release notes for any intermediary releases as well.
The md5 hashing method has known weaknesses that make it unsuitable for cryptography. As such, we are deprecating md5 in favor of scram-sha-256, which is the default and most secure authentication method used in the latest Postgres versions.
We automatically migrate Supabase-managed roles' passwords to scram-sha-256 during the upgrade process, but you will need to manually migrate the passwords of any custom roles you have created, else you won't be able to connect using them after the upgrade.
To identify roles using the md5 hashing method and migrate their passwords, you can use the following SQL statements after the upgrade:
-- List roles using md5 hashing method
SELECT
rolname
FROM pg_authid
WHERE rolcanlogin = true
AND rolpassword LIKE 'md5%';
-- Migrate a role's password to scram-sha-256
ALTER ROLE <role_name> WITH PASSWORD '<password>';
As part of the upgrade process, maintenance operations such as vacuuming are also executed. This can result in a reduction in the reported database size.
When upgrading, the Supabase platform will "right-size" your disk based on the current size of the database. For example, if your database is 100GB in size, and you have a 200GB disk, the upgrade will reduce the disk size to 120GB (1.2x the size of your database).
When a project is paused, users have a 1-year window to restore the project on the platform from within Supabase Studio.
The restore window exists because backups are only retained for a limited period, and platform changes may not be backwards compatible with older backups. Unlike active projects, static backups can't be updated to accommodate such changes.
During the restore window a paused project can be restored to the platform with a single button click from Studio's dashboard page.
<Image alt="Project Paused: 90 Days Remaining" width={962} height={386} src="/docs/img/guides/platform/paused-90-day.png" />
After the restore window, you can download your project's backup file, and Storage objects from the project dashboard. You can restore the data in the following ways:
<Image alt="Project Paused: Download Backup" src="/docs/img/guides/platform/paused-dl-backup.png" width={495} height={306} />
If you upgrade to a paid plan while your project is paused, any expired one-click restore options are reenabled. Since the backup was taken outside the backwards compatibility window, it may fail to restore. If you have a problem restoring your backup after upgrading, contact Support.
<Image alt="Project Paused: Paid Tier Restore" src="/docs/img/guides/platform/paused-paid-tier.png" width={962} height={385} />
In projects using Postgres 17, the following extensions are deprecated:
plcoffeepllsplv8timescaledbpgjwtProjects planning to upgrade from Postgres 15 to Postgres 17 need to first disable these extensions in the Supabase Dashboard.
<Admonition type="note">pgjwt was enabled by default on every Supabase project up until Postgres 17. If you weren't explicitly using pgjwt in your project, it's most likely safe to disable.
Existing projects on lower versions of Postgres are not impacted, and the extensions will continue to be supported on projects using Postgres 15, until the end of life of Postgres 15 on the Supabase platform.
pg_cron usagepg_cron does not automatically clean up historical records. This can lead to extremely large cron.job_run_details tables if the records are not regularly pruned; you should clean unnecessary records from this table before an upgrade.
During the Supabase project upgrade, the pg_cron extension gets dropped and recreated. Before this process, the cron.job_run_details table is duplicated to avoid losing historical logs. The instantaneous disk pressure created by duplicating an extremely large details table can cause at best unnecessary performance degradation, or at worst, upgrade process failures.
Starting with pg_graphql 1.6.0, GraphQL introspection is disabled by default. After the upgrade, queries to __schema and __type will return an error unless introspection is explicitly enabled. See the pg_graphql configuration docs for full details.
This affects tools that rely on introspection:
graphql-codegen)__schema or __type directlyRegular data queries (e.g. accountCollection, insertIntoAccountCollection) are not affected.
To re-enable introspection on a schema, run the following SQL in the SQL editor:
comment on schema public is e'@graphql({"introspection": true})';
If your schema already has a comment with other directives (e.g. inflect_names), combine the keys — setting a new comment overwrites the old one:
comment on schema public is e'@graphql({"inflect_names": true, "introspection": true})';
To verify introspection is enabled:
select graphql.resolve('{ __schema { queryType { name } } }');
Existing projects on pg_graphql 1.5.x are not impacted unless they choose to upgrade.
Applies when upgrading to Postgres 15.18 or 17.10.
<Admonition type="caution">You are affected only if you have indexes on ltree columns and your database uses a multibyte encoding or a non-libc collation provider.
After upgrading, indexes on ltree columns that were built under the previous version can return incomplete results until the index is rebuilt. For example, label searches silently miss rows that are present. This affects databases using a multibyte encoding, such as UTF-8, or a non-libc collation provider such as ICU or builtin.
To mitigate this issue:
Check whether your database needs reindexing:
select
pg_encoding_to_char(encoding) as encoding,
pg_encoding_max_length(encoding) as max_bytes_per_char, -- 1 = single-byte, >1 = multibyte
datlocprovider as collation_provider, -- 'c' libc, 'i' icu, 'b' builtin
(pg_encoding_max_length(encoding) > 1 or datlocprovider != 'c') as reindex_required
from pg_database
where datname = current_database();
If reindex_required is false, such as a single-byte encoding like LATIN1 with libc collation, no action is needed.
If reindex_required is true, find the affected indexes:
select schemaname, tablename, indexname
from pg_indexes
where
indexname in (
select c.relname
from
pg_index as i
join pg_class as c on i.indexrelid = c.oid
join pg_attribute as a on a.attrelid = i.indrelid and a.attnum = ANY(i.indkey)
join pg_type as t on a.atttypid = t.oid
where t.typname in ('ltree', '_ltree')
);
Reindex each affected index. REINDEX INDEX CONCURRENTLY runs online with no downtime:
REINDEX INDEX CONCURRENTLY <index_name>;
Applies when upgrading to Postgres 15.18 or 17.10.
Attaching a non-built-in (extension- or user-provided) selectivity estimator function to an operator now requires superuser. Existing operators continue to work — the check only fires when an operator is (re)created, most commonly during pg_dump / pg_restore, a logical restore, or a branch.
Because Supabase database roles are not superusers, recreating such an operator on your behalf (for example during a restore or branch) can fail with:
ERROR: must be superuser to specify a non-built-in restriction estimator function
Most projects are not affected. To check whether your database has any user-defined operators that reference a non-built-in estimator:
SELECT n.nspname AS schema, o.oprname AS operator
FROM pg_operator o
JOIN pg_namespace n ON o.oprnamespace = n.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
AND ((o.oprrest <> 0 AND o.oprrest::oid >= 10000)
OR (o.oprjoin <> 0 AND o.oprjoin::oid >= 10000))
AND NOT EXISTS (
SELECT 1 FROM pg_depend d
WHERE d.classid = 'pg_operator'::regclass AND d.objid = o.oid AND d.deptype = 'e'
);
If this returns no rows, your project is unaffected.