Performance problems are usually specific#
When an application gets slow, the instinct is to upgrade the server. That buys a few months at best, and rarely fixes the cause. In most data-heavy applications a small number of queries, often an N+1 loop, a missing composite index or a report scanning a whole table, account for most of the time spent. Find those and the application speeds up without new hardware, and stays fast as data keeps growing.
The hard part isn't knowing that indexes exist. It's finding which three queries out of thousands are hurting you, understanding why the database chose a bad plan, and changing things safely on a live system with real customers.
Signs your application has a performance problem#
- Pages or API endpoints get slower every month as tables grow, even though the code hasn't changed.
- Database CPU sits near its limit, and hosting costs keep rising.
- Reports, imports and exports time out, or lock up the app while they run.
- Users see occasional errors under load that nobody can reproduce locally.
- Someone has suggested a bigger server or a different database, and you'd like evidence before spending.
What I optimise#
Slow queries#
Rewriting joins and subqueries, fixing N+1 patterns in the ORM (Eloquent and Prisma make them easy to write by accident), paginating large tables efficiently, and selecting only the columns that are needed.
Indexing#
Composite and partial indexes that match your real filters and sort orders, verified with the query plan. I also remove duplicate and unused indexes that slow down every write.
Schema and data design#
Denormalising where it genuinely helps, adding summary tables for dashboards and reports, and archiving old data so hot tables stay small.
Background processing#
Moving imports, exports, emails, PDFs and third-party calls out of the web request into queued jobs, so users get a fast response and heavy work runs on its own schedule with retries.
Caching#
Caching expensive, rarely-changing results in Redis, with clear invalidation rules, after the underlying query has been fixed.
Search and vector workloads#
Full-text search and vector search with PostgreSQL and pgvector, tuned for the balance of speed and accuracy your feature needs.
Measured, not guessed#
Every change is measured before and after on realistic data. I use slow-query logs, EXPLAIN ANALYZE, application traces and request timings, and I change one thing at a time so each improvement can be attributed. You get a short report of what was slow, why, what changed and the measured result, so the knowledge stays with your team rather than in my head.
Changing a live database safely#
Performance work happens on production systems with real customers. Index builds run without locking tables where the database supports it, migrations are split into safe steps, and every change has a rollback plan. Most optimisation work causes no customer-facing downtime at all.
Real performance work#
- Violerts: moving synchronous processing onto Horizon-based background jobs let the platform expand from 3–4 to 12+ NYC municipal datasets while keeping the app responsive, alongside a 60%+ frontend performance improvement in the affected workflows.
- Multi-carrier SIM activation: one-by-one activations replaced by queued CSV batches, with polling replaced by a live Server-Sent Events stream, while keeping three-tier wallet accounting exactly consistent.
- Henceforward AI: vector search on PostgreSQL with pgvector to power retrieval for a RAG chatbot, keeping all data in one database.
Common causes I find again and again#
- N+1 queries hidden inside loops or serializers, turning one page load into hundreds of queries.
- Missing composite indexes for the exact filter and sort a list page uses.
- Offset pagination on very large tables, which gets slower the further users page.
- Counting everything for badges and dashboards on every request instead of maintaining counts.
- Synchronous third-party calls in the request path, so one slow provider slows the whole app.
- Long transactions and locks from batch jobs running during peak hours.
Keeping it fast after the fix#
Performance isn't a one-off. Data keeps growing, new features add new queries, and a fast page can quietly become slow again. So the work ends with guardrails:
- Monitoring and alerts on slow queries, response times and database load, so regressions are caught in days rather than months.
- Query-count checks in tests for the busiest pages, so an accidental N+1 fails the build instead of reaching production.
- A short guide for your team on the patterns that caused trouble and how to avoid them.
When a bigger server really is the answer#
Sometimes the queries are already good and the workload has simply grown. Then the right move is more capacity: a larger database instance, read replicas for reporting, or a separate worker server for queues. The difference is that you'll make that decision with evidence, and you'll know exactly what the extra spend buys.
Related services#
Performance work often goes hand in hand with legacy modernization or ongoing Laravel development, and sometimes needs infrastructure changes through cloud and DevOps. For data-heavy products specifically, see real estate & data platforms.
Working together#
Performance engagements usually start with a focused audit: access to monitoring or logs, a copy of the schema, and a list of the slowest pages or endpoints. You get findings ranked by impact and effort, then I implement the fixes you approve. It can run as a fixed-scope project or as part of a retainer.
Is your application slowing down? Book a free call and describe the symptoms. I'll tell you where I'd look first.