> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Antony-Figueroa/my-evershop-app/llms.txt
> Use this file to discover all available pages before exploring further.

# Extensions

> Understand the EverShop extension system and how to build modular features

# Extensions

Extensions are the core building blocks of EverShop's modular architecture. They encapsulate features, business logic, and functionality in isolated, reusable packages that can be enabled or disabled independently.

## What are Extensions?

Extensions in EverShop allow you to:

* Add new API endpoints
* Create custom page components
* React to system events with subscribers
* Schedule background jobs with cron tasks
* Extend GraphQL schema with new types and resolvers
* Organize business logic separately from the core application

<Note>
  Extensions focus on **business logic and functionality**, while themes focus on visual presentation. This separation allows you to switch themes without losing functionality.
</Note>

## Directory Structure

Each extension lives in the `extensions/` directory with the following structure:

```plaintext theme={null}
extensions/[extension-name]/
├── src/
│   ├── api/              # REST API endpoints
│   ├── pages/            # Page components (React/TSX)
│   ├── subscribers/      # Event subscribers
│   ├── crons/            # Scheduled jobs
│   ├── graphql/          # GraphQL types and resolvers
│   └── bootstrap.ts      # Extension initialization
├── dist/                 # Compiled files (auto-generated)
├── package.json
└── tsconfig.json
```

## Registering Extensions

Extensions must be registered in `config/default.json` to be loaded:

```json config/default.json theme={null}
{
  "system": {
    "extensions": [
      {
        "name": "offlinePayments",
        "resolve": "extensions/offlinePayments",
        "enabled": true
      },
      {
        "name": "productCatalog",
        "resolve": "extensions/productCatalog",
        "enabled": true
      }
    ]
  }
}
```

<Tip>
  Set `"enabled": false` to disable an extension without removing it from your project.
</Tip>

## Creating an Extension

<Steps>
  ### Create the directory structure

  Create a new directory under `extensions/` with your extension name:

  ```bash theme={null}
  mkdir -p extensions/myExtension/src
  ```

  ### Add package.json

  Create a `package.json` file:

  ```json extensions/myExtension/package.json theme={null}
  {
    "name": "myExtension",
    "version": "1.0.0",
    "main": "index.js",
    "type": "module",
    "scripts": {
      "tsc": "tsc"
    }
  }
  ```

  ### Configure TypeScript

  Add a `tsconfig.json`:

  ```json extensions/myExtension/tsconfig.json theme={null}
  {
    "extends": "../../tsconfig.json",
    "compilerOptions": {
      "outDir": "./dist",
      "rootDir": "./src"
    },
    "include": ["src/**/*"]
  }
  ```

  ### Register the extension

  Add it to `config/default.json`:

  ```json theme={null}
  {
    "system": {
      "extensions": [
        {
          "name": "myExtension",
          "resolve": "extensions/myExtension",
          "enabled": true
        }
      ]
    }
  }
  ```
</Steps>

## Extension Components

### API Endpoints

Create REST API endpoints in `src/api/[endpoint]/`:

```typescript extensions/sample/src/api/createFoo/[bodyParser]createFoo.ts theme={null}
import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

export default (request: EvershopRequest, response: EvershopResponse, next) => {
  const { name, description } = request.body;

  if (!name || !description) {
    return response
      .status(400)
      .json({ error: 'Name and description are required' });
  }

  const newFoo = {
    id: Date.now(),
    name,
    description
  };

  console.log('Creating new foo:', newFoo);

  response.status(201).json({
    success: true,
    data: { foo: newFoo }
  });
};
```

With a corresponding `route.json`:

```json extensions/sample/src/api/createFoo/route.json theme={null}
{
  "methods": ["POST"],
  "path": "/foos",
  "access": "private"
}
```

<Note>
  The filename `[bodyParser]createFoo.ts` indicates that `bodyParser` middleware runs before `createFoo`. See [Routing](/concepts/routing) for details.
</Note>

### Page Components

Add React components in `src/pages/[area]/[page]/`:

```tsx extensions/sample/src/pages/frontStore/homepage/FooList.tsx theme={null}
import React from 'react';

type FooListProps = {
  foos?: {
    id: number;
    name: string;
    description: string;
  }[];
};

export default function FooList({ foos }: FooListProps) {
  return (
    <div className="foo-list container mx-auto px-4 py-8">
      <h2 className="font-bold text-center mb-8">Foo List</h2>
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        {foos?.map((foo) => (
          <div key={foo.id} className="bg-white rounded-lg shadow-md p-6">
            <h3 className="font-semibold mb-3">{foo.name}</h3>
            <p className="text-gray-600">{foo.description}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

export const layout = {
  areaId: 'content',
  sortOrder: 30
};

export const query = `
  query Query {
    foos {
      id
      name
      description
    }
  }
