Network transfer is one of the usage metrics that affects your Neon bill. This guide explains what network transfer is, what causes it to increase, how to monitor it, and how to reduce it. For broader cost guidance, see Cost optimization. For plan allowances and pricing, see Plans.

What is network transfer?

Neon measures data sent from your databases through the Neon proxy to clients. All PostgreSQL connections pass through the proxy, including pooled and direct connections, primary computes, and read replicas. All outbound client traffic counts toward network transfer, also known as egress.

There are two types of network transfer:

  • Public network transfer: Data sent over the public internet. Logical replication to any destination counts as public network transfer.
    • Free plan: 5 GB/month included. Exceeding this suspends your compute until the next billing cycle or you upgrade.
    • Launch / Scale plans: 100 GB/month included, then $0.10/GB.
  • Private network transfer: Traffic routed over AWS PrivateLink. Available on the Scale plan only. Billed at $0.01/GB, bi-directional. Unlike public network transfer, which only counts outbound data, private network transfer counts traffic in both directions: data sent from your database to clients and data sent from clients to your database.

In the Console, these appear as Public network transfer and Private network transfer. In the Consumption API, the fields are public_network_transfer_bytes and private_network_transfer_bytes. In project and branch detail API responses, the combined field is data_transfer_bytes.

What causes high network transfer?

The following are common causes of increased network transfer in Neon. See How to monitor to identify these patterns and How to reduce for solutions.

Large query result sets. Using SELECT *, fetching entire tables without LIMIT, missing pagination, or joins that unintentionally multiply rows sends more data than your application needs. ORM defaults can also pull more rows or columns than necessary. This includes queries against read replicas, which pass through the same proxy and count toward network transfer.

High-frequency repeated queries. Querying the database on every page render or API request without caching transfers the same data repeatedly. This is common in serverless environments where each invocation starts fresh. Check the calls column in pg_stat_statements to spot these patterns (see Diagnosing a spike).

Database exports (pg_dump). Full database dumps transfer the entire database over the network. Running frequent scheduled dumps multiplies the total. Compression flags like -Fc do not reduce the data sent from Neon because compression happens client-side after transfer.

Logical replication. Replicating data to external destinations produces a continuous outbound stream. Initial table syncs can create large one-time spikes.

Log export. Sending Postgres logs to Datadog, Grafana Cloud, or OpenTelemetry collectors counts toward network transfer. Logs contain metadata rather than row data, so the volume is typically small relative to other causes.

How to monitor network transfer

important

The Billing page only displays network transfer when usage exceeds the included allowance. To track usage before it results in charges, check the usage panel on the Organization or Project dashboard, or use the Consumption API.

Paid plans receive a weekly usage report by email that includes network transfer usage and cost.

Console organization page

The usage panel on the organization Projects page always displays current network transfer usage across all projects. Individual project dashboards show network transfer for that project.

Organization page usage panel showing network transfer

Console Billing page

Navigate to Organization > Billing to see Public network transfer and Private network transfer. These metrics only appear when your usage exceeds the included allowance and there is an overage charge. For more on the Billing page, see Monitor billing and usage.

Billing page showing network transfer charges

Consumption API for paid plans

tip

On the Free plan? Skip to Project and branch detail APIs for an API option available on all plans.

The /consumption_history/v2/projects endpoint provides programmatic access to network transfer metrics on paid plans.

It supports three granularity levels:

GranularityMaximum time range
hourlyLast 7 days
dailyLast 60 days
monthlyLast year

Use hourly granularity to diagnose recent spikes. Data updates approximately every 15 minutes.

tip

Consumption API calls do not wake suspended computes, so polling does not increase your compute usage.

The following example retrieves hourly public and private network transfer for all projects in an organization over a six-day window:

curl --request GET \
  --url 'https://console.neon.tech/api/v2/consumption_history/v2/projects?org_id=$ORG_ID&from=2026-02-01T00:00:00Z&to=2026-02-07T00:00:00Z&granularity=hourly&metrics=public_network_transfer_bytes,private_network_transfer_bytes' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer $NEON_API_KEY'
Response body (partial)

The response returns one entry per hour for each project, with the requested metrics in each hourly bucket. Metrics with no usage are omitted from the response.

{
  "projects": [
    {
      "project_id": "delicate-dawn-54854667",
      "periods": [
        {
          "period_id": "90c7f107-3fe7-4652-b1da-c61f71043128",
          "period_plan": "launch",
          "period_start": "2026-02-02T18:04:52Z",
          "consumption": [
            {
              "timeframe_start": "2026-02-04T00:00:00Z",
              "timeframe_end": "2026-02-04T01:00:00Z",
              "metrics": [
                {
                  "metric_name": "public_network_transfer_bytes",
                  "value": 8347291
                }
              ]
            },
            {
              "timeframe_start": "2026-02-04T01:00:00Z",
              "timeframe_end": "2026-02-04T02:00:00Z",
              "metrics": [
                {
                  "metric_name": "public_network_transfer_bytes",
                  "value": 1203477
                }
              ]
            }
          ]
        }
      ]
    }
  ],
  "pagination": {
    "cursor": "delicate-dawn-54854667"
  }
}

