---
title: "Build Your Own Plugin"
description: "Build a custom Vercel Workflow plugin for Slack, Stripe, GitHub, or any API you use. Apply everything you've learned to create a production-ready integration."
canonical_url: "https://vercel.com/academy/visual-workflow-builder-on-vercel/build-your-plugin"
md_url: "https://vercel.com/academy/visual-workflow-builder-on-vercel/build-your-plugin.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-04-11T10:12:57.764Z"
content_type: "lesson"
course: "visual-workflow-builder-on-vercel"
course_title: "Build Visual Workflow Plugins on Vercel"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Build Your Own Plugin

# Build Your Own Plugin

Time to fly solo. You've followed the steps, copied the code, fixed the errors. Now you build something the tutorial didn't plan for — YOUR plugin, YOUR API, YOUR problem. This is where "I took a course" becomes "I can build this."

You've built two plugins — Shout (toy) and email (real). You know the plugin folder pattern, how credentials work, how errors should behave. This is graduation: same patterns, no more hand-holding.

\*\*Note: Mental Model: Workflow Thinking\*\*

You can look at any async problem and see steps, pause points, failure modes. That's the skill — not just using this builder, but thinking in workflows.

For deeper patterns, explore [Building AI Agents with Vercel Workflow](https://vercel.com/kb/guide/how-to-build-ai-agents-with-vercel-and-the-ai-sdk) and [Stateful Slack Bots with Vercel Workflow](https://vercel.com/kb/guide/stateful-slack-bots-with-vercel-workflow).

## Outcome

You'll create a complete plugin for a service you actually use — Slack, Stripe, GitHub, your internal API — and run it in a workflow that does something useful for you.

## Fast Track

1. Deploy the production template (or continue on starter)
2. Run `pnpm create-plugin` to scaffold your plugin
3. Implement the step, test connection, and error handling

## Choose Your Path

You've been building on the starter template. For your own plugin, you have three options:

### Continue on Starter

Keep building where you are. The starter is intentionally minimal, but it has the same plugin patterns and discovery flow you've used throughout the course. Good for learning, quick experiments, or if you just want to finish what you started.

### Deploy Template Fresh (Recommended for Production)

The production template includes more plugins to study, a cleaner codebase, and is ready for real use:

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel-labs%2Fworkflow-builder-template\&project-name=workflow-builder\&repository-name=workflow-builder\&demo-title=Workflow+Builder\&demo-description=A+free%2C+open-source+template+for+building+visual+workflow+automation+platforms+with+real+integrations+and+code+generation\&demo-url=https%3A%2F%2Fworkflow-builder-template.vercel.app\&demo-image=https%3A%2F%2Fraw.githubusercontent.com%2Fvercel-labs%2Fworkflow-builder-template%2Fmain%2Fscreenshot.png\&env=BETTER_AUTH_SECRET%2CINTEGRATION_ENCRYPTION_KEY%2CAI_GATEWAY_API_KEY\&envDescription=BETTER_AUTH_SECRET+and+INTEGRATION_ENCRYPTION_KEY+are+required+secrets.+AI_GATEWAY_API_KEY+is+optional.\&stores=%5B%7B%22type%22%3A%22postgres%22%7D%5D)

This gives you a fresh Vercel project with Postgres provisioned automatically.

