Across my plugin work at LottieFiles and the Chrome extension work I do at Writer, I’ve shipped production plugins and extensions into a portfolio of host ecosystems: Figma, Adobe After Effects and Animate, Canva, VS Code, WordPress, ChatGPT, and Chrome. Each host is, in practice, a different operating system. Different sandbox, different permission model, different storage guarantees, different UI constraints, different review process, and different ideas about what your code is allowed to do.

Most architecture advice quietly assumes you own the runtime. Plugin work takes that assumption away, and what remains is the most honest architecture training I’ve had in 13+ years of shipping software. When the host controls your memory, your network, your storage, and your release schedule, every sloppy boundary in your codebase gets found. Here is what that pressure taught me.

Share decisions, not surfaces

The obvious move for a multi-platform portfolio is a shared core with host-specific adapters. It is the right move — but where you draw the line decides whether it works. The naive version shares UI components and tries to render the same interface everywhere. It fails fast: Figma gives you an iframe beside a canvas, VS Code wants tree views and webviews with its own theming, WordPress hands you a server-rendered admin page, and Adobe’s CEP panels run in an embedded browser generations behind anything you would target on the open web. A shared UI layer degrades into a pile of host conditionals that is worse than separate implementations.

What shares well is everything that isn’t a surface: the API client, the file-conversion pipelines, caching and retry logic, and the domain model of what an animation is and what a user can do with it. At LottieFiles, that split is what kept features consistent across the whole portfolio without versions drifting apart. The rule I ended up with: share decisions, not surfaces. And let adapters be thick where the host demands it — thin-adapter dogma just relocates host complexity into the core, which is the one place it must never live.

The test for whether the boundary sits in the right place is mechanical. When a host changes its API, the diff should stay inside that host’s adapter. The first time a Figma manifest change touches your conversion pipeline, the boundary has already failed — you are just finding out late.

Design auth for the most hostile sandbox first

Auth is where cross-platform work punishes optimism hardest. A plugin UI in a design tool runs in a sandboxed, effectively null-origin iframe: no cookies you can rely on, no persistent origin storage, no redirect URI where an OAuth callback can land. If you design your auth flow for a friendly host first — a Chrome extension with an identity API, say — you will retrofit security per platform forever, and retrofitted auth is where token-handling bugs are born.

So I design for the most hostile sandbox first. The flow that survives everywhere looks like this: the actual OAuth authorization happens in the system browser, where cookies and redirects work; the plugin holds a one-time pairing code and polls the backend for completion; refresh tokens never enter the plugin at all — they stay server-side; the plugin keeps only a short-lived access token, in memory. Permission scopes stay minimal and legible, because two different audiences will read them: the host’s review team now, and an enterprise security team later, deciding whether your product is allowed inside their tenant.

Every other platform then becomes a relaxation, not a rework. VS Code offers a secrets store and URI handlers — use them, but the flow must not depend on them. WordPress runs server-side, where the constraint set is entirely different but the token model still holds. Relaxing a constraint per host costs a few lines in an adapter. Adding security to a flow that assumed a friendly host is a rewrite.

Treat memory and bundle size as product requirements

Hosts give you a fraction of the resources you are used to. A Figma plugin shares the machine with a design file that may already be straining it. Adobe’s CEP panels run inside an embedded Chromium far behind current browsers. And animation workloads punish carelessness: Lottie files are JSON documents that can embed image assets and expand dramatically in memory once parsed and rendered. Budgets stop being an engineering virtue and become a product requirement, enforced like one:

  • A bundle budget per host, checked at build time — a size regression that is invisible on the web is a startup-time regression inside a panel.
  • The renderer loaded lazily. Most plugin sessions browse and search before they ever preview an animation, so the heaviest dependency has no business in the critical path.
  • Caches with explicit eviction policies, not caches that grow until the host kills the plugin — the host will not send a memory warning first.
  • Minimal traffic across the postMessage bridge between the plugin sandbox and its UI, because structured-clone serialization of large animation payloads is a real cost paid on every message.

Chrome’s Manifest V3 enforces its own version of this discipline: the service worker can be terminated at any moment, so long-lived in-memory state is a bug, not a design. Everything that matters must persist and rehydrate. It is inconvenient, and the code that survives it comes out more robust for exactly that reason.

Review queues and API breakage are weather

Every plugin release ships through someone else’s review process, on their timeline. You cannot hotfix a client a marketplace has not approved yet, and old versions live in the wild indefinitely because you cannot force an upgrade. Both facts have architectural consequences, and treating them as operational annoyances is how teams end up shipping apology releases.

The consequences: keep the plugin thin and move every decision you can server-side, where you deploy on your own schedule. Version the contract between plugin and backend explicitly, because at any given moment several plugin versions are talking to one API. Gate new behavior behind server-side flags, so a capability ships inside a reviewed binary but activates when you choose. And treat host API breakage — the Manifest V2 to V3 class of change — as a scheduled migration with an owner, not an emergency. If the adapter boundary is honest, it has already contained how far the change can reach.

When not to support a platform

The hardest-won lesson is that a platform is not a checkbox — it is a standing liability you choose to carry. The integration is the small cost. The real cost is the permanent tax: another review queue in every release, another API churning underneath you, another row in the support and testing matrix, indefinitely. A portfolio’s maintenance cost scales with the number of hosts whether or not users show up on each one.

Leaving a platform deserves the same seriousness as entering one — a deliberate deprecation path, not a slow ghosting of users who built your plugin into their daily workflow. And I argue against entering when any of these is true:

  • The sandbox cannot hold the core workflow. A degraded port teaches that platform’s users that your product is worse than it actually is.
  • The audience overlap is marginal, so the marketplace listing is a vanity checkbox rather than distribution.
  • The host’s review policy or data-handling rules conflict with your release cadence or your security model — a conflict that never resolves in your favor.

Why this matters more now

AI products are moving into other people’s surfaces at speed — assistants inside IDEs, browsers, office suites, and chat platforms. The ChatGPT plugin ecosystem was an early version of exactly this shape, and every AI company shipping a browser extension or an editor integration is doing plugin engineering now, whether it uses the word or not. The rules do not change: share decisions rather than surfaces, design auth for the most hostile sandbox, budget resources like requirements, keep the client thin, and choose hosts the way you would choose liabilities.

If your product has to live inside someone else’s platform and the portfolio is drifting — versions diverging, auth handled differently per host, releases stuck in review — that is a problem I have untangled before. A strategy session is usually enough to tell whether you need an architectural change or just discipline about the boundary you already have.