For full details on parameters, pagination, and polling, see Querying consumption metrics.

Project and branch detail APIs

The data_transfer_bytes field on the Get project details and Get branch details endpoints returns a running total of network transfer for the current billing period. Unlike the Consumption API, which provides time-windowed breakdowns, this value resets at the start of each billing cycle and is not broken down by hour or day. These endpoints are available on all plans.

Get project details:

curl --request GET \
  --url https://console.neon.tech/api/v2/projects/$PROJECT_ID \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer $NEON_API_KEY'

The response includes data_transfer_bytes in the project object:

{
  "project": {
    "data_transfer_bytes": 40821459,
    ...
  }
}

Get branch details:

curl --request GET \
  --url https://console.neon.tech/api/v2/projects/$PROJECT_ID/branches/$BRANCH_ID \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer $NEON_API_KEY'

The response includes data_transfer_bytes in the branch object:

{
  "branch": {
    "data_transfer_bytes": 40820887,
    ...
  }
}

Diagnosing a spike

Neon does not provide per-query or per-connection network transfer breakdowns. To identify the source of a spike, use hourly granularity from the Consumption API to narrow down the time window, then correlate it with known operations: scheduled pg_dump jobs, logical replication initial syncs, application deployments, or changes to query patterns. If you have multiple projects, compare per-project hourly data to isolate which project is responsible. On the Free plan, compare data_transfer_bytes across branches using the branch detail API to identify which branch contributes the most. Once you identify the branch, connect to it and run the pg_stat_statements queries below to find the top queries.

To find which queries return the most rows, use the pg_stat_statements extension. The rows column is not an exact byte count, but queries returning many rows or wide rows (TEXT, JSONB, BYTEA columns) are the most likely contributors to high network transfer.

Queries that returned the most total rows across all executions:

SELECT
  query,
  calls,
  rows AS total_rows,
  rows / calls AS avg_rows_per_call
FROM pg_stat_statements
WHERE calls > 0
ORDER BY rows DESC
LIMIT 10;

tip

In Neon, scaling to zero clears pg_stat_statements data, so computes that recently woke up already have fresh statistics. For long-running computes, run SELECT pg_stat_statements_reset(); to start a clean measurement window. This cannot be undone and resets stats for all database roles.

For wire-level analysis of exact message sizes, see Elephantshark, an open-source Postgres traffic monitor from Neon.

How to reduce network transfer

For broader cost reduction strategies across all billing metrics, see Cost optimization.

Optimize query results. Select only the columns you need. Use pagination (LIMIT/OFFSET or cursor-based) instead of fetching all rows at once. Use SQL aggregations (SUM, COUNT, GROUP BY) to summarize data in the database rather than returning raw rows to your application.

Reduce pg_dump frequency. Use Neon snapshots with scheduled backups as a backup alternative that keeps data within Neon. Reserve pg_dump for migrations or situations that require an external copy. When you do run pg_dump, use -t to dump only specific tables, --exclude-table to skip large ones, or --schema-only if you only need the schema. Note that compression flags (-Fc, -Z) compress the output file on the client after the data has already been sent from Neon, so they do not reduce your billed network transfer.

Manage logical replication. Initial table syncs can produce large spikes in network transfer. Dropping and re-creating a replication slot forces a new full sync, so avoid resetting slots as a troubleshooting step unless necessary. Replicate only the tables or columns you need by using row filters (WHERE clauses) and column lists on CREATE PUBLICATION (PostgreSQL 15+). Monitor replication lag and throughput to understand ongoing transfer volume.

Use Private Link for internal traffic. If your application runs in AWS, Private Networking (Scale plan) routes traffic over PrivateLink at $0.01/GB instead of $0.10/GB for public network transfer beyond the included allowance.

Use the egress optimizer agent skill

An agent skill is available that guides your AI assistant through diagnosing and fixing application-side query patterns that cause excessive egress. The skill walks through analyzing your codebase for anti-patterns (such as SELECT *, missing pagination, high-frequency queries on static data, and application-side aggregation), applying fixes, and verifying with tests. To add it to your AI assistant:

npx skills add neondatabase/agent-skills -s neon-postgres-egress-optimizer

tip

Building a platform on Neon? You can cap per-project network transfer with consumption limits.

References