building-logseq-plugins

C0ntr0lledCha0s's avatarfrom C0ntr0lledCha0s

Expert guidance for building Logseq plugins compatible with the new DB architecture. Auto-invokes when users want to create Logseq plugins, work with the Logseq Plugin API, extend Logseq functionality, or need help with plugin development for DB-based graphs. Covers plugin structure, API usage, and DB-specific considerations.

⭐1stars🔀0forks📁View on GitHub🕐Updated Dec 18, 2025

When & Why to Use This Skill

This Claude skill serves as a specialized technical assistant for developers building Logseq plugins, with a primary focus on the transition to the new DB-based architecture. It provides comprehensive guidance on the Logseq Plugin API, Datalog queries, and UI component integration. By offering architectural patterns, compatibility checklists, and code snippets, it streamlines the development lifecycle, helping users create robust extensions that work seamlessly across different Logseq graph versions.

Use Cases

  • Scenario 1: Migrating legacy Logseq plugins to the new DB architecture by implementing structured property handling and entity-based Datalog queries.
  • Scenario 2: Building custom user interface elements within Logseq, such as slash commands, block context menu items, and complex settings schemas.
  • Scenario 3: Developing advanced data management tools that utilize the logseq.DB and logseq.Editor namespaces to automate block manipulation and knowledge retrieval.
  • Scenario 4: Implementing feature detection and compatibility layers to ensure plugins function correctly on both Markdown-based and Database-based Logseq graphs.
namebuilding-logseq-plugins
version1.0.0
description>
allowed-toolsRead, Grep, Glob, WebFetch, WebSearch, Write, Edit, Bash

Building Logseq Plugins

When to Use This Skill

This skill auto-invokes when:

  • User wants to create a Logseq plugin
  • Questions about the Logseq Plugin API
  • Working with logseq.Editor, logseq.DB, logseq.App namespaces
  • Slash command registration
  • Plugin settings schema definition
  • DB vs MD version compatibility for plugins
  • User mentions "logseq plugin", "logseq extension", "@logseq/libs"

You are an expert in Logseq plugin development, with special focus on DB-version compatibility.

Plugin Architecture Overview

Logseq plugins run in sandboxed iframes and communicate with the main app via the Plugin API.

Plugin Structure

my-logseq-plugin/
├── package.json          # Plugin manifest
├── index.html            # Entry point
├── index.js              # Main logic (or TypeScript)
├── icon.png              # Plugin icon (optional)
└── README.md             # Documentation

package.json Manifest

{
  "name": "logseq-my-plugin",
  "version": "1.0.0",
  "main": "index.html",
  "logseq": {
    "id": "my-plugin-id",
    "title": "My Plugin",
    "icon": "./icon.png",
    "description": "Plugin description"
  }
}

Plugin API Basics

Initialization

import '@logseq/libs'

async function main() {
  console.log('Plugin loaded')

  // Register commands, settings, etc.
  logseq.Editor.registerSlashCommand('My Command', async () => {
    // Command logic
  })
}

logseq.ready(main).catch(console.error)

Key API Namespaces

Namespace Purpose
logseq.Editor Block/page manipulation
logseq.DB Database queries
logseq.App App-level operations
logseq.UI UI components
logseq.Settings Plugin settings

DB-Version Specific APIs

Working with Properties

// Get block with properties (DB version)
const block = await logseq.Editor.getBlock(blockUuid, {
  includeChildren: true
})

// Properties are structured differently in DB version
// Access via block.properties object
const author = block.properties?.author

// Set property value
await logseq.Editor.upsertBlockProperty(blockUuid, 'author', 'John Doe')

Working with Classes/Tags

// Get blocks with a specific tag/class
const books = await logseq.DB.datascriptQuery(`
  [:find (pull ?b [*])
   :where
   [?b :block/tags ?t]
   [?t :block/title "Book"]]
`)

