| name | performance-guidelines |
| description | Performance guidelines for TypeScript including frontend optimization, backend query optimization, caching, memory management, and profiling. Auto-loaded when working on performance-sensitive code. |
| category | guideline |
| user-invocable | false |
Performance Guidelines
Core Principles
- Measure first - Don't optimize without profiling
- Optimize bottlenecks - Focus on hot paths
- Consider tradeoffs - Performance vs. readability/maintainability
- Set budgets - Define acceptable thresholds
- Monitor continuously - Performance degrades over time
Performance Budgets
Define Thresholds
const PERFORMANCE_BUDGETS = {
firstContentfulPaint: 1500,
largestContentfulPaint: 2500,
timeToInteractive: 3500,
mainBundle: 200,
chunkSize: 50,
totalSize: 500,
apiResponse: 200,
dbQuery: 50,
frameRate: 60,
inputLatency: 100,
};
Frontend Performance
Bundle Optimization
const HeavyComponent = lazy(() => import('./HeavyComponent'));
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
const routes = [
{
path: '/dashboard',
component: lazy(() => import('./pages/Dashboard')),
},
{
path: '/settings',
component: lazy(() => import('./pages/Settings')),
},
];
Memoization
const expensiveResult = useMemo(() => {
return items.filter(complexFilter).sort(complexSort);
}, [items]);
const handleClick = useCallback((id: string) => {
setSelected(id);
}, []);
const MemoizedComponent = memo(function Component({ data }: Props) {
return <div>{data.name}</div>;
});
const filteredItems = computed(() => {
return items.value.filter(complexFilter).sort(complexSort);
});
Backend Performance
Database Query Optimization
const users = await db.users.findMany();
for (const user of users) {
user.orders = await db.orders.findMany({ where: { userId: user.id } });
}
const users = await db.users.findMany({
include: { orders: true },
});
const users = await db.users.findMany();
const userIds = users.map(u => u.id);
const orders = await db.orders.findMany({
where: { userId: { in: userIds } },
});
Pagination
async function getUsers(page: number, limit: number = 20) {
const offset = (page - 1) * limit;
const [users, total] = await Promise.all([
db.users.findMany({
skip: offset,
take: limit,
orderBy: { createdAt: 'desc' },
}),
db.users.count(),
]);
return {
data: users,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
},
};
}
async function getUsersCursor(cursor?: string, limit: number = 20) {
const users = await db.users.findMany({
take: limit + 1,
cursor: cursor ? { id: cursor } : undefined,
: cursor ? : ,
: { : },
});
hasMore = users. > limit;
items = hasMore ? users.(, -) : users;
{
: items,
: hasMore ? items[items. - ]. : ,
};
}
Common Anti-Patterns
Avoid These
function Component({ items }) {
return items.map(item => (
<Item key={item.id} onClick={() => handleClick(item.id)} />
));
}
function Component({ items }) {
const handleItemClick = useCallback((id: string) => {
handleClick(id);
}, []);
return items.map(item => (
<Item key={item.id} onClick={handleItemClick} id={item.id} />
));
}
const result = heavyComputation(largeData);
const worker = new Worker('./heavy-worker.js');
worker.postMessage(largeData);
worker.onmessage = (e) => (e.);
data = fs.();
data = fs..();
Known Gotchas
Premature Optimization
Hidden Costs
const copy = JSON.parse(JSON.stringify(obj));
const copy = structuredClone(obj);
const result = arr.filter(...).map(...).reduce(...);
Browser Reflows
elements.forEach(el => {
const height = el.offsetHeight;
el.style.height = `${height + 10}px`;
});
const heights = elements.map(el => el.offsetHeight);
elements.forEach((el, i) => {
el.style.height = `${heights[i] + 10}px`;
});
Additional References