webiny-full-stack-architect

Full-stack extension skeleton and registration pattern. Use this skill when creating an extension that spans both API and Admin — the top-level component with Api.Extension and Admin.Extension entry points, shared domain layer, BuildParam declarations, and package structure. References webiny-api-architect and webiny-admin-architect for layer-specific details.

7,955 stars

Best use case

webiny-full-stack-architect is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Full-stack extension skeleton and registration pattern. Use this skill when creating an extension that spans both API and Admin — the top-level component with Api.Extension and Admin.Extension entry points, shared domain layer, BuildParam declarations, and package structure. References webiny-api-architect and webiny-admin-architect for layer-specific details.

Teams using webiny-full-stack-architect should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/full-stack-architect/SKILL.md --create-dirs "https://raw.githubusercontent.com/webiny/webiny-js/main/skills/user-skills/full-stack-architect/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/full-stack-architect/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How webiny-full-stack-architect Compares

Feature / Agentwebiny-full-stack-architectStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Full-stack extension skeleton and registration pattern. Use this skill when creating an extension that spans both API and Admin — the top-level component with Api.Extension and Admin.Extension entry points, shared domain layer, BuildParam declarations, and package structure. References webiny-api-architect and webiny-admin-architect for layer-specific details.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Full-Stack Extension Skeleton

## TL;DR

A full-stack extension bundles **API** and **Admin** into a single package with a shared domain layer. The top-level component registers both sides via `<Api.Extension>` and `<Admin.Extension>`, which point to separate entry-point files. Each side follows its own layered architecture pattern — see **webiny-api-architect** and **webiny-admin-architect** skills for details.

## RULE — Extension Entry Points

> **Admin extensions CANNOT be directly mounted in `webiny.config.tsx` or in any child component tree without going through `<Admin.Extension />`.**

The same rule applies to API extensions — they must go through `<Api.Extension />`.

These entry-point components are the **only** way to register code that runs inside the Admin app or the API runtime. They use the `src` prop to point to a file that will be loaded in the correct execution environment (browser for Admin, Lambda for API). Bypassing these entry points will fail at runtime because the Admin and API contexts (DI containers, routers, GraphQL registries, etc.) are not available outside their respective runtimes.

**YOU MUST include the full file path with the `.ts` or `.tsx` extension in every `src` prop.** For example, use `src={"/extensions/lead/src/index.ts"}`, NOT `src={"/extensions/lead"}`. Omitting the file extension will cause a build failure.

**YOU MUST use `export default` for the `createImplementation()` call** when the file is targeted directly by an Extension `src` prop. Using a named export (`export const Foo = SomeFactory.createImplementation(...)`) will cause a build failure. Named exports are only valid inside files registered via `createFeature`.

```tsx
// CORRECT — always use entry-point components
<Api.Extension src={import.meta.dirname + "/api/Extension.js"} />
<Admin.Extension src={import.meta.dirname + "/admin/Extension.js"} />

// WRONG — never mount admin/api code directly
<MyAdminComponent />     // Will not have access to Admin DI container
<MyApiFeature />         // Will not have access to API DI container
```

## Package Structure

```
my-extension/
├── src/
│   ├── index.ts                  # Single public export
│   ├── MyExtension.tsx           # Top-level component (registers Api + Admin)
│   ├── shared/                   # Shared between API and Admin
│   │   ├── constants.ts          # Model IDs, permission names, etc.
│   │   └── types.ts              # Shared types
│   ├── api/                      # API-side code → see webiny-api-architect skill
│   │   ├── Extension.ts
│   │   ├── domain/
│   │   ├── features/
│   │   └── graphql/
│   └── admin/                    # Admin-side code → see webiny-admin-architect skill
│       ├── Extension.tsx
│       ├── features/
│       └── presentation/
```

## Top-Level Component

The top-level component is the single entry point that consumers use. It registers both the API and Admin extensions:

