Skip to main content
This guide walks you through creating a custom extension for EverShop from scratch.

Prerequisites

Before you begin, ensure you have:
  • An EverShop project set up and running
  • Node.js and npm installed
  • Basic knowledge of JavaScript/TypeScript
  • Familiarity with React (for UI components)
1
Create Extension Directory
2
Create a new directory for your extension in the extensions folder:
3
mkdir -p extensions/my-extension
cd extensions/my-extension
4
Initialize Package
5
Create a package.json file:
6
{
  "name": "my-evershop-extension",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "tsc": "tsc"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
7
Setup TypeScript
8
Create a tsconfig.json file for TypeScript support:
9
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ES2020",
    "moduleResolution": "node",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "jsx": "react",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
10
Create Directory Structure
11
Create the required directories:
12
mkdir -p src/api
mkdir -p src/pages/frontStore
mkdir -p src/pages/admin
mkdir -p src/subscribers
mkdir -p src/graphql/types
mkdir -p src/crons
mkdir -p dist
13
Configure Extension
14
Add your extension to config/default.json:
15
{
  "system": {
    "extensions": [
      {
        "name": "my-extension",
        "resolve": "extensions/my-extension",
        "enabled": true,
        "priority": 10
      }
    ]
  }
}
16
Configuration Options:
17
  • name: Unique identifier for your extension
  • resolve: Path to extension directory (relative to project root)
  • enabled: Set to true to enable the extension
  • priority: Lower numbers load first (default: 10)
  • 18
    Create Bootstrap File (Optional)
    19
    Create src/bootstrap.ts to register cron jobs or perform initialization:
    20
    import path from 'path';
    import { registerJob } from '@evershop/evershop/lib/cronjob';
    
    export default function () {
      registerJob({
        name: 'myCustomJob',
        schedule: '0 0 * * *', // Runs daily at midnight
        resolve: path.resolve(import.meta.dirname, 'crons', 'dailyJob.js'),
        enabled: true
      });
    }
    
    21
    Add Event Subscriber
    22
    Create src/subscribers/product_created/logProduct.ts to react to events:
    23
    import { EventSubscriber } from '@evershop/evershop/lib/event/subscriber';
    
    const logProduct: EventSubscriber<'product_created'> = async (data) => {
      console.log('New product created:', {
        id: data.product_id,
        name: data.name,
        sku: data.sku
      });
      
      // Add your custom logic here
      // - Send notification
      // - Update external system
      // - Trigger workflow
    };
    
    export default logProduct;
    
    24
    Create Custom Page Component
    25
    Create src/pages/frontStore/all/Banner.tsx to add a component to all pages:
    26
    import React from 'react';
    
    export default function Banner() {
      return (
        <div className="bg-blue-600 text-white py-3 px-4">
          <div className="container mx-auto text-center">
            <p className="font-medium">
              Welcome to our store! Free shipping on orders over $50.
            </p>
          </div>
        </div>
      );
    }
    
    export const layout = {
      areaId: 'body',
      sortOrder: 0
    };
    
    27
    Layout Configuration:
    28
  • areaId: Where to render the component (body, content, header, etc.)
  • sortOrder: Lower numbers render first
  • 29
    Create API Route
    30
    Create src/api/hello/route.json:
    31
    {
      "methods": ["GET"],
      "path": "/hello",
      "access": "public"
    }
    
    32
    Create src/api/hello/handler.ts:
    33
    import { EvershopRequest, EvershopResponse } from '@evershop/evershop';
    
    export default (request: EvershopRequest, response: EvershopResponse) => {
      response.json({
        message: 'Hello from my extension!',
        timestamp: new Date().toISOString()
      });
    };
    
    34
    Build Extension
    35
    Compile your TypeScript code:
    36
    npm run tsc
    
    37
    This generates compiled JavaScript in the dist/ directory.
    38
    Rebuild EverShop
    39
    Restart your development server or rebuild:
    40
    npm run build
    npm run start
    
    41
    In development mode, EverShop loads extensions from the src/ directory. In production, it uses the compiled dist/ directory.
    42
    Test Your Extension
    43
  • Check the banner: Visit your storefront homepage
  • Test the API: Visit http://localhost:3000/hello
  • Verify subscriber: Create a product and check console logs
  • Check cron job: Wait for scheduled time or check logs
  • Next Steps

    • Learn about Extension Structure for detailed folder organization
    • Explore Hooks and Events to react to system events
    • Check out the sample extension in your EverShop installation for more examples

    Troubleshooting

    Extension Not Loading

    Verify that:
    1. Extension is enabled in config/default.json
    2. The resolve path is correct
    3. You’ve rebuilt EverShop after configuration changes

    TypeScript Errors

    Ensure:
    1. Dependencies are installed: npm install
    2. TypeScript is installed: npm install -D typescript
    3. Your tsconfig.json is properly configured

    Component Not Appearing

    Check that:
    1. The layout export is present and correct
    2. The areaId exists on the target page
    3. The component file is in the correct directory
    4. The extension is rebuilt and EverShop is restarted

    Build docs developers (and LLMs) love