---
title: "Move a PostgreSQL dump to another version"
description: "Convert a pg_dump file from PostgreSQL 10 or later into a script that loads on PostgreSQL 13 to 18, with the same tables, keys and data, and a report of every change."
canonical: https://intosql.com/postgresql-to-postgresql
last_updated: 2026-10-15
---

# Move a PostgreSQL dump to another version

Drop a plain dump from pg_dump or pg_dumpall, as .sql or .sql.gz, and download one script that loads on PostgreSQL 13 to 18, whichever version wrote the dump. Identities, enums, arrays and jsonb stay as they are, types an extension brings become text, and every change is listed in the report.

[PostgreSQL to PostgreSQL migration guide](https://intosql.com/docs/migrations/postgresql-to-postgresql)

[PostgreSQL to PostgreSQL data types](https://intosql.com/docs/types/postgresql-to-postgresql)

## What changes between the file and the script

Each row is a rule the converter applies, with the report line it writes when the rule changes something in your data.

| In the file | In the script | Report line |
| --- | --- | --- |
| varchar(n), char(n), text | the same types |  |
| numeric(p,s), numeric without a precision, NaN and Infinity | the same types and values |  |
| money | numeric(19,2) | `type_replaced` |
| enum types | the same enum types, created before the tables |  |
| enum columns holding values outside their labels | text without a check | `enum_check_skipped` |
| composite and range types the dump defines, extension types (citext, hstore, ltree, PostGIS) and multiranges | text with PostgreSQL's text | `type_replaced` |
| citext | text, compared exactly | `case_insensitive_collation` |
| json, jsonb | the same types |  |
| timestamp with time zone | timestamptz, the same instants |  |
| time, time with time zone | the same types |  |
| infinity, -infinity and BC dates | kept |  |
| NaN and Infinity in numeric, real and double precision | kept |  |
| generated columns | the same generated columns |  |
| generated columns with functions IntoSQL doesn't write | a plain column with the values | `generated_not_translated` |
| defaults with functions IntoSQL doesn't write | no default | `default_not_translated` |
| CHECK constraints with functions IntoSQL doesn't write | not created | `check_skipped` |
| CHECK ... NOT VALID | added NOT VALID after the rows |  |
| gin, gist, brin and hash indexes, partial and expression indexes | not created | `index_skipped` |
| foreign keys to tables the dump doesn't create | not created | `foreign_key_skipped` |
| NOT NULL columns with values that become NULL | NOT NULL dropped | `not_null_relaxed` |
| partitioned tables | one table with every partition's rows | `partitions_dropped` |
| views, functions, procedures, triggers, rules, policies, extensions and types other than enums | listed in the report | `not_converted_objects` |
| dumps without CREATE TABLE (--data-only) | types read from the values | `no_schema` |
| expressions in INSERT values | NULL | `expression_value` |
| types IntoSQL doesn't know | text | `unknown_type` |
| text that isn't valid in its encoding | the bad bytes as the replacement character | `invalid_utf8_replaced` |
| text decoded twice (Ã±) | copied as it is | `mojibake_suspected` |

## Load the script into PostgreSQL

The script creates the tables, copies the rows, then adds keys, indexes and foreign keys, so it loads fast and stops at the first error.

```shell
psql -v ON_ERROR_STOP=1 -d mydb -f postgresql.postgresql.sql
```

Foreign keys are added as NOT VALID and then validated. If a row points to a row that doesn't exist, the script tells you which constraint, instead of failing half way.

For a large dump, create the database first and run the script with psql from the same machine as the server.

IntoSQL Pro loads the file straight into PostgreSQL from the desktop app or the command line, without writing a script.

## Dump PostgreSQL for the best result

The converter reads what the dump holds. These options keep more of your data in it:

- --format=plain, pg_dump's default, writes SQL. A custom or directory archive (-Fc, -Fd) becomes SQL with pg_restore -f dump.sql, without a database server.
- --no-owner --no-privileges leave out roles and grants, which the converter skips anyway, so the dump is smaller.
- pg_dumpall dumps every database in one file; each one's tables are named after it, so nothing collides.

## What isn't converted

Views, triggers, procedures, functions and other objects written in PostgreSQL's own language are listed in the report by name, never dropped silently, so you can check each one against the PostgreSQL version you load into before recreating it.

## Questions about moving PostgreSQL between versions

### Is my dump uploaded?

No. The converter runs in your browser and reads the dump from your disk in pieces, so it never leaves your computer. The desktop app and the command line convert on your computer too.

### How large can the dump be?

The converter never holds the whole dump in memory: it reads the file twice, by ranges, and writes the script as it goes. Multi-gigabyte dumps convert in the browser, in the desktop app and with the command line.

### Does it read pg_dump -Fc archives?

Not directly: a custom archive is a binary format. pg_restore -f dump.sql dump.backup turns it into the plain SQL the converter reads, without connecting to a server. The converter says so when it gets an archive.

### Which PostgreSQL versions can the dump come from?

Dumps written by pg_dump and pg_dumpall from PostgreSQL 10 on, with COPY or INSERT rows. Every test dump comes from PostgreSQL 13 and 18 and is compared with its source cell by cell.

### Are serial and identity values kept?

Yes. Serial and identity columns stay identity columns, every row keeps its id, and each counter continues from the value the dump's sequence had reached.

### What happens to arrays, enums and other PostgreSQL types?

They stay as they are: arrays, ranges, json and jsonb, bit strings, money aside. Enum types are created again with their labels. Types an extension brings (citext, hstore, PostGIS) and composite types become text, and the report says which columns.

### What about functions, triggers and views?

They are listed in the report by name and not converted, so you can recreate them once the tables are in. NOT VALID checks are added after the rows, still not valid.

### Which PostgreSQL versions does the script load on?

PostgreSQL 13 to 18, whichever version wrote the dump. The same script loads on each of them, stopping at the first error if anything goes wrong.

## From PostgreSQL

- [PostgreSQL to MySQL](https://intosql.com/postgresql-to-mysql)
- [PostgreSQL to MariaDB](https://intosql.com/postgresql-to-mariadb)
- [PostgreSQL to SQLite](https://intosql.com/postgresql-to-sqlite)
- [PostgreSQL to SQL Server](https://intosql.com/postgresql-to-sql-server)
- [PostgreSQL to Oracle](https://intosql.com/postgresql-to-oracle)

## Into PostgreSQL

- [MySQL to PostgreSQL](https://intosql.com/mysql-to-postgresql)
- [MariaDB to PostgreSQL](https://intosql.com/mariadb-to-postgresql)
- [SQL Server to PostgreSQL](https://intosql.com/sql-server-to-postgresql)
- [SQLite to PostgreSQL](https://intosql.com/sqlite-to-postgresql)
- [Oracle to PostgreSQL](https://intosql.com/oracle-to-postgresql)

## Guide and every pair

- [PostgreSQL to PostgreSQL migration guide](https://intosql.com/docs/migrations/postgresql-to-postgresql)
- [PostgreSQL to PostgreSQL data types](https://intosql.com/docs/types/postgresql-to-postgresql)
- [Every database pair](https://intosql.com/database-migration)
