Custom GPTs Retire Dec 11, 2026: How to Migrate to Plugins

TL;DR
Custom GPTs retire Dec 11, 2026. Instructions and files migrate to a ChatGPT plugin automatically; custom actions do not.
OpenAI is retiring custom GPTs on Dec 11, 2026 (Feb 11, 2027 for Enterprise workspaces with an approved deferral) and replacing them with plugins, which package your instructions as a skill alongside connected apps and reference files. The built-in Migrate to plugin button moves instructions, knowledge files and connected apps for you; custom actions do not move, so any GPT that calls your own API needs that integration rebuilt, usually as an MCP server. Verdict: if your GPT is instructions plus files, click migrate and test it this week. If it has Actions, start the MCP rebuild now, not in December.
Last updated: October 17, 2026
Everything below is checked against OpenAI's release notes, the Custom GPT retirement FAQ and the plugin developer docs as of this date. The TypeScript server was type-checked, not run against a live API, because the example backend is fictional.
What is changing, and the dates#
On September 11, 2026, OpenAI posted "Planned custom GPT retirement and migration to plugins" in the ChatGPT release notes. The note says OpenAI plans to retire custom GPTs across ChatGPT plans and provide a migration path to plugins, that existing GPTs keep working until the retirement date that applies to you, and that timing may vary by plan and workspace.
The retirement FAQ fills in the dates. OpenAI describes all of them as subject to change and tells you to follow the in-product notice:
| Date | Milestone | Applies to |
|---|---|---|
| Sep 11, 2026 | Admin notice | Enterprise |
| Sep 22, 2026 | Target for migration experience and user banner | Enterprise |
| Oct 1, 2026 | Banner target for workspaces that opted into delayed migration banners | Enterprise |
| Oct 26, 2026 (planned) | Creation of new custom GPTs ends; edits to existing unmigrated GPTs still allowed | Enterprise |
| Dec 11, 2026 | Standard retirement: custom GPTs and GPT pages become inaccessible | All plans |
| Feb 11, 2027 | Retirement for workspaces with a qualified, approved deferral | Some Enterprise |
Three details in the FAQ are easy to miss:
- The creator's workspace sets the clock. The timeline and permissions of the account or workspace where the GPT was created apply, even if you use it from another account. A public GPT built in an affected Enterprise workspace follows the Enterprise transition even when you open it from a personal Plus account.
- Conversations survive, GPT pages do not. Existing conversations with custom GPTs remain accessible after retirement. The GPT itself and its page do not.
- A target date is not a guarantee. OpenAI says migration access may arrive at different times, and a missing migration button before your workspace's date does not by itself mean something is wrong.
This is the second half of a move that started on July 9, 2026, when OpenAI replaced the App Directory with the Plugin Directory and made plugins available across web and desktop, including Work and Codex. If you missed that change, the ChatGPT Work and Codex desktop app breakdown covers it.
Custom GPT vs plugin, field by field#
A plugin is a package. Per OpenAI's plugins help article, it can include skills (instructions and workflow guidance), connected apps, app templates for admins, and extensions such as interactive views, mentions, file viewers and forms. Some plugins are skills-only and need no app connection at all, which is exactly what a typical "instructions plus PDFs" GPT becomes.
Here is how each part of a GPT maps across, according to the FAQ:
| Custom GPT field | After "Migrate to plugin" |
|---|---|
| Instructions | Become a skill in the new plugin |
| Knowledge files | Copied into the plugin's reference files |
| Connected apps | Added to the plugin as apps |
| Custom actions | Not migrated. Rebuild, often as a custom MCP server |
| Selected model | Not carried over (Enterprise defaults apply in Enterprise) |
| Sharing settings | Not carried over. The plugin starts private and is not auto-installed |
| Drafts and unpublished edits | Not migrated. Only the latest published version moves |
| The original GPT | Stays usable until retirement, becomes read-only, and its creator cannot delete it |
%% title: What the Migrate to plugin button moves
flowchart LR
subgraph GPT["Custom GPT"]
I[Instructions]
K[Knowledge files]
A[Connected apps]
X[Custom actions]
M[Selected model]
S[Sharing settings]
end
subgraph PL["Plugin - private"]
SK[Skill]
RF[Reference files]
AP[Apps]
end
I --> SK
K --> RF
A --> AP
X --> N[Not migrated]
M --> N
S --> NThe practical reading: the migration handles content, not behavior that depends on your infrastructure. Anything that made an HTTP call to a system you own is your job.
Step 1: inventory before you click#
Migration is one-way in an important sense: the original GPT goes read-only the moment you migrate it. So the FAQ's prep advice is worth doing in order.
- List the GPTs you rely on. For each one, note who created it (only the creator, or an Enterprise workspace admin, can migrate it), which workspace it was created in, and who uses it.
- Finish and publish essential edits first. Migration uses the latest published version. Publishing does not require public sharing, so you can publish with the same restricted sharing the GPT has today. In Enterprise, do this before the planned Oct 26 creation freeze if you still have drafts you need.
- Save a regression set. Write down three to five prompts you run all the time plus one hard case, along with what a good answer looks like. You will replay these against the plugin.
- Flag every GPT with Actions. Those need the developer track in Step 3. The FAQ explicitly says to allow extra time for them.
- Edit the GPT description now. If you plan to point users at a replacement, change the description before migrating, because you cannot edit it afterward.
Step 2: run the built-in migration#
When migration is available for your account:
- Open My GPTs.
- Select Migrate to plugin on the GPT.
- Review the migration details and follow the prompts.
The result is a private plugin. It is not installed for you and nobody else gets access. Install it yourself, then replay your regression set. OpenAI's FAQ lists four things to check: that it selects the right skill and follows your instructions, uses the expected reference material, produces complete answers or files in the required format, and has the tools and integrations the workflow needs.
The biggest behavior change is how the instructions get triggered. A GPT applied its instructions to every message in its chat. A skill is different: ChatGPT may use an installed skill automatically when its description matches the request, and the FAQ is explicit that it will not necessarily run on every request. That makes the skill's description field the most important line in the migrated plugin. A tight, specific description looks like the format in OpenAI's own skill example:
---
name: release-notes-writer
description: Turn a list of merged pull requests into customer-facing release notes in our house style. Use when the user pastes PR titles or asks for release notes.
---
Group changes into Added, Changed and Fixed. Lead with user impact, not implementation.
Use the style guide in the reference files. Never invent version numbers.
When you need the skill to run regardless, invoke it explicitly with an @ mention or open + and select More. If you are unsure whether a given instruction belongs in a skill at all, or should become a tool, the MCP servers vs Agent Skills decision guide has a five-question test.
To edit the plugin afterward, mention @plugin-creator together with the plugin (Plugin Creator is installed from the plugin directory). In Enterprise, note the cost model from the FAQ: using a migrated GPT without apps in Instant Chat has no incremental cost, but creating and editing plugins through a conversation uses Work or Codex, and actions in Work consume credits.
%% title: Migration and test loop
sequenceDiagram
participant C as Creator
participant G as My GPTs
participant P as Plugin
participant W as Workspace
C->>G: Migrate to plugin
G->>P: Create private plugin
Note over G: Original GPT is now read-only
C->>P: Install and run saved prompts
P-->>C: Outputs to compare
C->>P: Tighten skill description
C->>W: Share or publish
Note over W: Separate permissionsStep 3: rebuild custom actions as an MCP server#
This is the part only developers can do. A GPT Action, per OpenAI's Actions introduction, used function calling to decide which REST call was relevant, generate the JSON input, and execute the call, with an authentication mechanism you configured on the action. The FAQ says these do not transfer, that rebuilding the connection may require a custom MCP server, and that a rebuilt integration should not be assumed to provide every capability of the original. Before building, check whether an existing app in the Plugin Directory already covers the service you were calling.
If you do build, the mapping is straightforward: each operation in your old OpenAPI schema becomes one focused MCP tool with an input schema, an output schema and honest annotations. OpenAI's MCP server guide uses the official TypeScript SDK with McpServer, registerTool, inputSchema, outputSchema and the readOnlyHint, destructiveHint and openWorldHint annotations, and returns both structuredContent and content. It also recommends keeping the key details of the server's instructions in the first 512 characters.
Install:
npm install @modelcontextprotocol/sdk zod expressHere is a GPT Action that called GET /orders/{id}, rebuilt as a stateless Streamable HTTP server:
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { z } from "zod";
const API_BASE = process.env.ORDERS_API_BASE ?? "https://api.example.com";
function buildServer(): McpServer {
const server = new McpServer(
{ name: "acme-orders", version: "1.0.0" },
{
instructions:
"Look up Acme order status by order ID. Read-only. Order IDs look like ORD-12345.",
},
);
// One focused tool per former GPT Action operation (here: GET /orders/{id}).
server.registerTool(
"get_order_status",
{
title: "Get order status",
description:
"Use this when the user asks where an order is or when it will arrive.",
inputSchema: {
orderId: z.string().regex(/^ORD-\d+$/).describe("Order ID, e.g. ORD-12345"),
},
outputSchema: {
orderId: z.string(),
status: z.enum(["processing", "shipped", "delivered", "cancelled"]),
eta: z.string().nullable(),
},
annotations: {
readOnlyHint: true,
destructiveHint: false,
openWorldHint: false,
},
},
async ({ orderId }) => {
const res = await fetch(`${API_BASE}/orders/${encodeURIComponent(orderId)}`, {
headers: { Authorization: `Bearer ${process.env.ORDERS_API_TOKEN ?? ""}` },
});
if (!res.ok) {
return {
isError: true,
content: [{ type: "text", text: `Order lookup failed: HTTP ${res.status}` }],
};
}
const data = (await res.json()) as {
status: "processing" | "shipped" | "delivered" | "cancelled";
eta: string | null;
};
const structuredContent = { orderId, status: data.status, eta: data.eta };
return {
structuredContent,
content: [{ type: "text", text: JSON.stringify(structuredContent) }],
};
},
);
return server;
}
const app = express();
app.use(express.json());
// Stateless Streamable HTTP: a fresh server and transport per request.
app.post("/mcp", async (req, res) => {
const server = buildServer();
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
res.on("close", () => {
void transport.close();
void server.close();
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000, () => console.log("MCP server on http://localhost:3000/mcp"));
This was type-checked with npx tsc --noEmit (strict, moduleResolution: "bundler") against @modelcontextprotocol/sdk@1.32.1, zod@4.6.7, express@5.3.0, @types/express@5.0.6 and TypeScript 7.0.2. It was not run against a live API.
A few design choices are deliberate:
- One tool per operation, not one tool per API. A GPT Action could expose a whole OpenAPI spec. Smaller tools with specific "Use this when..." descriptions give the model a cleaner choice, and accurate annotations help ChatGPT decide when a call should ask for confirmation. Mark anything that writes data with
readOnlyHint: false, and anything irreversible withdestructiveHint: true. - Stateless transport. Passing
sessionIdGenerator: undefinedputs the SDK transport in stateless mode, so no session IDs are issued or validated and any instance behind a load balancer can answer. - The static token is a placeholder. The
ORDERS_API_TOKENbearer header mirrors a service-level API key on an old Action. If the tool reads per-user data, OpenAI's docs say to use OAuth 2.1 instead.
Test it locally with the MCP Inspector: run npx @modelcontextprotocol/inspector, choose the Streamable HTTP transport, and connect to http://localhost:3000/mcp. Call get_order_status and confirm the response carries both structuredContent and a text content block. For a longer walkthrough of tool design, resources and transports, see how to build MCP servers.
Auth when you package it. Plugin mcp.json files declare auth per server under extensions["com.openai"].auth, with four types documented in the packaging guide: none, oauth (with client.mode of provided, dcr or cimd), mixed (public plus OAuth-protected) and api_key (with headerScheme of bearer, basic or custom_header). Two limits matter for Action migrations: the manifest does not accept a clientSecret field (you supply it in the connection setup flow), and API-key declarations are not supported by the submission portal's connection form. If your old Action used a static API key and you want a public listing, plan for OAuth.
Step 4: wire the MCP server into the migrated plugin#
OpenAI documents a test path that uses Plugin Creator to connect a registered MCP server to a plugin:
- Go to chatgpt.com/plugins.
- Select the plus button, then Add custom MCP server, and fill in your server URL and connection details.
- Review the risk warning and select I understand and want to continue.
- Select Create as a plugin.
- Copy the technical ID from the browser URL. It starts with
plugin_asdk_app. - Give that ID to
@plugin-creatorin Work mode (or$plugin-creatorin Codex). OpenAI's example prompt:
@plugin-creator create a plugin for ChatGPT and Codex using my MCP server.
Use plugin_asdk_app_6a4c0062f3b88191855c0a80eac5d53d and name it Acme Support.
Include a personal marketplace entry so I can test it locally.
Then review what it generated: .app.json should map to the correct plugin_asdk_app... ID, and .codex-plugin/plugin.json should have its apps field pointing to ./.app.json. Copy the skill from your migrated plugin into skills/ so the instructions and the tool ship together, refresh ChatGPT, and install from your local source in the Plugins Directory.
Note that @plugin-creator currently scaffolds the Codex compatibility layout, not the portable one. If you want a package other clients can read, OpenAI documents the portable Agent Plugins 1.0.0 layout: a root plugin.json, skills under skills/<name>/SKILL.md, and an mcp.json. The minimal manifest from OpenAI's docs:
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "my-first-plugin",
"version": "1.0.0",
"description": "Reusable greeting workflow"
}
And the remote server entry in mcp.json, which, unlike the scaffold's .mcp.json, declares a transport type:
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"docs": {
"type": "streamable-http",
"url": "https://example.com/mcp"
}
}
}
OpenAI-specific settings, such as display metadata and registered .app.json mappings, go under extensions.com.openai in the root plugin.json. A .codex-plugin/plugin.json remains supported as a compatibility fallback when that object is absent; the two are not merged.
%% title: Plugin package anatomy
flowchart TD
PJ[plugin.json] --> SK["skills/ - migrated instructions"]
PJ --> RF[Reference files]
PJ --> MJ[mcp.json]
MJ --> MS[Your MCP server]
MS --> API[Your REST API]
PJ --> EX[extensions.com.openai]
EX --> UI[Interface metadata]
EX --> AJ[".app.json mappings"]Enterprise permissions. The built-in migration does not require upload permissions, but the rebuild does touch them. In the plugins help article, Upload plugins and Create plugins with MCPs are both off by default for Enterprise roles. Ask your admin for them now rather than in the first week of December.
Step 5: share, publish and tell your users#
Migration copies no sharing. What you need next depends on the audience:
- Just you: install the private plugin and you are done.
- People or groups in an Enterprise workspace: requires the Share plugins permission.
- The whole workspace directory: requires Publish plugins to workspace, a separate permission. Workspace admins can also publish from Personal in chatgpt.com/plugins and pick which roles get access.
- The public directory: requires a separate plugin submission. For plugins with an MCP server, OpenAI's submission flow needs a stable public HTTPS Streamable HTTP endpoint, domain verification and OpenAI review.
On the user side, people need the Use plugins permission (on by default in Enterprise) plus a workspace policy that lets them install the plugin or installs it for them. Any included apps still need their own authorization. Before you ask anyone to switch, have one intended user install it and run a real task, which is exactly what OpenAI's FAQ recommends.
Gotchas and limits#
- Drafts are lost. Only the latest published version migrates.
- Model choice is lost. If your GPT depended on a specific model, retest on whatever the plugin runs with. Enterprise gets Enterprise defaults.
- You cannot undo or delete. After migration the original GPT is read-only and the creator cannot delete it.
- Actions do not migrate, and rebuilt ones may not match. OpenAI says not to assume a rebuilt integration provides every capability of the original action.
- Skills are not always on. Auto-selection depends on the description matching the request. Use
@mentions for must-run workflows. - Permission to use is not permission to migrate. Only the creator, or an Enterprise workspace admin, can migrate a GPT.
- Directory refresh lag in Codex. OpenAI notes Codex directory changes can take up to 6 hours to refresh.
- Lifecycle hooks block public listing. Hooks are supported only for manually installed Codex desktop plugins, and a plugin containing them is not eligible for the public directory.
- Local MCP servers are a different path. Public submission wants a remote HTTPS endpoint; local servers go through OpenAI's separate desktop-only submission process.
How it compares to the closest alternative: Claude Code plugins#
The nearest equivalent to what OpenAI is building is Anthropic's Claude Code plugin system, and OpenAI's own guide for Claude Code plugin authors is the clearest documented comparison. The main structural difference, in OpenAI's words: Claude uses separate submission processes for Claude Code plugins and MCP connectors, while OpenAI uses one plugin package that can contain skills, MCP servers or both. Claude marketplace listings and approvals do not transfer.
| ChatGPT and Codex plugins | Claude Code plugins | |
|---|---|---|
| Manifest | Root plugin.json (Agent Plugins 1.0.0), .codex-plugin/plugin.json fallback | .claude-plugin/plugin.json |
| Instructions | Skills (SKILL.md) | Skills, plus commands and agents |
| Tools | MCP servers in the same package | MCP servers in the plugin; connectors submitted separately |
| Install-time config | Not supported (userConfig is not run) | userConfig prompts |
| Hooks | Manual Codex desktop installs only, blocks public listing | Supported |
| Surfaces | Chat, Work and Codex from one package | Claude Code |
Credit where it is due on both sides. Anthropic introduced the SKILL.md format, which now underpins the skills in both systems, and Claude Code's plugin system exposes more local extension points: OpenAI's guide lists commands, agents, userConfig, output styles and LSP servers among the things that have no direct OpenAI equivalent and must be converted or dropped. OpenAI's design, meanwhile, ships one package across Chat, Work and Codex and adopts the vendor-neutral Agent Plugins layout. ChatGPT desktop even reads $REPO_ROOT/.claude-plugin/marketplace.json as a legacy-compatible marketplace, and Codex sets CLAUDE_PLUGIN_ROOT and CLAUDE_PLUGIN_DATA for hook compatibility.
The practical takeaway for anyone migrating a GPT: write skills in provider-neutral language (OpenAI's guide literally asks you to replace "Claude" with "the model" in skill text) and host tools as a remote Streamable HTTP MCP server. Then the same skill folder and the same server can ship to both hosts, with only the manifest differing. If your team also runs Claude Code, the Claude Code plugins for teams guide covers the marketplace side.
%% title: One codebase, two plugin hosts
flowchart LR
SK["skills/ - provider-neutral"] --> OA[ChatGPT and Codex plugin]
MCP[Remote MCP server] --> OA
SK --> CC[Claude Code plugin]
MCP --> CC
OA --- M1["plugin.json + mcp.json"]
CC --- M2[".claude-plugin/plugin.json"]FAQ#
When exactly do custom GPTs stop working?#
The standard retirement date is Dec 11, 2026, when custom GPTs and their GPT pages become inaccessible. Enterprise workspaces with a qualified, approved deferral retire on Feb 11, 2027. The date that applies is set by the workspace where the GPT was created, not where you use it, and OpenAI says the dates are subject to change.
Do my GPT Actions migrate automatically?#
No. Custom actions do not transfer through the migration workflow. Check whether an existing app covers the service, or rebuild the integration as an MCP server tool and add it to the plugin, then test it, because OpenAI says a rebuilt integration may not match every capability of the original.
Will my old GPT conversations disappear?#
No. OpenAI says existing conversations with custom GPTs remain accessible after retirement and you do not need to do anything to preserve them. The GPT and its page are what go away.
Can I migrate a GPT someone else built?#
No. Permission to use a GPT does not let you migrate it. The creator can migrate it, and in Enterprise a workspace admin can as well, once migration is available and plugins are enabled.
Does migrating make my plugin public?#
No. A migrated plugin starts private, is not auto-installed, and does not inherit the GPT's sharing settings. Sharing inside a workspace needs separate permissions, and a public listing requires a separate plugin submission and review.
Sources#
- ChatGPT release notes - Sep 11, 2026 retirement announcement; Jul 9, 2026 Plugin Directory change
- Custom GPT retirement and migration FAQ - dates, what transfers, permissions, Enterprise credits
- Plugins in ChatGPT and Codex - plugin components, Plugin Creator, Enterprise role permissions
- Package your plugin -
plugin.json,mcp.json, auth types,plugin_asdk_apptest flow, marketplaces, hooks - Build an MCP server -
registerTool, annotations,structuredContent, Inspector testing - Submit your Claude Code plugin to OpenAI - Claude vs OpenAI packaging differences
- GPT Actions introduction - how Actions used function calling against REST APIs
- MCP TypeScript SDK -
McpServerandStreamableHTTPServerTransport - Anthropic Engineering: Agent Skills - origin of the
SKILL.mdformat
Continue Reading#
- OpenAI Apps SDK: Building MCP UIs Inside ChatGPT - add an interactive view to the MCP server you just built
- Ship a Remote MCP Server: Give Your Coding Agent Cloud Tools in an Afternoon - get the public HTTPS endpoint that plugin submission requires
- What Are Claude Code Skills? A Complete Beginner Guide - the
SKILL.mdformat your GPT instructions just became
Get the next deep dive like this in your inbox
One email a week on OpenAI and the rest of the AI dev stack. Free.
Read next
Agent Plugins 1.0.0: One Package Format for Agent Skills and MCP Servers
Agent Plugins 1.0.0 is an open standard that packages Agent Skills and MCP servers into one plugin, with ChatGPT, Codex, Cursor and Copilot support at launch.
7 min readOpenAI Apps SDK: Building MCP UIs Inside ChatGPT
Apps SDK extends MCP with UI. Here is how to ship a real Apps SDK app from scratch: logic, interface, deploy, distribution, and the gotchas that cost me a weekend.
12 min readChatGPT Work and Codex Now Share One Desktop App: What Actually Changed
OpenAI is consolidating its desktop apps, not merging ChatGPT and Codex into one indistinguishable product. Here is how ChatGPT Work, Codex, and GPT-5.6 fit together.
8 min readNew here? Start with
Technical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.








