figma-performance-tuning
Optimize Figma REST API performance with caching, partial fetches, and connection reuse. Use when experiencing slow API responses, reducing bandwidth for large files, or optimizing request throughput for Figma integrations. Trigger with phrases like "figma performance", "figma slow", "figma caching", "figma optimize", "figma large file".
What this skill does
# Figma Performance Tuning
## Overview
Optimize Figma REST API performance. Large Figma files can return multi-megabyte JSON responses. Key strategies: fetch only what you need, cache aggressively, and batch requests.
## Prerequisites
- Working Figma API integration
- Understanding of your access patterns (which endpoints, how often)
## Instructions
### Step 1: Reduce Payload Size
```typescript
// BAD: fetches the entire file tree (can be 10+ MB for large files)
const file = await fetch(`https://api.figma.com/v1/files/${fileKey}`, {
headers: { 'X-Figma-Token': token },
}).then(r => r.json());
// GOOD: use depth parameter to limit tree depth
// depth=1 returns only pages (CANVAS nodes), not their children
const fileMeta = await fetch(
`https://api.figma.com/v1/files/${fileKey}?depth=1`,
{ headers: { 'X-Figma-Token': token } }
).then(r => r.json());
// GOOD: fetch only specific nodes you need
const nodes = await fetch(
`https://api.figma.com/v1/files/${fileKey}/nodes?ids=${nodeIds.join(',')}`,
{ headers: { 'X-Figma-Token': token } }
).then(r => r.json());
// GOOD: use plugin_data or branch_data params only when needed
// By default, plugin data and branch data are NOT returned
```
### Step 2: Response Caching
```typescript
import { LRUCache } from 'lru-cache';
// File metadata changes rarely -- cache for 5 minutes
const fileCache = new LRUCache<string, any>({
max: 100,
ttl: 5 * 60 * 1000, // 5 minutes
});
async function getCachedFile(fileKey: string, token: string) {
const cached = fileCache.get(fileKey);
if (cached) return cached;
const file = await fetch(
`https://api.figma.com/v1/files/${fileKey}?depth=1`,
{ headers: { 'X-Figma-Token': token } }
).then(r => r.json());
fileCache.set(fileKey, file);
return file;
}
// Image URLs expire after 30 days -- cache them but with a shorter TTL
const imageUrlCache = new LRUCache<string, string>({
max: 1000,
ttl: 24 * 60 * 60 * 1000, // 1 day (well within 30-day expiry)
});
async function getCachedImageUrl(
fileKey: string, nodeId: string, format: string, token: string
): Promise<string | null> {
const cacheKey = `${fileKey}:${nodeId}:${format}`;
const cached = imageUrlCache.get(cacheKey);
if (cached) return cached;
const data = await fetch(
`https://api.figma.com/v1/images/${fileKey}?ids=${nodeId}&format=${format}`,
{ headers: { 'X-Figma-Token': token } }
).then(r => r.json());
const url = data.images[nodeId];
if (url) imageUrlCache.set(cacheKey, url);
return url;
}
```
### Step 3: Webhook-Driven Cache Invalidation
```typescript
// Instead of polling, use webhooks to know when to re-fetch
// See figma-webhooks-events for full webhook setup
async function handleFileUpdate(fileKey: string) {
// Invalidate cached data for this file
fileCache.delete(fileKey);
// Proactively re-fetch commonly accessed data
const token = process.env.FIGMA_PAT!;
await getCachedFile(fileKey, token);
console.log(`Cache invalidated and refreshed for ${fileKey}`);
}
```
### Step 4: Batch Node Fetches
```typescript
// The /nodes endpoint accepts multiple IDs -- batch them
// Max practical batch size: ~50-100 IDs per request
async function batchFetchNodes(
fileKey: string,
nodeIds: string[],
token: string,
batchSize = 50
): Promise<Map<string, any>> {
const results = new Map<string, any>();
for (let i = 0; i < nodeIds.length; i += batchSize) {
const batch = nodeIds.slice(i, i + batchSize);
const ids = encodeURIComponent(batch.join(','));
const data = await fetch(
`https://api.figma.com/v1/files/${fileKey}/nodes?ids=${ids}`,
{ headers: { 'X-Figma-Token': token } }
).then(r => r.json());
for (const [id, node] of Object.entries(data.nodes)) {
results.set(id, node);
}
}
return results;
}
```
### Step 5: Connection Reuse
```typescript
import { Agent } from 'undici';
// Reuse HTTP connections to api.figma.com
const figmaAgent = new Agent({
keepAliveTimeout: 30_000,
keepAliveMaxTimeout: 60_000,
connections: 5,
});
// Use with Node.js 18+ built-in fetch
async function optimizedFetch(path: string, token: string) {
return fetch(`https://api.figma.com${path}`, {
headers: { 'X-Figma-Token': token },
// @ts-ignore -- dispatcher is a Node.js fetch option
dispatcher: figmaAgent,
});
}
```
## Output
- Reduced API payload sizes with `depth` and `nodes` endpoints
- Response caching with appropriate TTLs
- Webhook-driven cache invalidation
- Batched node fetches reducing request count
- Connection reuse for lower latency
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| Stale cache | No invalidation | Use webhooks to invalidate on changes |
| Out of memory | Caching full file JSON | Use `depth=1` or `nodes` endpoint |
| Slow image exports | Large batch, high scale | Reduce scale; batch in groups of 50 |
| Expired image URLs | Cached URL older than 30 days | Set image cache TTL to <24h |
## Resources
- [Figma File Endpoints](https://developers.figma.com/docs/rest-api/file-endpoints/)
- [Figma Rate Limits](https://developers.figma.com/docs/rest-api/rate-limits/)
- [lru-cache](https://github.com/isaacs/node-lru-cache)
## Next Steps
For cost optimization, see `figma-cost-tuning`.
Related in Design
contribute
IncludedLocal-only OSS contribution command center. Auto-refreshes the user's in-flight PR and issue state on invoke so conversations start with full context — no need to brief Claude on what's in flight. Helps the user find issues to contribute to on GitHub, builds per-repo dossiers of what each upstream expects (CLA, DCO, branch convention, AI policy, draft-first, review bots, issue templates), runs deterministic gates before any external action so AI-assisted contributions don't reach maintainers as slop. State is markdown-only: candidate files at ~/.contribute-system/candidates/, repo dossiers at ~/.contribute-system/research/, append-only event log at ~/.contribute-system/log.jsonl. No database, no cloud calls. Use when the user asks about their PRs / issues / contributions, wants to find new work to take on, claim an issue, build/refresh a repo's dossier, or draft a Design Issue or PR. Trigger with "/contribute", "what's my PR status", "find a contribution", "claim issue X", "draft a Design Issue for Y", "refresh dossier for Z".
architectural-analysis
IncludedUser-triggered deep architectural analysis of a codebase or scoped subtree across eight modes — information architecture, data flow, integration points, UI surfaces, interaction patterns, data model, control flow, and failure modes. This skill should be used when the user asks to "diagram this codebase," "map the architecture," "show the data flow," "give me an ERD," "trace control flow," "find the integration points," "verify the layout pattern," "audit the UX architecture," or any similar request whose primary deliverable is mermaid diagrams plus cited reports under docs/architecture/. Dispatches haiku/sonnet sub-agents in parallel for per-mode exploration, then verifies every citation mechanically before any node lands in a diagram. Not for one-off prose explanations of code (use code-explanation) or for high-level system design from scratch (use system-design).
mcp
IncludedModel Context Protocol (MCP) server development and tool management. Languages: Python, TypeScript. Capabilities: build MCP servers, integrate external APIs, discover/execute MCP tools, manage multi-server configs, design agent-centric tools. Actions: create, build, integrate, discover, execute, configure MCP servers/tools. Keywords: MCP, Model Context Protocol, MCP server, MCP tool, stdio transport, SSE transport, tool discovery, resource provider, prompt template, external API integration, Gemini CLI MCP, Claude MCP, agent tools, tool execution, server config. Use when: building MCP servers, integrating external APIs as MCP tools, discovering available MCP tools, executing MCP capabilities, configuring multi-server setups, designing tools for AI agents.
react-native-skia
IncludedDesign, build, debug, and optimise high-polish animated graphics in React Native or Expo using @shopify/react-native-skia, Reanimated, and Gesture Handler. Use when the user wants canvas-driven UI, shaders, paths, rich text, image filters, sprite fields, Skottie, video frames, snapshots, web CanvasKit setup, or performance tuning for custom motion-heavy elements such as loaders, hero art, cards, charts, progress indicators, particle systems, or gesture-driven surfaces. Also use when the user asks for fluid, glow, glass, blob, parallax, 60fps/120fps, or GPU-friendly animated effects in React Native, even if they do not explicitly say "Skia". Do not use for ordinary form/layout work with standard views.
plaid
IncludedProduct Led AI Development — guides founders from idea to launched product. Six capabilities: Idea (discover a product idea), Validate (pressure-test the idea against fatal flaws, problem reality, competition, and 2-week MVP feasibility), Plan (vision intake + document generation), Design (translate image references into a design.md spec), Launch (go-to-market strategy), and Build (roadmap execution). Use when someone says "PLAID", "plaid idea", "help me find an idea", "product idea", "idea from my business", "idea from my expertise", "plaid validate", "validate my idea", "pressure-test", "is this idea good", "find fatal flaws", "validate the problem", "plan a product", "define my vision", "generate a PRD", "product strategy", "plaid design", "design from image", "translate image to design", "create design.md", "extract design tokens", "plaid launch", "go-to-market", "launch plan", "GTM strategy", "launch playbook", "plaid build", "build the app", "start building", or "execute the roadmap".
nextjs-framer-motion-animations
IncludedAdds production-safe Motion for React or Framer Motion animations to Next.js apps, including reveal, hover and tap micro-interactions, whileInView, stagger, AnimatePresence, layout and layoutId transitions, reorder, scroll-linked UI, and lightweight route-content transitions. Use when the user asks to add, refactor, or debug Motion or Framer Motion in App Router or Pages Router codebases, especially around server/client boundaries, reduced motion, LazyMotion, bundle size, hydration, or route transitions. Avoid for GSAP-style timelines, WebGL or 3D scenes, heavy scroll storytelling, or CSS-only effects unless Motion is explicitly requested.