Repository navigation
Development
This guide covers how to create custom nself plugins.
BEFORE developing a plugin, you MUST read and follow Standards.
Key requirements:
- ✅ ALL tables must use
np_prefix - ✅ ALL plugins must use
source_account_idfor multi-app isolation - ✅ Use one of 13 official categories only
- ✅ Plugin names must be lowercase-with-hyphens
Failure to comply will result in automated build failures.
Every plugin follows this structure:
plugins/<name>/
├── plugin.json # Plugin metadata (required)
├── cmd/ # Go service or CLI entry point (required)
├── migrations/ # Embedded SQL migrations, applied at boot (required for plugins with tables)
├── schema/
│ └── tables.sql # Database schema reference
├── Dockerfile
└── docker-compose.plugin.yml
A plugin ships a binary. The CLI never runs per-plugin install.sh, uninstall.sh, actions/*.sh or
webhooks/**/*.sh scripts, and the repository carries none. Install, upgrade and removal go through
nself plugin install|upgrade|remove; migrations run when the service starts. Start from
nself plugin new and follow Plugin Development.
mkdir -p plugins/my-service/{cmd,migrations,schema}The manifest file describes your plugin:
{
"name": "my-service",
"version": "1.0.0",
"description": "Integration with My Service",
"author": "Your Name",
"license": "MIT",
"minNselfVersion": "0.4.8",
"category": "integrations",
"tags": ["my-service", "integration"],
"tables": [
"np_myservice_items",
"np_myservice_webhooks"
],
"webhooks": {
"item.created": "Sync new items",
"item.updated": "Update item data"
},
"actions": {
"sync": "Sync all data",
"items": "Manage items"
},
"envVars": {
"required": ["MYSERVICE_API_KEY"],
"optional": ["MYSERVICE_WEBHOOK_SECRET"]
},
"multiApp": {
"supported": true,
"isolationColumn": "source_account_id",
"pkStrategy": "uuid",
"defaultValue": "primary"
},
"config": {
"port": 4000,
"webhookPath": "/webhooks/my-service"
}
}Key Points:
⚠️ Tables MUST start withnp_prefix⚠️ Category must be one of 13 official categories⚠️ multiApp.isolationColumnMUST besource_account_id
Create schema/tables.sql:
-- ⚠️ IMPORTANT: ALL tables MUST use np_ prefix and include source_account_id
CREATE TABLE IF NOT EXISTS np_myservice_items (
id UUID PRIMARY KEY,
source_account_id VARCHAR(255) NOT NULL, -- REQUIRED for multi-app
name VARCHAR(255) NOT NULL,
data JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS np_myservice_webhooks (
id UUID PRIMARY KEY,
source_account_id VARCHAR(255) NOT NULL, -- REQUIRED for multi-app
type VARCHAR(100) NOT NULL,
data JSONB NOT NULL,
processed BOOLEAN DEFAULT FALSE,
received_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes for multi-tenant queries
CREATE INDEX IF NOT EXISTS idx_np_myservice_items_account
ON np_myservice_items(source_account_id);
CREATE INDEX IF NOT EXISTS idx_np_myservice_items_name
ON np_myservice_items(name);
CREATE INDEX IF NOT EXISTS idx_np_myservice_webhooks_account
ON np_myservice_webhooks(source_account_id);Schema Requirements:
⚠️ Table name MUST start withnp_⚠️ MUST includesource_account_id VARCHAR(255) NOT NULL⚠️ MUST add index onsource_account_id- Use UUID for primary keys (recommended)
- Include
created_atandsynced_attimestamps
nself plugin install ./plugins/my-servicenself plugin my-service sync
nself plugin my-service items list# Send test webhook
curl -X POST http://localhost/webhooks/my-service \
-H "Content-Type: application/json" \
-d '{"type":"item.created","item_id":"123","name":"Test"}'- Update version in
plugin.json - Create git tag:
git tag my-service-v1.0.0 - Submit PR to nself-plugins repository
- Idempotent syncs - Running sync twice should produce same result
- Upsert data - Use ON CONFLICT for database inserts
- Handle errors gracefully - Log errors, don't crash
- Validate input - Check required fields exist
- Use transactions - For multi-table operations
- Rate limit awareness - Respect API rate limits
- Incremental sync - Support syncing only changes
See the Stripe plugin for a complete implementation example.
Which checks run on a pull request is described in CI scope.
- Commands
- File Processing Commands
- GitHub Commands
- ID.me Commands
- Jobs Commands
- Notifications Commands
- Realtime Commands
- Shopify Commands
- Stripe Commands
View All: Home (or see the full alphabetical list below — 129/129 synced with registry.json)
- Access-Controls
- Admin-Api
- AI-CLI
- AI-Studio
- Alerts
- Analytics
- API
- Audit
- Audit-Analytics
- Audit-Log
- Auth-Enterprise
- Backup
- BYOK
- CDC
- CDN
- CI
- Claw-CLI
- Cloudflare
- Compliance
- Content-Acquisition
- Content-Progress
- Content-Safety
- Costs
- CRDT
- Cron
- DDNS
- Devices
- DLQ
- Documents
- Dogfood
- Donorbox
- DR
- E2EE
- Encryption
- Entitlements
- Event-Bus
- Family-Ancestry
- Family-FamilySearch
- Family-GEDCOM
- Family-MyHeritage
- Family-WikiTree
- Feature-Flags
- Federation
- File-Processing
- Flags
- Forgejo
- Functions-V8
- Game-Metadata
- Gateway
- Gauth
- GDPR
- Geocoding
- GitHub
- GitHub-Runner
- HIPAA
- Home
- IDme
- Infra
- Invitations
- Job-Queue
- Jobs
- K8s
- Link-Preview
- Maintenance
- MDNS
- Media-Processing
- Meetings
- MLflow
- Model
- Monitor
- Monitoring
- Notifications
- Notify
- nSelf-Cloud
- nSelf-Eval-Gate
- nSelf-Geo
- nSelf-Image
- nSelf-PDF
- nSelf-Scan
- nSelf-Sync
- nSelf-Vault
- Object-Storage
- Observability
- Ollama
- Payments
- PayPal
- Pentest
- Pentest-Kit
- Plugin-ClawDE
- Plugin-Gauth
- Plugin-LLM-Gateway
- Plugin-PTY
- Plugin-Retrieval
- Podcast
- Post
- Push
- Queue
- Region
- Release
- Retro-Gaming
- Rom-Discovery
- Search
- Sentry-CLI
- Shared-Utils
- Shopify
- SIEM
- SMS
- Soak
- Sports
- Storage
- Stripe
- Subtitle-Manager
- Tenant
- Tenant-Controller
- TMDB
- Tokens
- Torrent-Manager
- Traefik
- Transactional-Email
- VPN
- WAF
- Watchdog
- Web3
- Webhooks
- Workflows
Related