The production template includes additional features like overlay-based UI, public workflow sharing, API keys management, and OG image generation. See the [workflow-builder-template repository](https://github.com/vercel-labs/workflow-builder-template) for the full feature set.

### GitHub Template (Clone Locally First)

Want to explore the code before deploying? Create a repo from the template:

[Use this template on GitHub](https://github.com/new?template_name=workflow-builder-template\&template_owner=vercel-labs)

Clone it, poke around, then deploy when ready.

## Why This Lesson Matters

Tutorials are passive. You follow steps, things work, you move on. Retention is maybe 20%.

Building YOUR plugin, for YOUR API, when the docs don't map perfectly? That's where friction happens. You'll debug something weird. You'll make a decision the tutorial didn't cover. You'll come out knowing this system instead of just recognizing it.

This is the difference between "I took a course" and "I can build this."

## Study These Production Plugins

The production template includes several real-world plugins. Before building your own, study how these handle common patterns there — not in the stripped-down starter:

| Plugin        | What to Learn                                                   |
| ------------- | --------------------------------------------------------------- |
| **Resend**    | Clean credential handling, simple single-action plugin          |
| **Slack**     | OAuth-style tokens, message formatting                          |
| **Linear**    | Multiple actions (create ticket, find issues), API with GraphQL |
| **Firecrawl** | Scraping and search actions, handling complex API responses     |

Each follows the same folder structure. Read one thoroughly — the patterns repeat.

## Plugin Folder Checklist

The production template uses a streamlined structure:

```
plugins/[your-plugin]/
├── index.ts           → Plugin definition, registration
├── icon.tsx           → Icon component
├── credentials.ts     → Credential type definition
├── test.ts            → Connection test function
└── steps/
    └── [action].ts    → "use step" function with fetchCredentials()
```

Run `pnpm create-plugin` to scaffold this structure automatically.

\*\*Reflection:\*\* Before you start building, answer these questions for your chosen API: (1) What's the main action your plugin will perform? (2) What credentials does it need? (3) What inputs should the config UI collect? (4) What can fail, and which failures are retryable vs fatal? Write this down — it's your design doc.

## Hands-on Exercise

**1. Pick your API:**

- **Your internal service (recommended)** — the real test is integrating something the template doesn't have
- Stripe (create charge, refund, subscription)
- Twilio (send SMS, make call)
- GitHub (create issue, comment on PR)
- Any API you actually use at work

**2. Design before you code:**

- What inputs does the UI need?
- What can fail? Which failures are retryable?
- What should the step output for downstream nodes?

**3. Build the plugin:**

Run `pnpm create-plugin` to scaffold, then customize. Here's the skeleton you'll fill in:

```typescript title="plugins/[your-plugin]/steps/[action].ts"
import "server-only";

import { FatalError, RetryableError } from "workflow";
import { fetchCredentials } from "@/lib/credential-fetcher";
import { type StepInput, withStepLogging } from "@/lib/steps/step-handler";
import type { YourCredentials } from "../credentials";

type YourActionResult =
  | { success: true; /* your output fields */ }
  | { success: false; error: string };

type YourActionInput = StepInput & {
  // Your config fields from index.ts
};

async function stepHandler(
  input: YourActionInput,
  credentials: YourCredentials
): Promise<YourActionResult> {
  // 1. Validate credentials
  if (!credentials.API_KEY) {
    throw new FatalError("API_KEY is not configured");
  }

  // 2. Call your API
  const response = await fetch("https://your-api.com/endpoint", {
    method: "POST",
    headers: { Authorization: `Bearer ${credentials.API_KEY}` },
    body: JSON.stringify({ /* your payload */ }),
  });

  // 3. Handle errors by type
  if (response.status === 401) {
    throw new FatalError("Invalid API key");
  }
  if (response.status === 429 || response.status >= 500) {
    throw new RetryableError(`API returned ${response.status}`);
  }

  // 4. Return success
  const data = await response.json();
  return { success: true, /* your output fields */ };
}

export async function yourActionStep(
  input: YourActionInput
): Promise<YourActionResult> {
  "use step";
  const credentials = input.integrationId
    ? await fetchCredentials(input.integrationId)
    : {};
  return withStepLogging(input, () => stepHandler(input, credentials));
}

export const _integrationType = "your-plugin";
```

The key sections:

- Validate credentials exist (FatalError if missing)
- Call your API
- Handle errors by type (401 = Fatal, 429/5xx = Retryable)
- Return success with output for downstream nodes

**4. Test the full flow:**

- Add your plugin to a workflow
- Run it
- Break it on purpose (bad credentials)
- Verify retries or fatal errors work as expected
- Fix it and run successfully

## Verify It Works

Your plugin is ready when:

1. **Happy path succeeds** — Run your workflow and check the Runs tab:
   ```json
   {
     "success": true,
     // your output fields from step return
   }
   ```

2. **Bad credentials fail fast** — Remove or invalidate your API key, run again. You should see `FatalError` logged immediately, not retry attempts.

3. **Transient errors retry** — If your API returns 429 or 503, the workflow should retry with backoff (check the step execution count in logs).

If all three work, you've internalized the pattern. Ship it.

## Learn More

Now that you've built real plugins, go deeper with these resources:

| Resource                                                          | What You'll Learn                            |
| ----------------------------------------------------------------- | -------------------------------------------- |
| [Workflow SDK Docs](https://useworkflow.dev)                      | Complete API reference, advanced patterns    |
| [Vercel Workflow Platform Docs](https://vercel.com/docs/workflow) | Deployment, observability, production config |
| [Vercel Functions](https://vercel.com/docs/functions)             | The runtime powering your workflow steps     |
| [Fluid Compute](https://vercel.com/docs/fluid-compute)            | How Vercel optimizes function execution      |

## Done

- [ ] Picked a real API you actually use
- [ ] Built the plugin folder structure
- [ ] Plugin appears in action grid
- [ ] Workflow runs successfully with your plugin
- [ ] Tested error handling (retries or fatal)
- [ ] Credentials stay out of logs

## What You've Learned

You started with a deploy button and ended with a custom integration. Along the way:

- **Keep Your API Fast** — Routes return instantly, workflows run in background
- **Pause and Continue** — Workflows suspend for webhooks, resume exactly
- **Steps and Flow** — Code matches diagram, steps are composable promises
- **Retry and Error Recovery** — You control what retries and what stops
- **Step Tracing** — Observability comes free, correlation IDs thread everything

Now go build something real. When you do, [share it in the Vercel Community](https://community.vercel.com/) — we want to see what you create.


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
