Back to Skills

Cloudflare Workers Testing

Comprehensive testing guide for Cloudflare Workers using Vitest and @cloudflare/vitest-pool-workers. Use for test setup, binding mocks (D1/KV/R2/DO), integration tests, or encountering test failures, mock errors, coverage issues.

cloudflaretestingairag
By secondsky
17928Updated 1 day agoTypeScriptMIT

Skill Content

# Cloudflare Workers Testing with Vitest

**Status**: ✅ Production Ready | Last Verified: 2025-01-27
**Vitest**: 2.1.8 | **@cloudflare/vitest-pool-workers**: 0.7.2 | **Miniflare**: Latest

## Table of Contents

- [What Is Workers Testing?](#what-is-workers-testing)
- [New in 2025](#new-in-2025)
- [Quick Start (5 Minutes)](#quick-start-5-minutes)
- [Critical Rules](#critical-rules)
- [Core Concepts](#core-concepts)
- [Top 5 Use Cases](#top-5-use-cases)
- [Best Practices](#best-practices)
- [Top 8 Errors Prevented](#top-8-errors-prevented)
- [When to Load References](#when-to-load-references)

---

## What Is Workers Testing?

Testing Cloudflare Workers with **Vitest** and **@cloudflare/vitest-pool-workers** enables writing unit and integration tests that run in a real Workers environment with full binding support (D1, KV, R2, Durable Objects, Queues, AI). Tests execute in Miniflare for local development and can run in CI/CD with actual Workers runtime behavior.

**Key capabilities**: Binding mocks, execution context testing, edge runtime simulation, coverage tracking, fast test execution.

---

## New in 2025

**@cloudflare/vitest-pool-workers 0.7.2** (January 2025):
- **BREAKING**: Miniflare v3 → requires Node.js 18+
- **NEW**: `cloudflare:test` module for env/ctx access
- **IMPROVED**: Faster isolated storage for bindings
- **FIXED**: Worker-to-worker service bindings now work correctly
- **ADDED**: Support for Vectorize and Workers AI bindings

**Migration from older versions**:
```bash
# Update dependencies
bun add -D vitest@^2.1.8 @cloudflare/vitest-pool-workers@^0.7.2

# Update vitest.config.ts (new pool configuration format)
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' },
        miniflare: { compatibilityDate: '2025-01-27' }
      }
    }
  }
});
```

---

## Quick Start (5 Minutes)

### 1. Install Dependencies

```bash
bun add -D vitest @cloudflare/vitest-pool-workers
```

### 2. Create `vitest.config.ts`

```typescript
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';

export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' },
        miniflare: {
          compatibilityDate: '2025-01-27',
          compatibilityFlags: ['nodejs_compat']
        }
      }
    }
  }
});
```

### 3. Write Your First Test

```typescript
import { describe, it, expect } from 'vitest';
import { env, createExecutionContext, waitOnExecutionContext } from 'cloudflare:test';
import worker from '../src/index';

describe('Worker', () => {
  it('responds with 200', async () => {
    const request = new Request('http://example.com/');
    const ctx = createExecutionContext();
    const response = await worker.fetch(request, env, ctx);
    await waitOnExecutionContext(ctx);

    expect(response.status).toBe(200);
  });
});
```

### 4. Run Tests

```bash
bun test
# or
bunx vitest
```

---

## Critical Rules

### 1. Always Use `cloudflare:test` for Env Access

**✅ CORRECT**:
```typescript
import { env } from 'cloudflare:test';

it('queries D1', async () => {
  const result = await env.DB.prepare('SELECT * FROM users').all();
  expect(result.results).toHaveLength(0); // Fresh isolated DB per test
});
```

**❌ WRONG**:
```typescript
// Don't manually create env object
const env = { DB: mockDB }; // ❌ Won't use real D1 binding
```

**Why**: `cloudflare:test` provides real bindings configured from `wrangler.jsonc` with isolated storage per test.

### 2. Always Wait on Execution Context

**✅ CORRECT**:
```typescript
it('handles async operations', async () => {
  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  await waitOnExecutionContext(ctx); // ✅ Ensures ctx.waitUntil completes

  expect(response.status).toBe(200);
});
```

**❌ WRONG**:
```typescript
it('missing wait', async () => {
  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  // ❌ Missing waitOnExecutionContext - ctx.waitUntil tasks may not complete
  expect(response.status).toBe(200);
});
```

**Why**: Workers use `ctx.waitUntil()` for background tasks (logging, analytics). Without waiting, these tasks may not complete in tests.

### 3. Each Test Gets Isolated Storage

**✅ CORRECT**:
```typescript
describe('KV Operations', () => {
  it('test 1: writes to KV', async () => {
    await env.CACHE.put('key', 'value1');
    const val = await env.CACHE.get('key');
    expect(val).toBe('value1'); // ✅ Isolated
  });

  it('test 2: clean state', async () => {
    const val = await env.CACHE.get('key');
    expect(val).toBeNull(); // ✅ Test 1's data doesn't leak here
  });
});
```

**Why**: Each test runs with fresh binding storage (automatic isolation).

### 4. Use Wrangler Config for Bindings

**✅ CORRECT**:
```typescript
// vitest.config.ts
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' } // ✅ Reads bindings from wrangler
      }
    }
  }
});
```

**❌ WRONG**:
```typescript
// vitest.config.ts
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        // ❌ No wrangler config - bindings won't be available
        miniflare: { compatibilityDate: '2025-01-27' }
      }
    }
  }
});
```

**Why**: Wrangler config defines all bindings (D1, KV, R2, etc.). Without it, `env` will be empty.

### 5. Match Compatibility Date

**✅ CORRECT**:
```typescript
// vitest.config.ts
miniflare: {
  compatibilityDate: '2025-01-27' // ✅ Matches wrangler.jsonc
}

// wrangler.jsonc
{
  "compatibility_date": "2025-01-27"
}
```

**Why**: Ensures test environment matches production runtime behavior.

---

## Core Concepts

### Binding Testing Patterns

**D1 Database**:
```typescript
import { env } from 'cloudflare:test';

it('queries D1', async () => {
  // Insert test data
  await env.DB.prepare('INSERT INTO users (name) VALUES (?)').bind('Alice').run();

  // Query
  const result = await env.DB.prepare('SELECT * FROM users WHERE name = ?').bind('Alice').first();
  expect(result?.name).toBe('Alice');
});
```

**KV Namespace**:
```typescript
it('reads from KV', async () => {
  await env.CACHE.put('test-key', 'test-value');
  const value = await env.CACHE.get('test-key');
  expect(value).toBe('test-value');
});
```

**R2 Bucket**:
```typescript
it('uploads to R2', async () => {
  await env.BUCKET.put('file.txt', 'Hello World');
  const object = await env.BUCKET.get('file.txt');
  expect(await object?.text()).toBe('Hello World');
});
```

**Durable Objects**:
```typescript
it('interacts with Durable Object', async () => {
  const id = env.COUNTER.idFromName('test-counter');
  const stub = env.COUNTER.get(id);

  const response = await stub.fetch('http://fake/increment');
  const data = await response.json();
  expect(data.count).toBe(1);
});
```

### Unit vs Integration Tests

**Unit Test** (single function):
```typescript
import { validateInput } from '../src/utils/validator';

it('validates input', () => {
  const result = validateInput({ name: 'Alice', age: 30 });
  expect(result.valid).toBe(true);
});
```

**Integration Test** (full fetch handler):
```typescript
import worker from '../src/index';
import { env, createExecutionContext, waitOnExecutionContext } from 'cloudflare:test';

it('handles full request flow', async () => {
  const request = new Request('http://example.com/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: 'Alice' })
  });

  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  await waitOnExecutionContext(ctx);

  expect(response.status).toBe(201);
  const user = await response.json();
  expect(user.name).toBe('Alice');
});
```

### Coverage Configuration

Add to `vitest.config.ts`:
```typescript
export default defineWorkersConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      include: ['src/**/*.ts'],
      exclude: ['src/**/*.test.ts', 'src/**/*.spec.ts'],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 80,
        statements: 80
      }
    }
  }
});
```

Run with coverage:
```bash
bunx vitest run --coverage
```

---

## Top 5 Use Cases

### 1. Testing API Endpoints with D1

```typescript
it('creates user via API', async () => {
  const request = new Request('http://example.com/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: 'Bob', email: 'bob@example.com' })
  });

  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  await waitOnExecutionContext(ctx);

  expect(response.status).toBe(201);

  // Verify DB insert
  const user = await env.DB.prepare('SELECT * FROM users WHERE email = ?')
    .bind('bob@example.com')
    .first();
  expect(user?.name).toBe('Bob');
});
```

### 2. Testing Caching with KV

```typescript
it('caches API responses', async () => {
  // First request (cache miss)
  const req1 = new Request('http://example.com/api/data');
  const ctx1 = createExecutionContext();
  const res1 = await worker.fetch(req1, env, ctx1);
  await waitOnExecutionContext(ctx1);

  expect(res1.headers.get('X-Cache')).toBe('MISS');

  // Second request (cache hit)
  const req2 = new Request('http://example.com/api/data');
  const ctx2 = createExecutionContext();
  const res2 = await worker.fetch(req2, env, ctx2);
  await waitOnExecutionContext(ctx2);

  expect(res2.headers.get('X-Cache')).toBe('HIT');
});
```

### 3. Testing File Uploads to R2

```typescript
it('handles file upload', async () => {
  const formData = new FormData();
  formData.append('file', new Blob(['test content'], { type: 'text/plain' }), 'test.txt');

  const request = new Request('http://example.com/upload', {
    method: 'POST',
    body: formData
  });

  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  await waitOnExecutionContext(ctx);

  expect(response.status).toBe(200);

  // Verify R2 upload
  const object = await env.BUCKET.get('test.txt');
  expect(await object?.text()).toBe('test content');
});
```

### 4. Testing Durable Objects State

```typescript
it('maintains counter state', async () => {
  const id = env.COUNTER.idFromName('my-counter');
  const stub = env.COUNTER.get(id);

  // Increment 3 times
  for (let i = 0; i < 3; i++) {
    await stub.fetch('http://fake/increment');
  }

  // Verify state
  const response = await stub.fetch('http://fake/value');
  const data = await response.json();
  expect(data.count).toBe(3);
});
```

### 5. Testing Queue Consumers

```typescript
it('processes queue messages', async () => {
  const messages = [
    { id: '1', body: { action: 'email', to: 'user@example.com' }, timestamp: new Date() }
  ];

  // Simulate queue batch
  await worker.queue(
    {
      queue: 'my-queue',
      messages,
      retryAll: () => {},
      ackAll: () => {}
    },
    env
  );

  // Verify processing (check DB, logs, etc.)
  const log = await env.DB.prepare('SELECT * FROM email_log WHERE id = ?').bind('1').first();
  expect(log?.status).toBe('sent');
});
```

---

## Best Practices

### ✅ DO

1. **Use descriptive test names**:
   ```typescript
   it('returns 404 when user not found', async () => {});
   it('validates email format before saving', async () => {});
   ```

2. **Test error cases**:
   ```typescript
   it('returns 400 for invalid JSON', async () => {
     const request = new Request('http://example.com/api', {
       method: 'POST',
       headers: { 'Content-Type': 'application/json' },
       body: 'invalid json'
     });

     const ctx = createExecutionContext();
     const response = await worker.fetch(request, env, ctx);
     await waitOnExecutionContext(ctx);

     expect(response.status).toBe(400);
   });
   ```

3. **Group related tests**:
   ```typescript
   describe('User API', () => {
     describe('POST /users', () => {
       it('creates user with valid data', async () => {});
       it('rejects duplicate email', async () => {});
       it('validates required fields', async () => {});
     });
   });
   ```

4. **Use beforeEach for setup**:
   ```typescript
   describe('Database tests', () => {
     beforeEach(async () => {
       // Seed test data
       await env.DB.prepare('INSERT INTO users (name) VALUES (?)').bind('Test User').run();
     });

     it('queries users', async () => {
       const result = await env.DB.prepare('SELECT * FROM users').all();
       expect(result.results).toHaveLength(1);
     });
   });
   ```

5. **Test realistic scenarios**:
   ```typescript
   it('handles concurrent requests', async () => {
     const requests = Array(10).fill(null).map(() =>
       worker.fetch(new Request('http://example.com/'), env, createExecutionContext())
     );

     const responses = await Promise.all(requests);
     expect(responses.every(r => r.status === 200)).toBe(true);
   });
   ```

### ❌ DON'T

1. **Don't share state between tests**:
   ```typescript
   // ❌ BAD: Leaky state
   let counter = 0;
   it('test 1', () => { counter++; });
   it('test 2', () => { expect(counter).toBe(1); }); // Fragile!

   // ✅ GOOD: Isolated
   it('test 1', () => { const counter = 0; counter++; });
   it('test 2', () => { const counter = 0; /* fresh state */ });
   ```

2. **Don't forget to wait**:
   ```typescript
   // ❌ BAD
   const response = await worker.fetch(request, env, ctx);
   expect(response.status).toBe(200); // ctx.waitUntil not finished

   // ✅ GOOD
   const response = await worker.fetch(request, env, ctx);
   await waitOnExecutionContext(ctx);
   expect(response.status).toBe(200);
   ```

3. **Don't hardcode URLs**:
   ```typescript
   // ❌ BAD
   const request = new Request('http://example.com/test');

   // ✅ GOOD
   const request = new Request('http://fake-host/test'); // Host doesn't matter in tests
   ```

4. **Don't test implementation details**:
   ```typescript
   // ❌ BAD: Testing internals
   expect(worker.privateHelperFunction).toBeDefined();

   // ✅ GOOD: Testing behavior
   const response = await worker.fetch(request, env, ctx);
   expect(response.status).toBe(200);
   ```

---

## Top 8 Errors Prevented

### 1. ❌ `ReferenceError: env is not defined`

**Cause**: Not importing `env` from `cloudflare:test`.

**Fix**:
```typescript
import { env } from 'cloudflare:test'; // ✅ Add this import
```

**Prevention**: Always use `cloudflare:test` module for env access.

---

### 2. ❌ `TypeError: Cannot read property 'DB' of undefined`

**Cause**: `wrangler.jsonc` not loaded in `vitest.config.ts`.

**Fix**:
```typescript
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' } // ✅ Add this
      }
    }
  }
});
```

**Prevention**: Always configure wrangler path in vitest config.

---

### 3. ❌ `Error: D1_ERROR: no such table: users`

**Cause**: D1 database schema not applied in tests.

**Fix**:
```typescript
// Option 1: Seed in beforeEach
beforeEach(async () => {
  await env.DB.exec(`
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY,
      name TEXT NOT NULL
    )
  `);
});

// Option 2: Use migrations (load from file)
beforeEach(async () => {
  const schema = await fs.readFile('./migrations/schema.sql', 'utf-8');
  await env.DB.exec(schema);
});
```

**Prevention**: Create schema before each test or use shared setup.

---

### 4. ❌ `Error: ctx.waitUntil tasks did not complete`

**Cause**: Missing `await waitOnExecutionContext(ctx)`.

**Fix**:
```typescript
const ctx = createExecutionContext();
const response = await worker.fetch(request, env, ctx);
await waitOnExecutionContext(ctx); // ✅ Add this
```

**Prevention**: Always wait on execution context in tests.

---

### 5. ❌ `Error: SELF is not defined`

**Cause**: Using old `SELF.fetch()` pattern instead of direct worker import.

**Fix**:
```typescript
// ❌ OLD (vitest-pool-workers <0.5)
import { SELF } from 'cloudflare:test';
await SELF.fetch(request);

// ✅ NEW (vitest-pool-workers ≥0.7)
import worker from '../src/index';
await worker.fetch(request, env, ctx);
```

**Prevention**: Use direct worker imports (modern pattern).

---

### 6. ❌ `Error: KV.get() returned data from previous test`

**Cause**: Believing storage is shared (it's not, but may indicate test leak).

**Fix**: Each test is isolated. If seeing this, check for:
```typescript
// ❌ Test pollution (shared variable)
let cache = {};
it('test 1', () => { cache.key = 'value'; });
it('test 2', () => { expect(cache.key).toBeUndefined(); }); // Fails!

// ✅ Proper isolation
it('test 1', async () => { await env.CACHE.put('key', 'value1'); });
it('test 2', async () => { const val = await env.CACHE.get('key'); expect(val).toBeNull(); });
```

**Prevention**: Don't use shared variables for test data.

---

### 7. ❌ `TypeError: env.BUCKET.put is not a function`

**Cause**: R2 binding not configured in `wrangler.jsonc`.

**Fix**:
```jsonc
// wrangler.jsonc
{
  "r2_buckets": [
    { "binding": "BUCKET", "bucket_name": "test-bucket" }
  ]
}
```

**Prevention**: Define all bindings in wrangler config.

---

### 8. ❌ `Error: Pool 'workers' is not supported`

**Cause**: Missing `@cloudflare/vitest-pool-workers` dependency.

**Fix**:
```bash
bun add -D @cloudflare/vitest-pool-workers
```

**Prevention**: Install pool package for Workers testing.

---

## When to Load References

Load reference files for detailed, specialized content:

**Load `references/vitest-setup.md` when:**
- Setting up Vitest from scratch
- Configuring custom pool options
- Troubleshooting Miniflare configuration
- Migrating from older vitest-pool-workers versions

**Load `references/binding-mocks.md` when:**
- Testing specific bindings (D1, KV, R2, DO, Queues, AI, Vectorize)
- Mocking service bindings (worker-to-worker)
- Creating test fixtures for bindings
- Understanding isolated storage behavior

**Load `references/integration-testing.md` when:**
- Writing full request/response tests
- Testing multi-step workflows
- Simulating production scenarios
- Testing WebSocket or streaming responses

**Load `references/coverage-optimization.md` when:**
- Setting up coverage thresholds
- Identifying untested code paths
- Optimizing test suite performance
- Configuring coverage reporters

**Load `references/troubleshooting.md` when:**
- Debugging failing tests
- Resolving binding errors
- Fixing timeout issues
- Understanding error messages

**Load `templates/vitest-config.ts` for:**
- Complete vitest.config.ts example
- Advanced configuration options
- Multiple wrangler environments

**Load `templates/basic-test.ts` for:**
- Test file structure template
- Common test patterns
- beforeEach/afterEach examples

**Load `templates/binding-mock-test.ts` for:**
- Binding-specific test examples
- D1, KV, R2, DO test patterns
- Queue and AI testing examples

**Load `scripts/setup-vitest.sh` for:**
- Automated Vitest installation
- Project configuration script

**Load `scripts/run-tests.sh` for:**
- CI/CD test execution
- Coverage reporting automation

---

## Related Cloudflare Plugins

**For service-specific testing patterns, load:**
- **cloudflare-d1** - D1 database testing, migrations, seeding
- **cloudflare-kv** - KV namespace testing, TTL verification
- **cloudflare-r2** - R2 bucket testing, file upload/download
- **cloudflare-durable-objects** - DO testing, WebSocket testing
- **cloudflare-queues** - Queue testing, batch processing
- **cloudflare-workers-ai** - AI model testing, inference mocking

**This skill focuses on cross-cutting Workers testing patterns** applicable to ALL binding types and Workers features.

---

**Questions?** Load `references/troubleshooting.md` or use `/workers-debug` command for interactive help.

How to use

  1. Copy the skill content above
  2. Create a .claude/skills directory in your project
  3. Save as .claude/skills/claude-skills-cloudflare-workers-testing.md
  4. Use /claude-skills-cloudflare-workers-testing in Claude Code to invoke this skill

Claude Code Skills Collection

170 production-ready skills for Claude Code CLI

Version 3.3.1 | Last Updated: 2026-05-14

<div align="center">

🔌 Platform Support

This repository uses Claude Plugin Patterns — natively supported by:

PlatformStatusNotes
Claude CodeNativeFull marketplace support
Factory DroidNativeFull marketplace support
</div> **For all other Platforms like opencode, codex and others, you can use https://github.com/enulus/OpenPackage **

A curated collection of battle-tested skills for building modern web applications with Cloudflare, AI integrations, React, Tailwind, and more.

PS: if skills.sh warns about any skill: Their scan process is a outdated LLM which flags newest versions pins (like in ZOD) as non existent and by that potentially malicous.


Quick Start

Marketplace Installation (Recommended)

# Add the marketplace
/plugin marketplace add https://github.com/secondsky/claude-skills

# Install individual skills as needed
/plugin install cloudflare-d1@claude-skills
/plugin install tailwind-v4-shadcn@claude-skills
/plugin install ai-sdk-core@claude-skills

See MARKETPLACE.md for complete catalog of all 170 skills.

Bulk Installation (Contributors)

# Clone the repository
git clone https://github.com/secondsky/claude-skills.git
cd claude-skills

# Install all 170 skills at once
./scripts/install-all.sh

# Or install individual skills
./scripts/install-skill.sh cloudflare-d1

Repository Structure

This repository contains 170 production-tested skills for Claude Code, each focused on a specific technology or capability.

Individual Skills: Each skill is a standalone unit with:

  • SKILL.md - Core knowledge and guidance
  • Templates - Working code examples
  • References - Extended documentation
  • Scripts - Helper utilities

Installation Options:

  1. Individual - Install only the skills you need via marketplace
  2. Bulk - Install all 170 skills using ./scripts/install-all.sh

Available Skills (170 Individual Skills)

Each skill is individually installable. Install only the skills you need.

Full Catalog: See MARKETPLACE.md for detailed listings.

Categories

CategorySkillsExamples
tooling29turborepo, plan-interview, code-review
frontend26nuxt-v4, nuxt-v5, tailwind-v4-shadcn, tanstack-query, nuxt-studio, maz-ui, threejs
cloudflare21cloudflare-d1, cloudflare-workers-ai, cloudflare-agents
ai20openai-agents, claude-api, ai-sdk-core
api16api-design-principles, graphql-implementation
web10hono-routing, firecrawl-scraper, web-performance
mobile7swift-best-practices, react-native-app, react-native-skills
database6drizzle-orm-d1, neon-vercel-postgres, supabase-postgres-best-practices
security6csrf-protection, access-control-rbac
auth4better-auth
testing4vitest-testing, playwright-testing
design4design-review, design-system-creation
woocommerce4woocommerce-backend-dev
cms4hugo, sveltia-cms, wordpress-plugin-core
architecture3microservices-patterns, architecture-patterns
data3sql-query-optimization, recommendation-engine
seo2seo-optimizer, seo-keyword-cluster-builder
documentation1technical-specification

How It Works

Auto-Discovery

Claude Code automatically checks ~/.claude/skills/ for relevant skills before planning tasks:

User: "Set up a Cloudflare Worker with D1 database"
           ↓
Claude: [Checks skills automatically]
           ↓
Claude: "Found cloudflare-d1 skills.
         These prevent 12 documented errors. Use them?"
           ↓
User: "Yes"
           ↓
Result: Production-ready setup, zero errors, ~65% token savings

Note: Due to token limits, not all skills may be visible at once. See ⚠️ Important: Token Limits below.

Skill Structure

Each skill includes:

skills/[skill-name]/
├── SKILL.md              # Complete documentation
├── .claude-plugin/
│   └── plugin.json       # Plugin metadata
├── templates/            # Ready-to-copy templates
├── scripts/              # Automation scripts
└── references/           # Extended documentation

Recent Additions

May 2026

Supply Chain Security (cross-cutting):

  • dependency-upgrade expanded with Socket CLI integration — proactive malicious package detection, typosquatting alerts, and CI/CD security gates. New 418-line reference guide, 2 GitHub Actions templates, and expanded supply chain security comparison (3 tools)
  • 31 skills now include "Secure Installation" guidance — contextually-tailored security sections across all high-risk skill categories (scaffolding, MCP/agent SDKs, multi-provider installs, Docker, CI/CD). Covers 8 Bun skills, 5 Nuxt skills, 6 Cloudflare skills, 4 AI/agent skills, and 8 frontend/tooling skills
  • Supply chain security is now a first-class cross-cutting concern woven into the skill collection — not a standalone topic

February - April 2026

Full-Stack Frameworks:

  • nuxt-v5 (v1.0.0) - Full Nuxt 5 support with 4 skills (core, data, server, production), 3 diagnostic agents, and interactive setup wizard
  • supabase-postgres-best-practices - 30 Postgres optimization rules from Supabase across 8 categories
  • threejs (v1.0.0) - 3D web graphics: scenes, geometries, shaders, animations, post-processing

Infrastructure:

  • JSON schema validation - Automated plugin.json validation with CI support
  • GitHub issue templates - Skill-specific issue templates for bug reports, feature requests, and submissions

Plugin Enhancements:

  • mutation-testing - Added Bun native runner support
  • dependency-upgrade - Added supply chain security content

December 2025 - January 2026

Frontend Expansion:

  • nuxt-studio (v1.0.0) - Visual CMS for Nuxt Content with live preview, OAuth auth, and R2 storage integration
  • maz-ui (v1.0.0) - 50+ Vue/Nuxt components with theming, i18n, form generation, and 14 composables

Developer Workflow:

  • plan-interview (v2.0.0) - Adaptive interview-driven spec generation with autonomous quality review
  • turborepo (v2.8.0) - Updated to official Vercel skill with enhanced monorepo build optimization

Mobile Development:

  • react-native-skills (v1.0.0) - React Native & Expo best practices with performance optimization patterns

Enhanced Authentication:

  • better-auth (v2.2.0) - Expanded to 18 framework integrations with 30+ authentication plugins

⚠️ Important: Token Limits

Skill Visibility Constraint

Claude Code has a 15,000 character limit for the total size of skill descriptions in the system prompt. This limit also applies to commands and agents.

What this means:

  • Not all 170 skills may be visible in Claude's context at once
  • Skills are loaded based on relevance and available token budget
  • You can verify how many skills Claude currently sees by asking: "How many skills do you see in your system prompt?"

Checking Visible Skills

To verify which skills are currently loaded:

# Ask Claude Code directly
"Check what skills/plugins you see in your system prompt"

Claude will report something like: "85 of 170 skills visible due to token limits"

Workaround: Increase Token Budget

You can double the headroom for skill descriptions by setting an environment variable:

# Increase limit to 30,000 characters
export SLASH_COMMAND_TOOL_CHAR_BUDGET=30000

# Then launch Claude Code
claude

This gives you approximately 2x more skill visibility in the system prompt.

Note: This is a temporary workaround. The Claude Code team is working on better solutions for skill discovery and loading.


Token Efficiency

MetricManual SetupWith SkillsSavings
Average Tokens12,000-15,0004,000-5,000~65%
Typical Errors2-4 per service0 (prevented)100%
Setup Time2-4 hours15-45 minutes~80%

Across all 170 skills: 400+ documented errors prevented.


Contributing

Prerequisites for Contributors

Install the official plugin development toolkit:

/plugin install plugin-dev@claude-code-marketplace

This provides:

  • /plugin-dev:create-plugin command (8-phase guided workflow)
  • 7 comprehensive skills (hooks, MCP, structure, agents, commands, skills)
  • 2 specialized agents (agent-creator, plugin-validator)

Quick Steps

  1. Create skill directory in plugins/
  2. Add SKILL.md with YAML frontmatter
  3. Run ./scripts/sync-plugins.sh
  4. Submit pull request

See CONTRIBUTING.md and PLUGIN_DEV_BEST_PRACTICES.md for detailed guidelines.


Documentation

DocumentPurpose
START_HERE.mdStart here! Quick navigation guide
PLUGIN_DEV_BEST_PRACTICES.mdRepository-specific best practices (marketplace, budget, quality)
MARKETPLACE.mdFull skill catalog and installation guide
MARKETPLACE_MANAGEMENT.mdTechnical infrastructure (plugin.json, scripts, validation)
CLAUDE.mdProject context and development standards
CONTRIBUTING.mdContribution guidelines

Links


Built with ❤️ by Claude Skills Maintainers

View source on GitHub