Skip to content

Guide · Neon to HornetHiveMigrate from Neon to HornetHive

A Neon database is standard PostgreSQL, so it moves to HornetHive with one pg_dump and one pg_restore. The part that changes is how your app connects: Neon's serverless driver talks to Neon's own proxy, and HornetHive speaks the normal Postgres protocol. This guide covers both.

Tools
pg_dump · pg_restore
Needs
Pro plan
Steps
One dump, one restore

What moves to HornetHive, and what does not?

Everything in the database moves: every schema, not only public, with its tables, rows, keys, indexes, sequences, enums, views and materialized views, functions, triggers and Row Level Security policies. Extensions come over too when HornetHive has them, created by the database owner during the restore.

What stays behind is what Neon runs around Postgres:

  • Branches, point-in-time restore and scale-to-zero. Each Neon branch is its own copy; move the one your app uses, usually main or production.
  • Neon Auth. Its users are rows in the neon_auth schema and come over with the dump, but HornetHive does not sign your users in.
  • Neon's Data API, and Row Level Security built on Neon's pg_session_jwt and auth.user_id(). Use HornetHive's REST and GraphQL APIs, and move those checks into your server.
  • Extensions outside PostgreSQL's own contrib set, such as pgvector, PostGIS, pg_cron and pg_session_jwt. Contrib extensions such as pgcrypto, uuid-ossp, pg_trgm, citext, hstore and ltree are available.

What do you need before you start?

A HornetHive database on the Pro plan, which comes with the direct connection string pg_restore needs. Each Neon database (neondb by default) becomes one HornetHive database; Pro has ten.

PostgreSQL 18 client tools (pg_dump, pg_restore, psql). pg_dump must be at least the version of the server it reads, and version 18 reads every Neon version.

Neon's direct connection string, not the pooled one: in the Neon console, Connect, then turn Connection pooling off. The pooled host has -pooler in its name and runs PgBouncer in transaction mode, which does not suit pg_dump. Then check which extensions your database uses, and that HornetHive has each of them:

export NEON_URL='postgresql://neondb_owner:<password>@ep-<name>.<region>.aws.neon.tech/neondb?sslmode=require'
export HIVE_URL='<HornetHive direct connection string>'

# on Neon: the extensions in use
psql "$NEON_URL" -Atc "SELECT extname FROM pg_extension WHERE extname <> 'plpgsql' ORDER BY 1"
# on HornetHive: the extensions you can create
psql "$HIVE_URL" -Atc "SELECT name FROM pg_available_extensions ORDER BY 1"
HornetHive plans compared, in Ringgit
PlanPrice (RM / month)BilledDatabasesStorageAPI calls / monthREST & GraphQLMCPDirect connection
Free0.00Free forever1500 MB500KYes——
Starter7.00Yearly, RM 84.0035 GB2.5MYesYes—
Pro29.00Yearly, RM 348.001020 GB25MYesYesYes

Step 1: how do you dump from Neon?

Stop writes to Neon first, or accept that rows written after the dump starts stay behind. A Neon compute that has scaled to zero wakes on the first connection, so the dump may take a few seconds to start. Dumping only reads; your Neon project is not changed.

pg_dump "$NEON_URL" --no-owner --no-privileges --format=custom -f neon.dump

Step 2: how do you restore into HornetHive?

--no-owner and --no-privileges leave out Neon's roles (neondb_owner, neon_superuser and any you made), so every object belongs to your HornetHive database's owner. pg_restore prints each statement it could not run and carries on: expect errors only for extensions HornetHive does not have, the objects that depend on them, and policies or grants that name a role HornetHive does not have.

pg_restore --no-owner --no-privileges -d "$HIVE_URL" neon.dump

Step 3: how do you check what came over?

Compare row counts with Neon, table by table, and look at the extensions that were created. Refresh materialized views if your app relies on them being current.

psql "$HIVE_URL" -c "SELECT schemaname, relname AS table, n_live_tup AS rows FROM pg_stat_user_tables ORDER BY 1, 2;"
psql "$HIVE_URL" -Atc "SELECT extname FROM pg_extension ORDER BY 1"

