At ButFor, I inherited a Node.js API that handled claims processing, user management, and business workflows. The system worked, but it was hitting ceilings: response times were inconsistent, the MySQL database was struggling under query load, and infrastructure costs were climbing.

The decision to migrate to FastAPI was not about language preference. It was about the specific constraints of the system: CPU-bound data processing, complex query patterns, and a need for predictable performance under variable load. Python with FastAPI and asyncpg handled these constraints better than the existing Node.js setup.

The migration was not the performance gain

Here is the part that surprises most developers: switching frameworks did not directly produce a 50% performance improvement. The improvement came from the decisions the migration forced us to make.

When you rebuild a system, you have a rare opportunity to question every assumption. We did not port the Node.js code to Python. We redesigned the data access layer, rethought the query patterns, and changed how the system interacted with the database.

  • N+1 queries disappeared. The old system had多处 places where a list endpoint made a query for the list and then individual queries for each item. The new system used eager loading, batch queries, and materialized views.
  • Connection pooling was reconfigured. The old setup used default pool settings that caused contention under load. We tuned pool sizes, timeouts, and queue limits based on observed traffic patterns.
  • Query optimization. The migration forced a review of every query. We added composite indexes, rewrote slow joins, and eliminated full-table scans. Some queries that took 800ms now take 15ms.

Infrastructure changes mattered more than code

The 20% infrastructure cost reduction did not come from using a cheaper database. It came from using the database more efficiently.

We migrated from a large MySQL instance on dedicated hardware to Supabase (PostgreSQL) with connection pooling, read replicas, and auto-scaling. The PostgreSQL query planner handled our complex join patterns significantly better than MySQL, and the Supabase managed service eliminated the operational overhead of maintaining the database server.

The real savings were in compute. Because the API handled requests faster, we needed fewer instances to serve the same traffic. CPU utilization dropped, memory usage stabilized, and the auto-scaling configuration could be relaxed. The system became cheaper to run because it was more efficient, not because we found a cheaper hosting provider.

Lessons for anyone considering a migration

Do not migrate and optimize simultaneously

We made the mistake of changing too many things at once. The API framework changed, the database changed, the query patterns changed, the deployment model changed. When something broke, it was difficult to isolate the cause. If I did it again, I would stage the changes: migrate the framework first with minimal changes, then optimize.

Measure before and after

We had good APM data on the Node.js system: p50, p95, and p99 response times, error rates, throughput, and resource utilization. This made it possible to compare the new system objectively. Without that baseline, the 50% improvement claim would be guesswork.

Plan the rollback

We kept the old system running in parallel for two weeks, routing a percentage of traffic to the new API and gradually increasing. When we found issues — and we did — the old system was a single DNS change away. This saved us at least three times during the migration.

The result

After the migration, API p50 response times dropped from 320ms to 120ms. Infrastructure costs decreased by approximately 20%. The system became easier to maintain, and the team could iterate faster because FastAPI's type system and auto-generated documentation made the codebase more accessible to new developers.

But the lesson that stuck with me is this: the migration was the excuse, not the cause. The real improvements came from questioning assumptions, measuring outcomes, and being willing to change more than just the framework.