Figma Reliability Patterns

SkillMedia

'Build resilient Figma integrations with circuit breakers, fallbacks,

Use Figma Reliability Patterns in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add Figma Reliability Patterns and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the Figma Reliability Patterns skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Figma Reliability PatternsStart free

What this skill tells your AI

The instructions your AI receives, as published by jeremylongshore/tons-of-skills-marketplace in skills/.curated/figma-reliability-patterns/SKILL.md and read by ahel’s review.

Overview

Production reliability patterns for Figma REST API integrations. Figma is an external dependency -- your application must handle its outages, rate limits, and slow responses without cascading failures.

Prerequisites

  • Working Figma API integration
  • Understanding of circuit breaker pattern
  • Cache or file system for fallback data

Instructions

Step 1: Circuit Breaker

// Prevent cascading failures when Figma is down
class FigmaCircuitBreaker {
  private failures = 0;
  private lastFailure = 0;
  private state: 'closed' | 'open' | 'half-open' = 'closed';

  constructor(
    private threshold = 5,        // Open after 5 failures
    private resetTimeMs = 30_000  // Try again after 30s
  ) {}

  async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === 'open') {
      if (Date.now() - this.lastFailure > this.resetTimeMs) {
        this.state = 'half-open';
        console.log('[figma-circuit] State: half-open (testing recovery)');
      } else {
        throw new Error('Figma circuit breaker is OPEN -- failing fast');
      }
    }

    try {
      const result = await fn();
      if (this.state === 'half-open') {
        this.state = 'closed';
        this.failures = 0;
        console.log('[figma-circuit] State: closed (recovered)');
      }
      return result;
    } catch (error) {
      this.failures++;
      this.lastFailure = Date.now();

      if (this.failures >= this.threshold) {
        this.state = 'open';
        console.warn(`[figma-circuit] State: OPEN after ${this.failures} failures`);
      }
      throw error;
    }
  }

  getState() { return this.state; }
}

const figmaBreaker = new FigmaCircuitBreaker();

// Usage
async function safeFigmaCall<T>(fn: () => Promise<T>): Promise<T> {
  return figmaBreaker.execute(fn);
}

Step 2: Cached Fallback

import { readFileSync, writeFileSync, existsSync } from 'fs';

// Serve cached data when Figma is unavailable
class FigmaFallbackCache {
  constructor(private cacheDir = '.figma-cache') {}

  private getPath(key: string) {
    return `${this.cacheDir}/${key.replace(/[^a-zA-Z0-9]/g, '_')}.json`;
  }

  save(key: string, data: any) {
    const { mkdirSync } = require('fs');
    mkdirSync(this.cacheDir, { recursive: true });
    writeFileSync(this.getPath(key), JSON.stringify({
      data,
      cachedAt: new Date().toISOString(),
    }));
  }

  load(key: string): { data: any; cachedAt: string } | null {
    const path = this.getPath(key);
    if (!existsSync(path)) return null;
    return JSON.parse(readFileSync(path, 'utf-8'));
  }
}

const fallbackCache = new FigmaFallbackCache();

async function fetchWithFallback<T>(
  cacheKey: string,
  fetcher: () => Promise<T>
): Promise<{ data: T; fromCache: boolean; cachedAt?: string }> {
  try {
    const data = await safeFigmaCall(fetcher);
    // Update cache with fresh data
    fallbackCache.save(cacheKey, data);
    return { data, fromCache: false };
  } catch (error) {
    console.warn(`Figma unavailable, loading cached ${cacheKey}`);
    const cached = fallbackCache.load(cacheKey);
    if (cached) {
      return { data: cached.data as T, fromCache: true, cachedAt: cached.cachedAt };
    }
    throw new Error(`Figma unavailable and no cached data for ${cacheKey}`);
  }
}

Step 3: Retry with Backoff (Respecting Retry-After)

