← all posts
// tooling · jetbrains

JetBrains Marketplace now flags internal API use: your plugin has an expiry date

The Q2 2026 edition of JetBrains' Busy Plugin Developers newsletter went out on July 21, and one line in it changes how I plan plugin maintenance. JetBrains Marketplace now automatically notifies authors whose plugins touch internal or unsupported APIs, as part of the ongoing IntelliJ Platform API stabilisation. That is a polite sentence for a hard fact: any plugin that leans on an internal API now has an expiry date, and the Marketplace can tell you which one.

What shipped on July 21

  • Internal API notifications. The Marketplace scans listings and warns the author when a plugin uses internal or unsupported API surface, so you can migrate before a platform build breaks it, not after.
  • Exceptions tab by default. Every author now gets the exception analyzer view without asking for it.
  • Plugin Template 2.6.0, built on IntelliJ Platform Gradle Plugin 2.16.0, IDEA 2025.2.6.2 and Gradle 9.5.0.
  • Plugin Verifier 1.409 and IntelliJ Platform Gradle Plugin 2.18.1.
  • A new web-based IDE Plugin Generator that replaces both the old wizard and the Plugin Template as the way to scaffold a plugin.

Two related changes arrived in the 2026.2 cycle, which started on July 16: the LSP client API is now open source across JetBrains IDEs, Android Studio and products built on the open platform, and the Java plugin was split into modules with their own classloaders, which requires Gradle Plugin 2.x. As of July 20, LspServerManager was renamed to LspClientManager, and the service is registered only under the new interface. Call the old getInstance and the build against 2026.2 fails.

Why a notification is not a grace period

The notification is a warning, not a deferral of deprecation. Internal API is code JetBrains never promised to keep, and stabilisation means they are now actively drawing the line between the public surface and everything else. A plugin that works today on an internal class can stop working on any 2026.x build, without a changelog entry that mentions your use case.

The commercial consequence is quiet. A user updates the IDE, your plugin fails to load or throws in the exception analyzer, they leave a two-star review, and installs drift down over a quarter. That is the failure mode the flag exists to prevent, which is why I treat it as a P1 the day it appears.

Internal API in a plugin is a loan with a floating rate, and the Marketplace flag is the first statement showing the rate went up.

The migration checklist I run

  • Check the author dashboard for every listing. If a plugin is flagged, that is the work queue.
  • Grep the source for @ApiStatus.Internal on every symbol you touch, including transitive ones pulled in through extension points. The annotation is the contract; the notification is only the enforcement.
  • Run Plugin Verifier 1.409 against the current build and the latest EAP, not just the sinceBuild you shipped with.
  • Replace internal calls with stable equivalents. Where none exists, file the request and isolate the call behind one adapter class so the blast radius is one file.
  • Bump the target through Gradle Plugin 2.18.1, and if you integrate with LSP, rename to LspClientManager before you build against 2026.2.
  • Release in lockstep. Version bump, change-notes in plugin.xml, README and the Marketplace listing all move in one commit. A hotfix that updates the binary but not the listing is how you get support tickets for a bug you already fixed.

If your plugin talks to an agent through ACP or ships an MCP integration for Junie, audit those code paths first. They tend to be the newest code, written against the least stable APIs.

What the new generator changes

For new plugins the web generator replaces the wizard and the template in one move. The point is not speed. It is that the scaffold starts on the current Gradle Plugin and current template conventions, so a plugin born today does not start life with internal API debt. Existing plugins get none of that for free.

The honest gap

I have not seen JetBrains publish what the scanner actually detects. It may catch direct calls to @ApiStatus.Internal symbols and miss reflection, bytecode-level access or internal classes reached through a dependency. Treat a clean dashboard as necessary, not sufficient, and keep your own verifier run in CI as the real gate.

#jetbrains#plugins#api-stability#maintenance