Summer is over, and the IntelliJ Platform kept moving. The short video gives you the quickest possible version of ten changes that stood out for plugin authors. This post is the slower companion and explains why you should care about each change, when to act, and
where to start if it touches your plugin.
1. Native plugin variants in the Gradle plugin
This topic is for you if your plugin ships native binaries such as launchers, helper tools, native libraries, or anything else that varies by operating system or CPU architecture. Previously, many plugins either bundled all native artifacts into a single ZIP or maintained custom packaging logic. Native plugin variants make that a first-class Gradle Plugin workflow.
The important question is whether your users need different native files on Linux, macOS, or Windows, and whether you are ready to target the 2026.1 platform baseline or newer. If the answer is yes, you can use intellijPlatform.nativeVariants to describe the native files for each target, then build variant ZIPs instead of one universal package. The generated descriptors are patched with OS and architecture dependencies, and publishing can upload the generated ZIPs together.
If your plugin is pure JVM code, you probably do not need to do anything. If you currently ship one large archive because native packaging was awkward, you can use this in your next 2026.1+ release. Platform-specific packages are already visible on the Marketplace: the Android plugin publishes OS/architecture-specific packages, and GitHub Copilot also publishes platform-specific packages for 2026.1+ IDEs. These are examples of real plugins that need to ship different native payloads without making every user download every platform’s binaries.
Start with the official Gradle Plugin documentation for
intellijPlatform.nativeVariants, because it shows the DSL and the platform-baseline requirement. The Gradle task documentation for buildPluginVariants explains the generated build tasks and classifiers. If you need to understand exactly how descriptors are patched and validated, the implementation is in
PreparePluginVariantTask.kt.
2. Integration testing with Starter, Driver, and testIdeUi
Plugin integration tests have always been something you don’t talk about at parties. To be fair, AI wanted me to tell you that integration tests were the part where many projects quietly accumulate custom scripts, but who are we kidding, right? However, now the updated SDK guidance gives plugin authors a documented route for starting an IDE, installing the plugin, opening a project, collecting logs, and driving UI or API checks from tests.
It is something for you if your plugin behavior depends on a real IDE instance. That includes tool windows, actions, project indexing behavior, UI flows, settings pages, and workflows where unit tests just don’t cut it. Starter handles IDE preparation and launch. Driver talks to the running IDE, including UI interactions and API calls. On the Gradle side, intellijPlatformTesting.testIdeUi gives you a task model instead of a hand-rolled launcher.
The caveat is that both Driver and UI APIs are still experimental. For plugin projects that already have fragile UI tests, this may still be an improvement, but do not treat the API surface as frozen. For new integration tests, though, this is the path I would start from rather than inventing another local test harness.
The best entry point is the SDK page on integration tests, which explains the
Starter and Driver split and the Gradle setup. The UI testing page is where to look once you need component lookup and interaction examples. The Gradle side is documented under
testIdeUi, including its incubating status.
3. LSP OpenAPI moved from server names to client names
If you use IntelliJ Platform LSP support, check your imports and extension registration. The IDE-side API is moving away from names like LspServerSupportProvider and toward names that match the LSP model more accurately. Now, the IDE is the “LSP client”, and it talks to a “language server”.
New code should use the client-named APIs, including LspIntegrationProvider, LspClientDescriptor, ProjectWideLspClientDescriptor, and LspClientManager. The extension point to use is com.intellij.platform.lsp.integrationProvider. The older server-named APIs and extension point remain as deprecated for a while, in case you still support older IDE builds, but they should not be the default for new 2026.x work.
The migration is straightforward if your usage is close to the documented API. It becomes more interesting if you have abstractions around service lookup, extension registration, or compatibility layers across multiple platform versions. In that case, make the naming change deliberately and test against the oldest IDE you still support.
The SDK has a direct LSP API refactoring section with the rename table. For source-level confirmation, LspIntegrationProvider.kt shows the current provider API, while the LSP implementation XML shows both the current and deprecated extension point declarations.
4. Stricter plugin descriptor reachability and dynamic plugin checks
This is mostly a correctness change, but it can feel like a build or IDE inspection suddenly became stricter. You will see it most often in multi-module plugins, plugins with optional descriptors, plugins split into content modules, and plugins that reference classes or extension points from another bundled or external plugin.
Practically, it just means if your plugin.xml references a class, action, group, resource bundle, or extension point, that thing must be reachable through the plugin’s declared dependency graph. A Gradle dependency alone may not be enough, because runtime plugin loading follows descriptor dependencies. When DevKit reports an unreachable reference, fix both sides: the build-system dependency and the corresponding plugin.xml dependency structure.
Also, be careful if your plugin supports dynamic unload and reload. Dynamic plugin checks are stricter about descriptor shape and runtime behavior. For example, dynamic extension points need to be declared correctly, action groups need IDs, and some plugin structures still require a restart.
The public SDK page on dynamic plugins is the best starting point for understanding what can and cannot reload dynamically. The page on dynamic extension points explains what is required when declaring EPs that support dynamic behavior. The newer descriptor reachability inspection is mainly source-backed; PluginXmlReferencesModuleReachabilityInspection.kt is the place to look if you need to understand exactly what DevKit is checking.
5. Search Everywhere contributor API deprecation
Plugins that add results to Search Everywhere should look at this one. You don’t need to rush into a procrastinatory refactoring session, but take a look. The older SearchEverywhereContributor and SearchEverywhereContributorFactory APIs are deprecated. The replacement direction is SeItemsProvider and SeItemsProviderFactory, registered through com.intellij.searchEverywhere.itemsProviderFactory.
You should know about the deprecation because Search Everywhere integrations are often central to productivity plugins, and deprecated APIs can become annoying if ignored for too long. You shouldn’t rush into it, because the new provider API is still experimental, and parts of the source surface are not as stable as a normal OpenAPI migration target.
For now, I would avoid writing new code against the old contributor model. For existing plugins, start by identifying your current SearchEverywhereContributor implementations and watching the newer provider model. If you need to migrate soon, isolate the integration behind your own small adapter so you have less code to revisit if the experimental API changes.
The official extension point list is useful here because it shows com.intellij.searchEverywhere.itemsProviderFactory and its experimental status. The
replacement source is SeItemsProvider.kt. The old API deprecation is visible in SearchEverywhereContributor.java, which is helpful when you need to confirm what exactly is being phased out.
6. Plugin error reporting and automatic observability
Error reporting now has a clearer split in the SDK docs. ErrorReportSubmitter is still the path for user-submitted reports from the Fatal Errors UI. The newer ErrorReportSink extension point is for automatic plugin-attributed exception and freeze reports.
You should definitely take a look if you maintain a plugin with enough users that production diagnostics are worth the effort, especially if you currently rely only on users manually reporting errors. Automatic reporting can include unhandled exceptions and freeze reports. Freeze reports can carry duration, attachments, and thread dumps, which is exactly the sort of information that is hard to reconstruct after the fact.
There are several caveats. ErrorReportSink is experimental. Delivery is best effort, not a guarantee. There are limits, and the platform does not solve your deduplication, debouncing, rate limiting, or privacy policy for you. In other words, this is a useful observability hook, not a complete reporting product.
Start with the SDK page on error reporting, because I updated it recently and tried my best to explain everything in detail. If you want to use JetBrains infrastructure for user-submitted reports, the Marketplace documentation for the Exception Analyzer explains that path. For exact report types, limits, and extension point details, read ErrorReportSink.kt.
7. Kotlin UI DSL 1.0 removal
This is the most direct migration warning in the list. Kotlin UI DSL 1.0, the old com.intellij.ui.layout API, is gone. If your plugin still imports that package, expect compilation failures or runtime problems when targeting newer builds.
If you use settings pages, configurables, inspection option panels, dialogs, or custom forms written with the old Kotlin UI DSL, the compiler will come for you.
The replacement is Kotlin UI DSL v2, now the current Kotlin UI DSL, under com.intellij.ui.dsl.builder. In day-to-day code this usually means replacing old layout imports and updating panel, row, cell, and binding calls to the v2 shape.
This is easy to triage. Search your plugin for com.intellij.ui.layout. If it appears, schedule the migration before you move your target platform forward. Also check module dependencies if you were depending on implementation modules just to access UI DSL APIs.
The official 2026 API changes list calls out the removal. The older UI DSL page has the useful migration to version 2 table. For current code, use the Kotlin UI DSL v2 documentation, which covers the com.intellij.ui.dsl.builder API.
8. PolySymbols PSI-linked APIs and own references
This is narrower than some of the other changes, but it is aimed at language, framework, and web ecosystem plugins that use PolySymbols. The old PSI-sourced terminology has been renamed to PSI-linked terminology. In practice, PsiSourcedPolySymbol becomes PsiLinkedPolySymbol, and source becomes linkedElement.
The rename describes the model more clearly: a PolySymbol can be linked one-to-one to a real PSI element, and platform features such as navigation, rename, usages, and equivalence can route through that linked element. If your plugin exposes framework-specific symbols backed by PSI, this is the area to review.
There is also a new own references mechanism: PolySymbolOwnReferenceHost and polySymbolOwnReferences(...). Use it when the reference belongs intrinsically to the PSI element itself. One detail to watch: own references take priority over external polySymbols.psiReferenceProvider references, so do not accidentally model the same thing twice.
The PolySymbols section in the 2026 API changes list is the best starting point for the rename. The source for PsiLinkedPolySymbol shows the linked-element model. The own references behavior is documented in code in PolySymbolOwnReferences.kt.
9. Coroutine edtWriteAction
Coroutine-based plugin code now has a clearer API when you need to perform write work, and that write work must run on the Event Dispatch Thread. The API is suspend fun <T> edtWriteAction(action: () -> T): T in com.intellij.openapi.application.
Use it for the actual mutation step when PSI, VFS, or project model changes require a write lock and must happen on the UI thread (EDT, yep, same thing). Do not use it as a way to move a large operation onto the UI thread. Prepare data in the background, then keep the write block small. If the operation should participate in undo/redo, use a write command instead.
This is most relevant if your plugin already uses Kotlin coroutines and you have code that manually combines EDT dispatching with write actions. For general coroutine write work, also look at the broader suspending write-action APIs and threading guidance, because edtWriteAction is not a replacement for understanding where write actions belong.
The exact API is in coroutines.kt. The SDK threading model explains write actions and when to use command-aware alternatives. The coroutine dispatchers page is useful background for EDT dispatching and modality in coroutine code.
10. Background-capable bulk VFS listeners
If your plugin listens to VFS changes and does real work in those callbacks, this one is worth checking. BulkFileListenerBackgroundable is now stable OpenAPI for listeners that need synchronous bulk VFS event delivery but can safely run on a background thread. The related topic is VirtualFileManager.VFS_CHANGES_BG.
This is not a recommendation to move every VFS listener. Prefer AsyncFileListener when it is enough, because it is designed for asynchronous preparation around VFS events. Use the background bulk listener path when you truly need synchronous delivery, and your listener is thread-safe, project-aware, and has no UI dependency.
Pay attention to the threading detail. The callbacks still run under a write action, but on a background thread, and before and after callbacks are not guaranteed to use the same thread. VFS events are also project-agnostic, so plugins still need to filter by project content themselves.
The SDK notable API changes page has the public entry for background-capable VFS listeners. The source contract for the listener is in BulkFileListenerBackgroundable.kt.
VirtualFileManager.java shows the VFS_CHANGES_BG topic.
What to check in your plugin
If you only have time for a quick pass, search your codebase for the obvious migration markers: com.intellij.ui.layout, SearchEverywhereContributor, LspServer, LspServerSupportProvider, PsiSourcedPolySymbol, custom VFS listeners, and old custom IDE test launchers. Also, review plugin.xml dependencies if your plugin is split across modules or uses optional descriptors.
As always, if you’ve got any questions, feel free to ask, and we’ll do our best to answer.