Automating Neon Postgres Tuning with an AI Database Agent
There are two kinds of index recommendations. The first is a line in a report: "consider adding an index on orders(customer_id)." Somebody still has to check it isn't redundant, guess its write cost, test it somewhere, and hope production behaves like staging. The second kind arrives already proven: the index was created on a copy-on-write branch of your actual production data ten minutes ago, the offending query re-run against it, and the proposal shows 3,400 ms → 45 ms measured on your rows — with the DDL waiting for your approval before it goes anywhere near main.
Neon Postgres is one of the few databases where the second kind is cheap enough to be the default: branching gives you a disposable clone of production in seconds, turning tuning from prediction into measurement. The catch is that nobody has time to run that loop by hand every day.
This is part three of our Neon Postgres performance series. Part one mapped what performance means on serverless Postgres — cold starts, autoscaling ceilings, pooled versus direct connections, and how compute-hours pricing converts slow queries into money. Part two ran the DIY audit with native tools: the console monitoring dashboard, pg_stat_statements, EXPLAIN (ANALYZE, BUFFERS), and branching as a manual test bench. This article is about making that loop continuous: Tony, CloudThinker's database agent, watching the same signals every day and rehearsing every fix on a branch before it ever touches main.
Why Neon changes the automation math
Two properties of Neon make continuous tuning more valuable here than on a conventional Postgres host.
First, the bill is a live feedback signal. Neon charges for compute-hours, so a query that pins your endpoint at its autoscaling ceiling for an hour a day is a visible line item — and a minimum compute size left at 2 CU on a project that idles at 0.3 CU is money spent on nothing. On Neon, query tuning and cost tuning are the same activity, and both drift weekly as workloads change.
Second, validation is nearly free. On RDS you'd restore a snapshot to test an index against production-scale data — slow and expensive, so almost nobody does it. On Neon, a branch is a copy-on-write clone that exists in seconds and costs only the compute you run against it. Part two showed the manual branch-test-measure-apply workflow. The gap between knowing it and running it for every finding, every week, is exactly the gap an agent fills.
Connecting: OAuth, about two minutes
Tony connects to Neon through the OAuth flow: you click connect, authorize CloudThinker against your Neon account, pick the projects it may see, and the first analysis starts. No connection strings pasted into a form, no manually created database roles, and access is read-only by default — Tony can query statistics views and read compute and branch configuration, but nothing at connection time grants it the right to change your schema or endpoints. Revoking access is one click in Neon's account settings. The whole flow takes about two minutes; the Neon connection guide walks through it screen by screen, including exactly what the authorization does and doesn't allow.
If pg_stat_statements isn't enabled on the database yet, Tony flags that on the first pass — it's a single CREATE EXTENSION on Neon, covered in part two, and it's the highest-value prerequisite for everything that follows.
What Tony watches on a Neon project
Once connected, Tony runs the part-two audit as a standing process rather than a quarterly afternoon:
- Slow query trends. The top of
pg_stat_statementsby total and mean time, tracked over time, so a query that regresses after a deploy is flagged as a regression with a date — not rediscovered three invoices later. - Autoscaling headroom. How often the endpoint sits at its maximum compute size, and for how long. Tony correlates those windows with the specific queries driving them, so the answer might be "raise the max" or might be "fix this one scan."
- The opposite failure: paying for a floor. Minimum compute sizes and scale-to-zero settings that don't match how each branch is actually used — the dev branch billing for 2 CU around the clock, or the production endpoint suspending overnight and serving the first customer a multi-second cold start.
- Connection saturation. Applications on the direct endpoint that should be on the pooled one, connection counts creeping toward the limit, and the deploy-time spike pattern that precedes intermittent connection errors.
- Index health. Unused indexes taxing every write, duplicate indexes, and missing ones implied by sequential-scan-heavy access patterns — the unindexed foreign key on a large child table remains the classic.
None of these checks is exotic; part two proved you can run each one yourself. What changes is cadence and memory: the dashboard you checked once becomes a signal that checks itself, with the before/after comparison attached when something moves.
Every proposal is rehearsed on a branch first
This is the part that's genuinely different on Neon. When Tony wants to propose an index or a query rewrite, it doesn't reason from the planner's estimates alone — it creates a branch from main, applies the candidate change there, replays the affected queries against your real data distribution, and measures. The proposal you review contains:
- the exact queries from
pg_stat_statementsthat motivated it, with call counts and current total time; - the measured before/after timings from the branch run — real numbers from your rows, not estimated cost units;
- the
EXPLAIN (ANALYZE, BUFFERS)comparison from both sides; - the write-side cost, because every index taxes INSERT and UPDATE, and a proposal on a hot table says so;
- the DDL itself, written as
CREATE INDEX CONCURRENTLYso applying it to main doesn't lock the table.
The branch is disposable and Tony cleans it up afterward, so the rehearsal costs a few minutes of small-compute time. "Drop this index" proposals get the same treatment in reverse: zero scans across the observation window, plus a branch-verified check that the queries you care about don't regress without it. You're reviewing an experiment that already ran, not a hypothesis you now have to test.
Graduated autonomy: nothing runs DDL on main without approval
Every action class has an autonomy level you set per project and per branch:
- Notify — Tony reports the finding. Nothing else. This is the default for everything.
- Suggest — Tony proposes the specific change with branch-measured impact and a rollback path.
- Approve — Tony prepares the change and executes only after a named human approves it in chat.
- Autonomous — Tony executes and reports. Teams that use this at all reserve it for reversible, low-blast-radius actions on non-production branches — and only after weeks of watching Tony be right at the Approve level.
One rule sits above the levels: no DDL executes on main without approval. Creating a test branch is a low-risk, reversible action; altering your production schema is not, and the two are never in the same class. Anything that changes main — index creation or removal, compute-size changes, endpoint settings — requires both explicitly granted write access and a human decision, and every proposal, approval, and execution lands in an audit trail with its evidence and its approver.
What a first week typically surfaces
The numbers below are illustrative — a composite of what a first analysis tends to return on a mid-market Neon setup: a production project around 60 GB, autoscaling 1–4 CU, a handful of preview and dev branches. Yours will differ.
| Finding | Detail | Typical impact |
|---|---|---|
| Morning cold starts | Production endpoint suspends overnight; first query of the day takes seconds instead of milliseconds | Daily latency spike on a customer-facing path |
| Autoscaling ceiling | Endpoint pinned at 4 CU for ~90 min/day, driven by two reporting queries | Queuing during peak; compute-hours cost |
| Dev branch floor | Dev branch minimum compute left at 2 CU, idle overnight and weekends | Steady spend for zero work |
| Direct-endpoint traffic | App connecting to the direct endpoint; spikes to ~85% of the connection limit during deploys | Intermittent connection errors |
| Missing FK index | Unindexed foreign key on a 40M-row child table; parent deletes scan it | Multi-second locks on delete paths |
| Unused indexes | 9 indexes, 11 GB total, zero scans in 60 days | Write amplification + storage |
| Query regression | Search endpoint 12x slower since a schema change three weeks ago | p95 breach nobody had dated |
Nothing here is clever. The value is that the table refreshes itself daily, each row arrives with a branch-validated, approval-gated fix, and the regression gets a date attached the week it happens instead of during the next incident review.
Prompts to try in your first session
Tony is conversational — you ask in plain language and get answers cited against pg_stat_statements and the project's configuration, so you can verify rather than trust:
"Tony, show the top 10 queries by total execution time this week and flag anything that regressed versus the previous 30 days."
"How much time did the production endpoint spend at its autoscaling max last week, and which queries were running during those windows?"
"Create a branch, test an index for the slow search query on it, and show me the measured before and after — don't touch main."
What Tony will not do
Worth stating plainly, because "AI agent connected to production Postgres" should make you ask:
- It is read-only by default. The OAuth connection starts with observation. Changing anything requires you to explicitly grant write access and raise the autonomy level above Notify.
- It never runs DDL on main without approval. Branch rehearsals are disposable; your production schema changes only when a named human approves that specific action.
- It does not touch anything unfindable in the audit trail. Every proposal, branch experiment, and execution is logged with its evidence and approver.
- It does not replace judgment on architecture. Tony can measure that a table wants partitioning before it wants another index; whether to partition is an engineering decision, and it stays yours.
From snapshot to standing process
You know what performance means on Neon, and you know how to audit it with the console, pg_stat_statements, and a branch. What's left is cadence — and cadence is an automation problem, not an effort problem. Teams that move from occasional tuning passes to continuous, branch-validated, approval-gated tuning typically stop paying for idle compute floors, catch regressions the week they ship, and keep the autoscaling ceiling for genuine load instead of unindexed scans.
Try CloudThinker free — 100 premium credits, no card required — and follow the Neon connection guide to see your own first findings table within the hour.