`;
```

### Event Subscribers

React to system events in `src/subscribers/[event]/`:

```javascript extensions/sample/src/subscribers/product_created/consoleLog.js theme={null}
export default function consoleLog(data) {
  console.log('Product Created:', data);
}
```

<Tip>
  Subscriber functions are automatically called when the corresponding event is emitted. The directory name (`product_created`) determines which event to subscribe to.
</Tip>

### Cron Jobs

Schedule background tasks in `src/crons/`:

```typescript extensions/sample/src/crons/everyMinute.ts theme={null}
export default function EveryMinute() {
  console.log('This cron job runs every minute');
}
```

Register the job in `bootstrap.ts`:

```typescript extensions/sample/src/bootstrap.ts theme={null}
import path from 'path';
import { registerJob } from '@evershop/evershop/lib/cronjob';

export default function () {
  registerJob({
    name: 'sampleJob',
    schedule: '*/1 * * * *', // Runs every minute
    resolve: path.resolve(import.meta.dirname, 'crons', 'everyMinute.js'),
    enabled: true
  });
}
```

### GraphQL Extensions

Extend the GraphQL schema in `src/graphql/types/[TypeName]/`:

```graphql extensions/sample/src/graphql/types/Foo/Foo.graphql theme={null}
type Foo {
  id: ID!
  name: String!
  description: String
}

type Query {
  foo(id: ID!): Foo
  foos: [Foo!]!
}
```

With corresponding resolvers:

```javascript extensions/sample/src/graphql/types/Foo/Foo.resolvers.js theme={null}
const fooList = [
  { id: 1, name: 'Foo', description: 'This is a Foo object' },
  { id: 2, name: 'Bar', description: 'This is a Bar object' },
  { id: 3, name: 'Baz', description: 'This is a Baz object' }
];

export default {
  Query: {
    foo: (root, { id }) => {
      return fooList.find((foo) => foo.id === id);
    },
    foos: () => {
      return fooList;
    }
  },
  Foo: {
    id: (foo) => foo.id,
    name: (foo) => foo.name,
    description: (foo) => foo.description
  }
};
```

## Real-World Examples

### offlinePayments Extension

Provides payment methods like Cash on Delivery and Bank Transfer:

```tsx extensions/offlinePayments/src/pages/frontStore/checkout/cod/CashOnDelivery.tsx theme={null}
import React from 'react';
import { useCheckout } from '@evershop/evershop';

export default function CashOnDeliveryMethod({ setting }) {
  const checkout = useCheckout();
  const { paymentMethods, setPaymentMethods } = checkout;
  const selectedPaymentMethod = paymentMethods?.find(pm => pm.code === 'cod');

  return (
    <div className="bg-[#F8FAF9] border border-[#E8F5E9] rounded-lg p-4 mb-4">
      {/* Payment method selection UI */}
    </div>
  );
}

export const layout = {
  areaId: 'checkoutPaymentMethod',
  sortOrder: 10
};
```

### productCatalog Extension

Extends the Product type with supplement-specific fields:

```graphql extensions/productCatalog/src/graphql/types/ProductExtension/ProductExtension.graphql theme={null}
type Supplement {
  ingredients: String
  benefits: [String]
  presentation: String
  dosage: String
  warnings: String
  storage: String
}

type ProductExtension {
  supplement: Supplement
}

extend type Product {
  extension: ProductExtension
}
```

## Best Practices

<Accordion title="Use TypeScript for type safety">
  Always use `.ts` and `.tsx` files for new code. Define proper interfaces for your props and data structures.
</Accordion>

<Accordion title="Follow naming conventions">
  * Extension names: camelCase (e.g., `offlinePayments`, `productCatalog`)
  * API endpoints: descriptive names (e.g., `createOrder`, `updateProduct`)
  * Components: PascalCase (e.g., `ProductReviews`, `CashOnDelivery`)
</Accordion>

<Accordion title="Keep extensions focused">
  Each extension should have a single, well-defined purpose. If you're adding multiple unrelated features, consider splitting them into separate extensions.
</Accordion>

<Accordion title="Never modify .evershop/ or node_modules/">
  All custom code should live in extensions. Never edit files in `.evershop/` or `node_modules/` as they will be overwritten.
</Accordion>

## Next Steps

* Learn about [Themes](/concepts/themes) for customizing the visual presentation
* Understand [Routing](/concepts/routing) to configure API endpoints and pages
* Explore the [GraphQL API](/concepts/graphql) for data fetching
