Back to Spree

Quickstart

docs/developer/customization/quickstart.mdx

5.4.27.6 KB
Original Source

Spree is a flexible platform allowing you to customize every part of it to suit your business needs. This guide presents customization options in order of recommendation - start from the top and only move down if simpler options don't meet your needs.

Quick Reference

What you want to doRecommended approach
Change store settings (currency, zones, languages)Store Settings
Tweak Spree behavior globallyConfiguration
React to model changes (sync, notifications)Events & Subscribers
Notify external servicesWebhooks
Swap core services (cart, checkout, etc.)Dependencies
Add admin menu itemsAdmin Navigation
Add sections to admin formsAdmin Partials
Add searchable/filterable fieldsRansack Configuration
Add associations/validations to modelsDecorators (last resort)
<AccordionGroup> <Accordion title="Store settings" defaultOpen> **Best for:** Changing currency, shipping zones, languages, and other business settings.
There's a lot of Store settings you can change in the admin panel without touching the code.

Go to **Admin > Settings**

</Accordion> <Accordion title="Configuration"> **Best for:** Tweaking Spree's behavior globally without modifying source code.
Global application configuration allows you to customize various aspects of Spree:

```ruby config/initializers/spree.rb
Spree.config do |config|
  config.allow_guest_checkout = false
  config.products_per_page = 20
end
```

Please see [Configuration](/developer/customization/configuration) section for more information.
</Accordion> <Accordion title="Events and Subscribers"> **Best for:** Reacting to model changes, syncing with external services, sending notifications, audit logging.
<Info>
  Events are the **recommended way** to add behavior when something happens in Spree, replacing the need for decorator callbacks.
</Info>

Spree's event system lets you subscribe to events like `order.completed`, `product.updated`, `payment.paid`, etc.:

```ruby app/subscribers/my_app/order_completed_subscriber.rb
module MyApp
  class OrderCompletedSubscriber < Spree::Subscriber
    subscribes_to 'order.completed'

    def handle(event)
      order = Spree::Order.find_by(id: event.payload['id'])
      return unless order

      # Sync to external service, send notification, etc.
      ExternalService.notify_order_placed(order)
    end
  end
end
```

**Key benefits:**
- Loose coupling - your code doesn't depend on Spree internals
- Async by default - keeps requests fast
- Easier testing and upgrades

Please see [Events](/developer/core-concepts/events) section for more information.
</Accordion> <Accordion title="Webhooks"> **Best for:** Notifying external services (ERPs, CRMs, fulfillment systems) when events occur.
Webhooks send HTTP POST requests to external URLs when Spree events happen:

- Order completed → Notify fulfillment system
- Product updated → Sync with PIM
- Customer created → Add to CRM

Configure webhooks in **Admin > Developers > Webhooks** or via the API.

Please see [Webhooks](/developer/core-concepts/webhooks) section for more information.
</Accordion> <Accordion title="Dependencies"> **Best for:** Swapping core services, serializers, and abilities with your own implementations.
Spree allows you to replace core classes without modifying them:

```ruby config/initializers/spree.rb
Spree::Dependencies.cart_add_item_service = "MyCartAddItemService"
Spree::Dependencies.cart_remove_item_service = "MyCartRemoveItemService"
```

This is cleaner than decorating services because you provide a complete replacement rather than patching behavior.

Please see [Dependencies](dependencies) section for more information.
</Accordion> <Accordion title="Admin Extensions"> **Best for:** Adding menu items, form sections, dashboard widgets, and other UI elements to the admin panel.
Spree provides declarative APIs for extending the admin without decorators or view overrides:

**Navigation API** - Add menu items:
```ruby config/initializers/spree.rb
Rails.application.config.after_initialize do
  Spree.admin.navigation.sidebar.add :brands,
    label: :brands,
    url: :admin_brands_path,
    icon: 'award',
    position: 35
end
```

**Partials API** - Add sections to forms:
```ruby config/initializers/spree.rb
Spree.admin.partials.product_form << 'spree/admin/products/erp_section'
```

Please see:
- [Admin Navigation](/developer/admin/navigation) - For adding menu items
- [Admin Partials](/developer/admin/extending-ui) - For extending UI
- [Admin Tables](/developer/admin/tables) - For customizing list views
</Accordion> <Accordion title="Search and Filtering"> **Best for:** Making custom fields searchable/sortable in the admin and API.
Instead of decorating models to add `ransackable_attributes`, use the Ransack configuration API:

```ruby config/initializers/spree.rb
Spree.ransack.add_attribute :product, :erp_id
Spree.ransack.add_association :product, :brand
```

Please see [Search & Filtering](/developer/core-concepts/search-filtering#extending-ransackable-configuration) section for more information.
</Accordion> <Accordion title="Authentication"> **Best for:** Using your own user model or authentication system.
Spree allows you to use your own authentication system instead of the default Devise-based one.

You can find more information in the [Authentication](authentication) section.
</Accordion> <Accordion title="Checkout flow"> **Best for:** Customizing checkout steps and flow.
With Spree you can change the checkout flow to fit your business needs - add steps, remove steps, or change the order.

Please see [Checkout flow customization section](checkout) for more information.
</Accordion> <Accordion title="Decorators"> **Best for:** Adding associations, validations, scopes, and methods to Spree models. Use as a last resort.
<Warning>
  Decorators should be used **only when no other option works**. They tightly couple your code to Spree internals and can break during upgrades.

  **Do NOT use decorators for:**
  - After-save callbacks → Use [Events](/developer/core-concepts/events) instead
  - External service sync → Use [Webhooks](/developer/core-concepts/webhooks) instead
  - Custom service logic → Use [Dependencies](dependencies) instead
  - Admin UI changes → Use [Admin Extensions](#admin-extensions) instead
</Warning>

Decorators are still appropriate for structural changes:

```ruby app/models/spree/product_decorator.rb
module Spree
  module ProductDecorator
    def self.prepended(base)
      base.belongs_to :brand, class_name: 'MyApp::Brand', optional: true
      base.validates :external_id, presence: true
      base.scope :featured, -> { where(featured: true) }
    end

    def full_title
      "#{brand&.name} #{name}"
    end
  end

  Product.prepend(ProductDecorator)
end
```

Please see [Decorators](decorators) section for more information.
</Accordion> </AccordionGroup>