Step 4: how do you point your app at HornetHive?

Change DATABASE_URL to HornetHive's pooled connection string, and your migration URL to the direct one. If your app uses a normal driver (pg, postgres.js, psycopg, PDO, JDBC), that is all.

If it uses Neon's serverless driver, @neondatabase/serverless, swap it for a normal driver: that driver reaches Neon over HTTP and WebSockets through Neon's proxy, and does not connect to other Postgres servers. With Drizzle, change the import; with Prisma, remove @prisma/adapter-neon. On runtimes without TCP connections, such as an edge function, call HornetHive's REST API over fetch, or the HornetHive JS SDK.

HornetHive's REST and GraphQL APIs serve tables in the public schema. Tables in other schemas stay reachable over the connection string and the SQL endpoint.

// before: Drizzle on Neon's serverless driver
import { drizzle } from 'drizzle-orm/neon-http'
const db = drizzle(process.env.DATABASE_URL!)

// after: Drizzle on node-postgres, HornetHive's pooled URL
import { drizzle } from 'drizzle-orm/node-postgres'
const db = drizzle(process.env.DATABASE_URL!)

// Prisma: drop the adapter and keep the datasource
//   url       = env("DATABASE_URL")   // pooled
//   directUrl = env("DIRECT_URL")     // direct, for migrations

Can an AI agent do the migration for you?

Yes, if the agent can run commands on your machine: Claude Code, Cursor, Codex or another coding agent with a terminal. It creates the HornetHive database through the HornetHive MCP server, runs pg_dump and pg_restore in the terminal, and checks the result.

You need the PostgreSQL 18 client tools, the Pro plan, and an API key with the write scope and Allowed IPs left at *. Add the MCP server to the agent, and export NEON_URL (the direct string) before you start the agent, so the password never goes into the chat. Then paste this prompt, with your label, region and password filled in:

Migrate my Neon database to HornetHive by following
https://hornethive.io/migrate-from-neon step by step.

- Neon: the direct (not pooled) connection string is in $NEON_URL.
  Only read from it; change nothing in Neon.
- Use PostgreSQL 18 client tools (check pg_dump --version first).
- List the extensions Neon uses. After creating the HornetHive database,
  compare them with pg_available_extensions there; if one is missing
  (pgvector, PostGIS, ...), stop and tell me before restoring.
- With the hive MCP server: list_regions, then tell me what you will create
  and wait for my yes. Then create_database with label "<label>",
  region "<my or jp>" and password "<a strong password>".
- get_connection_string masks the password: build the direct connection
  string with my password and export it as $HIVE_URL. Never print it.
- Dump and restore exactly as the guide says, then compare row counts
  table by table between Neon and HornetHive.
- Show me every pg_restore error and say whether it is expected.
- Finish with sync_graphql and list_tables on the new database, and tell me
  which files in my app use @neondatabase/serverless or a Neon adapter.

Updated

Questions

Does the move change my Neon project?+

No. pg_dump only reads. Keep Neon running until your app has switched and you have checked the data.

Why do I need the Pro plan?+

pg_restore needs a direct connection to Postgres, and the direct connection string comes with Pro. REST and GraphQL are on every plan.

My Neon project is on PostgreSQL 16 or 17. Can it move to PostgreSQL 18?+

Yes. Use the version 18 tools: pg_dump 18 reads every older server, and pg_restore 18 reads dumps made by older pg_dump.

Can I keep the Neon serverless driver?+

No. It connects through Neon's proxy, not to other Postgres servers. Use pg, postgres.js or your ORM's normal driver, or HornetHive's REST API where there is no TCP.

I have several Neon databases or branches. What do I move?+

Each Neon database becomes its own HornetHive database: dump and restore each one. For branches, move the one your app runs on.

Do my tables show up in REST and GraphQL?+

Tables in the public schema do: REST at once, GraphQL after a sync from the database's GraphQL tab or the sync_graphql MCP tool.