The Brief
FinEdge came to us with a problem most startups dread: a legacy system that worked well enough to get them to Series A, but was now actively killing growth.
Portfolio pages took 12 seconds to load. Their churn rate in the first 90 days was 34%. Their engineers had tried to refactor the Rails monolith for 18 months without success.
They had 10 weeks before their Q1 marketing push. We had to ship or they would miss their window.
What We Did Differently
Most agencies would have quoted a 6-month rebuild. We did something different: we started by understanding why the old system was slow, not just that it was slow.
The root cause was a combination of N+1 database queries on every portfolio load and a complete absence of caching. The Rails code itself was fine — the data access patterns were the problem.
The Architecture Decision
We chose Next.js with server-side rendering for the portfolio pages, Redis for caching portfolio calculations, and kept PostgreSQL as the primary database. We did not use a microservices architecture — that would have added complexity without solving the actual problem.
// Before: 47 database queries per portfolio load
// After: 3 queries + Redis cache with 1hr TTL
const portfolio = await cache.getOrFetch(
`portfolio:${userId}`,
() => db.portfolio.findWithHoldings(userId),
3600
);
The Migration Strategy
We ran both systems in parallel for 3 weeks. The new system wrote to both databases during the transition period. This meant:
- Zero data loss risk
- Easy rollback if anything went wrong
- Ability to compare outputs between old and new systems in production
Results
- Page load time: 12s → 0.9s
- User retention: up 340% in Q1
- Support tickets about performance: down 68%
- Engineering team could now ship features in days instead of weeks
What We Learned
The biggest lesson: the problem is almost never what the client thinks it is. FinEdge thought they needed a new framework. They needed better data access patterns. The new framework was a side effect of fixing those patterns properly.
When a client comes to us with a "rewrite everything" request, the first question we ask is: what would happen if we fixed the three worst things about the current system? Sometimes that is enough. In FinEdge's case, the legacy code had accumulated enough debt that a rebuild was genuinely the right call — but we went in with that question answered, not assumed.