Move a Fly Managed Postgres or unmanaged Fly Postgres database into Amazon RDS in your own AWS account, using flyctl proxies, pg_dump and pg_restore, then point a Go backend at the new database.

Fly.io runs Postgres in two ways: Fly Managed Postgres, where Fly operates the cluster, and the older unmanaged Fly Postgres, which is a Fly app running Postgres that you are responsible for upgrading, backing up and recovering. Teams usually start looking at RDS when the app moves to AWS for other reasons, or when the unmanaged cluster needs a major version upgrade and someone has to own the procedure.
This guide copies a Fly Postgres database of either kind into Amazon RDS in your own AWS account with pg_dump and pg_restore through a flyctl tunnel, then points a Go backend at it. The RDS target is created with Encore from the database declared in Go, with a note on doing it by hand.
Both kinds of Fly Postgres sit on Fly's private network, so the dump runs through a local proxy that flyctl opens over WireGuard. For Managed Postgres, fly mpg proxy forwards a local port to the cluster, and --local-port changes it if 16380 is taken:
Use 127.0.0.1 rather than localhost in the connection string, since localhost can resolve to the IPv6 address the proxy is not listening on. With the tunnel up in one terminal, check the source in another:
SELECT version();
SELECT extname FROM pg_extension ORDER BY extname;
SELECT pg_size_pretty(pg_database_size(current_database()));
Create RDS on the same or a newer major version, confirm each extension appears in the RDS for PostgreSQL extension list, and install a pg_dump at least as new as the server.
Encore brings infrastructure from code to TypeScript and Go backends: the Go service that queries the database declares it, and the Encore platform provisions and deploys into your own AWS or GCP account. Deploying to an AWS environment creates an RDS for PostgreSQL instance in private subnets, encrypted, with automated backups and a database role per service, alongside the Fargate or EKS compute the service runs on, as the AWS infrastructure docs list.

Run in your terminal to get started locally.
$FLY_URL is the connection string pointed at the local proxy. The schema-only dump becomes a bootstrap migration, as described in the RDS import docs, so every later environment starts with the same tables. The service declares the database next to its endpoints:
// orders/orders.go
package orders
import (
"context"
"errors"
"encore.dev/beta/errs"
"encore.dev/storage/sqldb"
)
// Postgres locally with `encore run`, Amazon RDS when deployed to AWS.
var db = sqldb.NewDatabase("app", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
type Order struct {
ID int64 `json:"id"`
CustomerID int64 `json:"customer_id"`
Status string `json:"status"`
TotalCents int64 `json:"total_cents"`
}
//encore:api public method=GET path=/orders/:id
func Get(ctx context.Context, id int64) (*Order, error) {
o := &Order{ID: id}
err := db.QueryRow(ctx, `
SELECT customer_id, status, total_cents FROM orders WHERE id = $1
`, id).Scan(&o.CustomerID, &o.Status, &o.TotalCents)
if errors.Is(err, sqldb.ErrNoRows) {
return nil, &errs.Error{Code: errs.NotFound, Message: "order not found"}
}
return o, err
}
After the first deploy to a production environment on AWS, the instance exists with the bootstrap schema and no public endpoint. encore db proxy --env=production opens a tunnel to it, much like the flyctl one on the other side, and encore db conn-uri app --env=production prints the connection string for the restore, both described in the database docs.
Locally, encore run starts Postgres with the bootstrap schema, so developers stop connecting to the Fly database through a proxy for day-to-day work, and a coding agent that changes the schema does it as a numbered migration tested on that local copy. If the Go app on Fly used pgx or database/sql directly, the query code usually carries over as it is, since sqldb exposes the same QueryRow, Query and Exec shape and db.Stdlib() returns a *sql.DB for libraries that need one.
Best fit: teams moving a Fly.io app and its Postgres to AWS who want RDS in their own account, created from the Go code that queries it, with the same schema on every laptop.
Without Encore, the target is an RDS instance with a DB subnet group in private subnets, a security group that allows 5432 from the application's security group only, and credentials in Secrets Manager. The restore then needs a host inside the VPC, such as an EC2 instance reached through SSM Session Manager port forwarding, and it restores schema and data together. The RDS Terraform guide walks through those resources.
With both tunnels open, copy the data while Fly still serves traffic:
The dump travels from Fly over WireGuard to your machine and then over the Encore proxy into RDS, so for databases above a few gigabytes run both commands from a host with good bandwidth, such as a temporary EC2 instance with flyctl installed. Record the total time, which is roughly the length of the write freeze, then empty the target with TRUNCATE ... RESTART IDENTITY CASCADE. The pg_restore documentation covers --jobs and the --disable-triggers flag for data-only restores with circular foreign keys.
Scale every Fly app that writes to the database to zero with fly scale count 0 -a <app>, including worker and scheduler apps, then repeat the copy and compare:
SELECT count(*) FROM orders;
SELECT max(id), (SELECT last_value FROM orders_id_seq) FROM orders;
Exact counts should match on both sides, and each sequence's last_value should be at or above max(id).
The Encore deployment on AWS already reads RDS, so switching means pointing DNS at the AWS environment and leaving the Fly apps at zero. A hand-built setup updates the database URL on the AWS service and restarts it. Keep the Fly database for a few days as a fallback, and for unmanaged Fly Postgres take a final volume snapshot before destroying the app.
For Fly Managed Postgres, run fly mpg proxy with the cluster ID, which listens on 127.0.0.1:16380 by default, and point pg_dump at the connection string from the cluster's dashboard with the host replaced by 127.0.0.1:16380. For an unmanaged Fly Postgres app, run fly proxy 15432:5432 -a your-db-app and connect to 127.0.0.1:15432.
Declare the database in Go with sqldb.NewDatabase("app", sqldb.DatabaseConfig{Migrations: "./migrations"}), use a schema-only dump of the Fly database as the first migration, and deploy to an AWS environment. Then run encore db proxy --env=production and restore the data into the connection string from encore db conn-uri app --env=production.
During the migration, the region only affects how fast the copy runs. After cutover, put RDS in the same AWS region as the services that query it, since every query pays the network latency between them.
Deploy to your cloud on AWS and Google Cloud
without managing infrastructure
Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.