// Add tag to block
await logseq.Editor.upsertBlockProperty(blockUuid, 'tags', ['Book', 'Fiction'])

Enhanced Block Properties APIs (2024+)

// New APIs for DB version
await logseq.Editor.getBlockProperties(blockUuid)
await logseq.Editor.setBlockProperties(blockUuid, {
  author: 'Jane Doe',
  rating: 5,
  published: '2024-01-15'
})

Datalog Queries in Plugins

Basic Query

const results = await logseq.DB.datascriptQuery(`
  [:find ?title
   :where
   [?p :block/title ?title]
   [?p :block/tags ?t]
   [?t :db/ident :logseq.class/Page]]
`)

Query with Parameters

const results = await logseq.DB.datascriptQuery(`
  [:find (pull ?b [*])
   :in $ ?tag-name
   :where
   [?b :block/tags ?t]
   [?t :block/title ?tag-name]]
`, ['Book'])

DB vs MD Query Differences

// MD version - file-based queries
const mdQuery = `
  [:find ?content
   :where
   [?b :block/content ?content]
   [?b :block/page ?p]
   [?p :block/name "my-page"]]
`

// DB version - entity-based queries
const dbQuery = `
  [:find ?title
   :where
   [?b :block/title ?title]
   [?b :block/tags ?t]
   [?t :block/title "My Tag"]]
`

UI Components

Slash Commands

logseq.Editor.registerSlashCommand('Insert Book Template', async () => {
  await logseq.Editor.insertAtEditingCursor(`
- [[New Book]] #Book
  author::
  rating::
  status:: To Read
`)
})

Block Context Menu

logseq.Editor.registerBlockContextMenuItem('Convert to Task', async (e) => {
  const block = await logseq.Editor.getBlock(e.uuid)
  await logseq.Editor.upsertBlockProperty(e.uuid, 'tags', ['Task'])
  await logseq.Editor.upsertBlockProperty(e.uuid, 'status', 'Todo')
})

Settings Schema

logseq.useSettingsSchema([
  {
    key: 'apiKey',
    type: 'string',
    title: 'API Key',
    description: 'Your API key for the service',
    default: ''
  },
  {
    key: 'enableFeature',
    type: 'boolean',
    title: 'Enable Feature',
    default: true
  },
  {
    key: 'theme',
    type: 'enum',
    title: 'Theme',
    enumChoices: ['light', 'dark', 'auto'],
    default: 'auto'
  }
])

DB-Version Compatibility Checklist

When building plugins for DB version:

  • Use :block/title instead of :block/content for page names
  • Handle structured properties (not just strings)
  • Support typed property values (numbers, dates, checkboxes)
  • Use tag-based queries instead of namespace queries
  • Test with both DB and MD graphs if supporting both
  • Handle the unified node model (pages ≈ blocks)
  • Use new block properties APIs when available

Common Patterns

Feature Detection

async function isDBGraph() {
  // Check if current graph is DB-based
  const graph = await logseq.App.getCurrentGraph()
  return graph?.name?.includes('db-') || graph?.type === 'db'
}

async function main() {
  const isDB = await isDBGraph()
  if (isDB) {
    // DB-specific initialization
  } else {
    // MD-specific initialization
  }
}

Property Type Handling

function formatPropertyValue(value, type) {
  switch (type) {
    case 'date':
      return new Date(value).toISOString().split('T')[0]
    case 'number':
      return Number(value)
    case 'checkbox':
      return Boolean(value)
    case 'node':
      return `[[${value}]]`
    default:
      return String(value)
  }
}

Development Workflow

  1. Setup: Clone logseq-plugin-template or start fresh
  2. Develop: Use npm run dev for hot reload
  3. Test: Load unpacked plugin in Logseq
  4. Build: npm run build for production
  5. Publish: Submit to Logseq Marketplace

Loading Development Plugin

Logseq > Settings > Advanced > Developer Mode: ON
Logseq > Plugins > Load unpacked plugin > Select folder

Resources