Neon’s migration tools make moving your existing PostgreSQL database to Neon surprisingly straightforward, even when starting from a completely different PostgreSQL distribution.
Let’s see it in action. Imagine you have a PostgreSQL 15 database running on AWS RDS with a table called users:
-- On your source RDS instance
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (username, email) VALUES
('alice', 'alice@example.com'),
('bob', 'bob@example.com');
Now, we want to move this to Neon.
First, you’ll need to create a Neon project. Head over to the Neon console (console.neon.tech) and create a new project. Once your project is ready, you’ll have a primary Neon endpoint. Get its connection string. It’ll look something like postgresql://[user]:[password]@[host]:5432/[database_name].
Neon offers several migration methods, but for a straightforward move from another PostgreSQL instance, pg_dump and pg_restore are your go-to tools, just like migrating between any two PostgreSQL instances.
Step 1: Dump your data from the source.
On your local machine or a bastion host that can connect to your RDS instance, run:
pg_dump -h rds-host.amazonaws.com -U rds-user -d your_rds_db -Fc -f rds_dump.pg
-h rds-host.amazonaws.com: The hostname of your RDS PostgreSQL instance.-U rds-user: Your RDS PostgreSQL username.-d your_rds_db: The database name on your RDS instance.-Fc: Specifies the custom archive format, which is more flexible forpg_restore.-f rds_dump.pg: The output file name.
Step 2: Restore your data to Neon.
Now, use pg_restore to load this dump into your Neon database. Make sure you have the Neon endpoint connection string handy.
pg_restore -h neon-primary-endpoint.neon.tech -U neon_user -d neon_db -Fc rds_dump.pg
-h neon-primary-endpoint.neon.tech: The hostname of your Neon primary endpoint.-U neon_user: Your Neon database username.-d neon_db: The database name in Neon.-Fc: Tellspg_restoreto expect the custom archive format.rds_dump.pg: The dump file created in the previous step.
After this, your users table and its data should be present in your Neon database.
The core problem Neon solves is the operational overhead of managing traditional PostgreSQL instances. Instead of worrying about provisioning, scaling, patching, and backups, Neon handles it all through its serverless architecture. Your data is stored in immutable "pages" that can be efficiently branched and shared. When you scale your compute, Neon spins up new compute instances that read from these shared pages, providing near-instant scaling without data movement.
The key to Neon’s architecture is its separation of storage and compute. Your data resides in a distributed object store (managed by Neon), and compute nodes (your endpoints) connect to this storage. This means you can have multiple compute endpoints (e.g., a read-only replica, a development branch) all pointing to the same underlying data. When you perform a write operation, a new compute instance writes its changes to a new set of pages, creating a new "timeline" for that branch. This is fundamentally different from traditional PostgreSQL, where compute and storage are tightly coupled.
You control the behavior of your Neon database primarily through the compute endpoints. You can adjust the size of these endpoints (e.g., compute.quantity, compute.threads) to scale your read/write capacity. Branching is a first-class citizen: creating a branch is an instantaneous operation that essentially creates a new compute endpoint pointing to a specific point in your database’s history. This allows for safe development and testing without impacting your production environment.
What trips most people up when migrating is understanding how Neon’s branching and autoscaling interact with traditional database tooling. You might be used to a single, monolithic database instance. With Neon, you have a primary endpoint, but you can also create branches. A branch is a separate compute instance that shares storage with its parent. When you restore a pg_dump into Neon, you’re typically restoring it into the default database associated with your primary endpoint. If you later create a branch, that branch will inherit the state of the database at the time the branch was created. So, if you want to migrate a specific state to a branch, you’d first restore to your primary, then create the branch.
The next hurdle you’ll likely encounter is setting up logical replication from Neon to another PostgreSQL instance, or vice-versa.