grill-me
Interview the user relentlessly about a plan or design until reaching shared understanding,…
Migration patterns for converting v5 Webiny code to v6 architecture. Use this skill when migrating existing v5 plugins to v6 features, converting context plugins to DI services, adapting v5 event subscriptions to v6 EventHandlers, or understanding how v5 patterns translate to
$ npx -y skills add webiny/webiny-js --skill v5-to-v6-migration --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/v5-to-v6-migrationContext preview
The summary Claude sees to decide when to auto-load this skill.
Migration patterns for converting v5 Webiny code to v6 architecture. Use this skill when migrating existing v5 plugins to v6 features, converting context plugins to DI services, adapting v5 event subscriptions to v6 EventHandlers, or understanding how v5 patterns translate to
name: webiny-v5-to-v6-migration description: > Migration patterns for converting v5 Webiny code to v6 architecture. Use this skill when migrating existing v5 plugins to v6 features, converting context plugins to DI services, adapting v5 event subscriptions to v6 EventHandlers, or understanding how v5 patterns translate to v6. Targeted at AI agents performing migrations.
v6 replaces v5's plugin-based architecture with **feature-based DI**. The key shifts:
| v5 Concept | v6 Equivalent | | -------------------------------- | ------------------------------------------------------ | | `ContextPlugin` | `createAbstraction` + `createImplementation` (Service) | | Plugin array | `createFeature` + `container.register()` | | `context.myService` | DI injection via constructor | | `onEntryAfterCreate.subscribe()` | `EventHandler` feature | | `new GraphQLSchemaPlugin()` | `GraphQLSchemaFactory.createImplementation()` |
---
new ContextPlugin(async context => {
context.lingotekService = {
translate: async (docId, locale) => {
/* ... */
},
getStatus: async docId => {
/* ... */
},
deleteProject: async projectId => {
/* ... */
}
};
});// features/lingotekService/abstractions.ts
import { createAbstraction } from "webiny/api";
export interface ILingotekService {
translate(docId: string, locale: string): Promise<Result<void, Error>>;
getStatus(docId: string): Promise<Result<TranslationStatus, Error>>;
deleteProject(projectId: string): Promise<Result<void, Error>>;
}
export const LingotekService = createAbstraction<ILingotekService>("MyExt/LingotekService");
export namespace LingotekService {
export type Interface = ILingotekService;
}
// features/lingotekService/LingotekService.ts
class LingotekServiceImpl implements LingotekService.Interface {
constructor(private buildParams: BuildParams.Interface) {}
async translate(docId: string, locale: string) {
/* ... */
}
async getStatus(docId: string) {
/* ... */
}
async deleteProject(projectId: string) {
/* ... */
}
}
export default LingotekService.createImplementation({
implementation: LingotekServiceImpl,
dependencies: [BuildParams]
});
// features/lingotekService/feature.ts
export const LingotekServiceFeature = createFeature({
name: "LingotekService",
register(container) {
container.register(LingotekServiceImpl).inSingletonScope();
}
});**Key difference:** v5 attaches to context object. v6 uses DI — consumers declare the service as a constructor dependency.
---
context.cms.onEntryAfterCreate.subscribe(async params => {
if (params.model.modelId !== "myModel") return;
await doSomething(params.entry);
});// features/syncOnCreate/EntryAfterCreateHandler.ts
import { EntryAfterCreateEventHandler } from "webiny/api/cms/entry";
import { LingotekService } from "../lingotekService/abstractions.js";
import { MY_MODEL_ID } from "~/shared/constants.js";
class SyncOnCreateHandler implements EntryAfterCreateEventHandler.Interface {
constructor(private lingotekService: LingotekService.Interface) {}
async handle(event: EntryAfterCreateEventHandler.Event) {
const { entry, model } = event.payload;
if (model.modelId !== MY_MODEL_ID) return;
await this.lingotekService.translate(entry.entryId, "en");
}
}
export default EntryAfterCreateEventHandler.createImplementation({
implementation: SyncOnCreateHandler,
dependencies: [LingotekService]
});
// features/syncOnCreate/feature.ts
export const SyncOnCreateFeature = createFeature({
name: "SyncOnCreate",
register(container) {
container.register(SyncOnCreateHandler);
}
});**Key differences:**
---
export default () => [
new GraphQLSchemaPlugin({ ... }),
new ContextPlugin(async ctx => { ... }),
myModelPlugin,
eventSubscriptionPlugin
];// api/Extension.ts
import { createFeature } from "webiny/api";
export const Extension = createFeature({
name: "MyExtension",
register(container) {
container.register(MyModel);
container.register(MyGraphQLSchema);
SyncOnCreateFeature.register(container);
LingotekServiceFeature.register(container);
}
});---
When a v5 service was initialized with async data (loading settings, fetching config), v6 uses the **ServiceProvider** pattern — a provider abstraction with `async getService()` that lazily creates and caches the service.
See the **ServiceProvider Pattern** section in **webiny-api-architect** for the full pattern with abstractions, implementation, and consumer examples.
---
[
{
name: "content.i18n",
locales: ["en-US"]
},
{
name: "cms.endpoint.read"
},
{
name: "cms.endpoint.manage"
},
{
name: "cms.endpoint.preview"
},
{
name: "cms.contentModelGroup",
groups: {
"en-US": [LT_TRANSLATION_MODEL_GROUP_ID]
},
rwd: "rw",
own: false,
pw: ""
},
{
name: "cms.contentModel",
models: {
"en-US": [
LT_TRANSLATION_DOCUMENT_MODEL_ID,
LT_CONFIG_MODEL_ID,
LT_TRANSLATION_PROJECT_MODEL_ID
]
},
rwd: "rwd",
own:Open-source content platform. Self-hosted on AWS serverless. Built as a TypeScript framework you extend with code, not a closed product you configure through a UI. Runs on Lambda, DynamoDB, S3, and CloudFront inside your own AWS account. Scales automatically.
Repo: webiny/webiny-js
Interview the user relentlessly about a plan or design until reaching shared understanding,…
Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices, saved…
Webiny-only. Run all checks required before packages are ready for publish: deps, build,…
Use when running tests. Shows how to run tests for a single package, including OpenSearch…
Generate, refresh, and maintain Webiny MCP server skills from source documentation and…
Create a PRD through user interview, codebase exploration, and module design, then submit as…