The EmDash Plugin Marketplace has arrived, and with it comes a massive opportunity for developers. Whether you're building internal tools for your team or creating the next popular SEO plugin, getting started with EmDash plugin development is surprisingly straightforward.

In this guide, you'll build a complete, working EmDash plugin from scratch — including a sandbox environment, UI components, and D1 database integration. By the end of 15 minutes, you'll have a published plugin on your own site.

Prerequisites

Before we start, make sure you have:

- A running EmDash site (deployed to Cloudflare Pages)

- Node.js 18+ and pnpm installed

- A Cloudflare account with D1 access

- Basic TypeScript knowledge

That's it. No proprietary SDK, no special license, no gatekeeping.

Step 1: Scaffold Your Plugin

EmDash plugins live under `src/plugins/`. Each plugin is a directory with a standard structure:

```

src/plugins/my-plugin/

├── index.ts # Entry point — plugin registration

├── schema.ts # Database migrations

├── client/ # Frontend components

│ └── AdminPanel.tsx

└── README.md

```

Create the directory and entry point:

```typescript

// src/plugins/my-plugin/index.ts

import { definePlugin } from 'emdash/plugin';

export default definePlugin({

name: 'my-plugin',

version: '1.0.0',

description: 'My first EmDash plugin',

setup: ({ db, logger }) => {

logger.info('Plugin initialized!');

return { db };

},

});

```

Step 2: Define Your Schema

Plugins declare their database schemas in `schema.ts`. EmDash provides a D1 migration helper:

```typescript

// src/plugins/my-plugin/schema.ts

import { defineSchema } from 'emdash/plugin';

export default defineSchema({

version: 1,

tables: [

{

name: 'plugin_data',

columns: [

{ name: 'id', type: 'text', primaryKey: true },

{ name: 'key', type: 'text', notNull: true },

{ name: 'value', type: 'text' },

{ name: 'created_at', type: 'text', default: "datetime('now')" },

],

},

],

});

```

Migrations run automatically when the plugin is installed. No manual SQL needed.

Step 3: Build a UI Component

Plugins can inject UI into the admin panel. Create a simple stats dashboard:

```tsx

// src/plugins/my-plugin/client/AdminPanel.tsx

import { usePluginData } from 'emdash/plugin/client';

export function AdminPanel() {

const { data, loading } = usePluginData('/api/stats');

if (loading) return <div>Loading...</div>;

return (

<div className="grid grid-cols-3 gap-4">

<StatCard label="Total Posts" value={data.postCount} />

<StatCard label="Published Today" value={data.publishedToday} />

<StatCard label="Avg Read Time" value={`${data.avgReadTime}m`} />

</div>

);

}

```

The plugin system handles routing, auth, and data fetching. Your component just receives props.

Step 4: Expose an API Route

Add a server-side endpoint under the plugin namespace:

```typescript

// src/plugins/my-plugin/api/stats.ts

import { defineEndpoint } from 'emdash/plugin';

export default defineEndpoint({

method: 'GET',

handler: async ({ db }) => {

const postCount = await db

.prepare('SELECT COUNT(*) as count FROM ec_posts WHERE status = ?')

.bind('published')

.first();

return new Response(JSON.stringify(postCount), {

headers: { 'Content-Type': 'application/json' },

});

},

});

```

API routes are automatically prefixed with `/_emdash/plugins/my-plugin/`, so this becomes `/_emdash/plugins/my-plugin/api/stats`.

Step 5: Register and Test

Add your plugin to the EmDash config:

```typescript

// astro.config.mjs

import emdash from '@emdash/cms';

export default defineConfig({

integrations: [

emdash({

plugins: ['./src/plugins/my-plugin'],

}),

],

});

```

Deploy and visit your admin panel. Your plugin appears automatically.

Why Plugin Development Matters

The EmDash plugin model matters for three reasons:

| Reason | Impact |

|--------|--------|

| **Sandboxed isolation** | Your plugin can't break core CMS. Errors are caught, logged, and contained. |

| **D1-native storage** | No separate database. Your plugin data lives alongside your content. |

| **Unlimited distribution** | No app store approval. Share via GitHub, a tarball, or the marketplace. |

Next Steps

- Explore the [EmDash Plugin SDK](https://ai-kit.net/docs/plugin-sdk) for advanced hooks

- Check out community plugins on the marketplace

- Join the EmDash Discord to share what you built

The best plugins solve real problems. What's a pain point in your current CMS workflow? Build a plugin for it.