async function figmaRetry<T>(
  fn: () => Promise<Response>,
  maxRetries = 3
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fn();

    if (res.ok) return res.json();

    if (res.status === 429) {
      const retryAfter = parseInt(res.headers.get('Retry-After') || '60');
      if (attempt < maxRetries) {
        console.warn(`429 -- waiting ${retryAfter}s (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise(r => setTimeout(r, retryAfter * 1000));
        continue;
      }
    }

    if (res.status >= 500 && attempt < maxRetries) {
      const delay = Math.min(1000 * Math.pow(2, attempt), 30_000);
      const jitter = Math.random() * 1000;
      await new Promise(r => setTimeout(r, delay + jitter));
      continue;
    }

    throw new FigmaApiError(res.status, await res.text());
  }
  throw new Error('Max retries exceeded');
}

Step 4: Request Timeout

// Prevent requests from hanging indefinitely
async function figmaFetchWithTimeout(
  path: string,
  token: string,
  timeoutMs = 15_000
): Promise<Response> {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), timeoutMs);

  try {
    return await fetch(`https://api.figma.com${path}`, {
      headers: { 'X-Figma-Token': token },
      signal: controller.signal,
    });
  } catch (error) {
    if (error instanceof Error && error.name === 'AbortError') {
      throw new Error(`Figma request timed out after ${timeoutMs}ms: ${path}`);
    }
    throw error;
  } finally {
    clearTimeout(timeout);
  }
}

Step 5: Health-Aware Request Routing

// Only make non-critical Figma calls when the API is healthy
class FigmaHealthTracker {
  private healthy = true;
  private lastCheck = 0;
  private checkIntervalMs = 30_000;

  async isHealthy(token: string): Promise<boolean> {
    if (Date.now() - this.lastCheck < this.checkIntervalMs) {
      return this.healthy;
    }

    try {
      const res = await figmaFetchWithTimeout('/v1/me', token, 5000);
      this.healthy = res.ok;
    } catch {
      this.healthy = false;
    }
    this.lastCheck = Date.now();
    return this.healthy;
  }
}

const healthTracker = new FigmaHealthTracker();

async function conditionalFigmaCall<T>(
  token: string,
  critical: boolean,
  fn: () => Promise<T>,
  fallback: () => Promise<T>
): Promise<T> {
  const healthy = await healthTracker.isHealthy(token);

  if (!healthy && !critical) {
    console.log('Figma unhealthy, using fallback for non-critical call');
    return fallback();
  }

  return fetchWithFallback('default', fn).then(r => r.data);
}

Output

  • Circuit breaker preventing cascading failures
  • Cached fallback serving stale data during outages
  • Retry logic respecting Figma's Retry-After header
  • Request timeouts preventing hung connections
  • Health-aware routing for non-critical calls

Error Handling

IssueCauseSolution
Circuit stays openThreshold too lowIncrease threshold or decrease reset time
Stale fallback dataCache not refreshedRefresh cache on successful calls
Retry loopsNot respecting Retry-AfterAlways use the header value
Timeout too shortLarge file responsesIncrease timeout for /v1/files calls

Examples

Watch the circuit breaker (Step 1) do its job during a Figma incident:

12:04:11 figma request failed (503) — failure 1/5
12:04:13 figma request failed (503) — failure 5/5 → circuit OPEN for 30s
12:04:14 request short-circuited; serving cached tokens (age 8m) via fallback
12:04:44 circuit HALF-OPEN — probe /v1/me → 200 → circuit CLOSED

Confirm retry honors Retry-After instead of hammering (Step 3):

GET /v1/files/abc → 429 (Retry-After: 32)
sleeping 32s (server-directed, overrides backoff schedule)
GET /v1/files/abc → 200 (attempt 2)

The cached-fallback contract (what staleness is acceptable per consumer) is in references/cached-fallback.md; composition of all five patterns: references/health-aware-request-routing.md.

Resources

Next Steps

For policy enforcement, see figma-policy-guardrails.

Signals

GitHub stars
3k
Forks
415
Last commit
Oct 2026

ahel review

  • S4info
    community integration, published by jeremylongshore, not figma

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
figma-reliability-patterns
Source
github.com/jeremylongshore/tons-of-skills-marketplace