```tsx
// src/MyExtension.tsx
import React from "react";
import { Api, Admin } from "webiny/extensions";

export const MyExtension = () => {
  return (
    <>
      {/* API extensions — runs in Lambda */}
      <Api.Extension src={import.meta.dirname + "/api/Extension.js"} />

      {/* Admin extensions — runs in browser */}
      <Admin.Extension src={import.meta.dirname + "/admin/Extension.js"} />
    </>
  );
};
```

Conditional rendering can wrap the entry points (e.g., feature flags, config parameters):

```tsx
<Infra.Env.Is name={"prod"}>
  <Api.Extension src={import.meta.dirname + "/api/Extension.js"} />
  <Admin.Extension src={import.meta.dirname + "/admin/Extension.js"} />
</Infra.Env.Is>
```

## Shared Domain Layer

The `shared/` directory contains types and value objects used by both API and Admin:

```ts
// src/shared/constants.ts
export const MY_MODEL_ID = "myModel";

// src/shared/MyEntity.ts
export interface MyEntityValues {
  name: string;
  status: "active" | "inactive";
}

export interface MyEntityDto {
  id: string;
  values: MyEntityValues;
}

export class MyEntity {
  private constructor(private dto: MyEntityDto) {}

  static from(dto: MyEntityDto) {
    return new MyEntity(dto);
  }

  get id() {
    return this.dto.id;
  }

  get values() {
    return this.dto.values;
  }
}
```

## Build Parameters

Build parameters pass configuration from `webiny.config.tsx` (build time) into both the API runtime and the Admin app. **A deployed API must NEVER use `process.env` to read configuration.**

**`BuildParam` declarations MUST live inside the extension's top-level component, NOT in `webiny.config.tsx`.** Required parameters are exposed as React props on the extension component.

### Declaring BuildParams

```tsx
// src/MyExtension.tsx — declares build params as React props
interface MyExtensionProps {
  apiEndpoint: string;
  dashboardUrl: string;
}

export const MyExtension = ({ apiEndpoint, dashboardUrl }: MyExtensionProps) => {
  return (
    <>
      <Api.BuildParam paramName="MY_API_ENDPOINT" value={apiEndpoint} />
      <Admin.BuildParam paramName="DASHBOARD_URL" value={dashboardUrl} />

      <Api.Extension src={import.meta.dirname + "/api/Extension.js"} />
      <Admin.Extension src={import.meta.dirname + "/admin/Extension.js"} />
    </>
  );
};
```

### Consuming in `webiny.config.tsx`

```tsx
// webiny.config.tsx — the ONLY place where process.env is read
<MyExtension
  apiEndpoint={process.env.MY_API_ENDPOINT || ""}
  dashboardUrl={process.env.DASHBOARD_URL || ""}
/>
```

### Reading BuildParams

- **API side:** Inject `BuildParams` via DI — see **webiny-api-architect** skill
- **Admin side:** Use `useBuildParams()` hook — see **webiny-admin-architect** skill

## Checklist

1. Create top-level component that uses `<Api.Extension>` and `<Admin.Extension>` — never mount admin/api code directly
2. Put shared domain models and constants in `shared/`
3. Declare `<Api.BuildParam>` / `<Admin.BuildParam>` in the top-level component, not in `webiny.config.tsx`
4. API entry point uses `createFeature` with `register(container)` — see **webiny-api-architect**
5. Admin entry point is a React component with `<RegisterFeature>` — see **webiny-admin-architect**
6. Use `.js` extensions in all import paths (ESM modules)

## Quick Reference

```
Entry point:            <Api.Extension src={...} /> + <Admin.Extension src={...} />
Shared code:            shared/ directory for domain models, constants, types
API architecture:       → see webiny-api-architect skill
Admin architecture:     → see webiny-admin-architect skill
DI pattern:             → see webiny-dependency-injection skill
BuildParam declare:     <Api.BuildParam paramName="KEY" value={prop} />
                        <Admin.BuildParam paramName="KEY" value={prop} />
BuildParam read (API):  buildParams.get<T>("KEY") via DI (→ webiny-api-architect)
BuildParam read (Admin): useBuildParams().get<T>("KEY") (→ webiny-admin-architect)
Import extensions:      Always use .js extensions in import paths (ESM)
```

## Related Skills

- **webiny-api-architect** — API-side architecture (features, abstractions, container registration)
- **webiny-admin-architect** — Admin-side architecture (headless + presentation features)
- **webiny-project-structure** — Extension registration and `webiny.config.tsx`
- **webiny-dependency-injection** — The `createImplementation` DI pattern and injectable services

Related Skills

webiny-v5-to-v6-migration

7955
from webiny/webiny-js

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.

webiny-api-permissions

7955
from webiny/webiny-js

Schema-based permission system for API features. Use this skill when implementing authorization in use cases, defining permission schemas with createPermissionSchema, creating injectable permissions via createPermissionsAbstraction/createPermissionsFeature, checking read/write/delete/publish permissions, handling own-record scoping, or testing permission scenarios. Covers the full pattern from schema definition to use case integration to test matrices.

webiny-admin-permissions

7955
from webiny/webiny-js

Admin-side permission UI registration and DI-backed permission checking. Use this skill when adding permission controls to the admin UI — schema-based auto-generated forms, injectable permissions via createPermissionsAbstraction/ createPermissionsFeature, typed hooks (createUsePermissions), the HasPermission component (createHasPermission), and the Security.Permissions component props. Covers both simple apps and complex multi-entity permission schemas.

webiny-sdk

7955
from webiny/webiny-js

Using @webiny/sdk to read and write CMS data from external applications. Use this skill when the developer is building a Next.js, Vue, Node.js, or any external app that needs to fetch or write content to Webiny, set up the SDK, use the Result pattern, list/get/create/update/publish entries, filter and sort queries, use TypeScript generics for type safety, work with the File Manager, or create API keys programmatically. Covers read vs preview mode, the `values` wrapper requirement, correct method names, and the `fields` required parameter.

webiny-project-structure

7955
from webiny/webiny-js

Webiny project layout, webiny.config.tsx anatomy, and extension registration. Use this skill when the developer asks about folder structure, where custom code goes, how to register extensions, what webiny.config.tsx does, or how the project is organized. Also use when they need to understand the relationship between extensions/, webiny.config.tsx, and the different extension types (Api, Admin, Infra, CLI).

webiny-local-development

7955
from webiny/webiny-js

Deploying, developing locally, managing environments, and debugging Webiny projects. Use this skill when the developer asks about deployment commands (deploy, destroy, info), local development with watch mode (API or Admin), the Local Lambda Development system, environment management (long-lived vs short-lived, production vs dev modes), build parameters, state files, debugging API/Admin/Infrastructure errors, or the redeploy-after-watch requirement.

webiny-infrastructure-extensions

7955
from webiny/webiny-js

Modifying AWS infrastructure using Pulumi handlers and declarative Infra components. Use this skill when the developer wants to customize AWS infrastructure, add Pulumi handlers, configure OpenSearch, VPC, resource tags, regions, custom domains, blue-green deployments, environment-conditional config, or manage production vs development infrastructure modes. Covers CorePulumi.Interface, all <Infra.*> declarative components, and <Infra.Env.Is>.

webiny-infra-catalog

7955
from webiny/webiny-js

Infrastructure — 33 abstractions. Infrastructure extensions.

webiny-extensions-catalog

7955
from webiny/webiny-js

extensions — 5 abstractions.

webiny-cli-command-catalog

7955
from webiny/webiny-js

cli/command — 1 abstractions.

webiny-cli-catalog

7955
from webiny/webiny-js

cli — 2 abstractions.

webiny-api-tenant-manager-catalog

7955
from webiny/webiny-js

API — Tenant Manager — 2 abstractions. Tenant management event handlers and use cases.