Skip to main content

Overview

The Customer Module manages customer data including profiles, addresses, and customer group memberships. It provides essential customer relationship management capabilities for your commerce platform. Key Features:
  • Customer profile management
  • Multiple address support
  • Customer groups for segmentation
  • Account and guest customer tracking
  • Searchable customer data
  • Custom metadata storage

When to Use

Use the Customer Module when you need to:
  • Create and manage customer profiles
  • Store customer contact information
  • Manage multiple shipping addresses per customer
  • Organize customers into groups
  • Track registered vs. guest customers
  • Store custom customer attributes
  • Search customers by name, email, or phone

Data Models

Customer

The core customer entity representing a person or business.
id
string
required
Unique customer identifier (prefix: cus_)
email
string
Customer email address (searchable)
first_name
string
Customer first name (searchable)
last_name
string
Customer last name (searchable)
company_name
string
Company name for B2B customers (searchable)
phone
string
Customer phone number (searchable)
has_account
boolean
Whether customer has a registered account (default: false)
created_by
string
ID of user who created the customer record
metadata
object
Additional custom data
addresses
CustomerAddress[]
Customer shipping/billing addresses
groups
CustomerGroup[]
Customer groups this customer belongs to

CustomerAddress

Represents a saved customer address.
id
string
required
Unique address identifier
customer_id
string
required
ID of the parent customer
address_name
string
Name for this address (e.g., “Home”, “Office”)
is_default_shipping
boolean
Whether this is the default shipping address
is_default_billing
boolean
Whether this is the default billing address
first_name
string
First name
last_name
string
Last name
phone
string
Phone number
company
string
Company name
address_1
string
Address line 1
address_2
string
Address line 2
city
string
City
country_code
string
Two-letter ISO country code
province
string
State or province
postal_code
string
Postal/ZIP code
metadata
object
Additional custom data

CustomerGroup

Groups customers for segmentation and targeting.
id
string
required
Unique customer group identifier
name
string
required
Customer group name
metadata
object
Additional custom data
customers
Customer[]
Customers in this group

CustomerGroupCustomer

Join entity for many-to-many customer-group relationship.
id
string
required
Unique relationship identifier
customer_id
string
required
ID of the customer
customer_group_id
string
required
ID of the customer group

Service Interface

The Customer Module service is available at @medusajs/medusa/customer.

Retrieve Customer

Retrieve a single customer with related data.
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { ICustomerModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"

export async function GET(
  req: MedusaRequest,
  res: MedusaResponse
) {
  const customerModuleService: ICustomerModuleService = req.scope.resolve(
    Modules.CUSTOMER
  )

  const customer = await customerModuleService.retrieveCustomer("cus_123", {
    relations: ["addresses", "groups"],
  })

  res.json({ customer })
}
customerId
string
required
The ID of the customer to retrieve
config
FindConfig
Configuration for the query
relations
string[]
Relations to load (e.g., ["addresses", "groups"])
select
string[]
Fields to select from the customer
customer
CustomerDTO
The retrieved customer

List Customers

List customers with filtering and search.
const [customers, count] = await customerModuleService.listAndCountCustomers(
  {
    has_account: true,
    groups: { id: ["cgroup_vip"] },
  },
  {
    relations: ["addresses"],
    take: 20,
    skip: 0,
  }
)
filters
FilterableCustomerProps
Filters to apply
id
string | string[]
Filter by customer IDs
email
string | string[]
Filter by email (supports partial match)
has_account
boolean
Filter by account status
first_name
string
Filter by first name (searchable)
last_name
string
Filter by last name (searchable)
phone
string
Filter by phone number (searchable)
groups
object
Filter by customer group
customers
CustomerDTO[]
Array of customers matching the filters
count
number
Total count of matching customers

Create Customers

Create one or more customer profiles.
const customer = await customerModuleService.createCustomers({
  email: "[email protected]",
  first_name: "John",
  last_name: "Doe",
  phone: "+1234567890",
  has_account: true,
  addresses: [
    {
      address_name: "Home",
      first_name: "John",
      last_name: "Doe",
      address_1: "123 Main St",
      city: "New York",
      country_code: "us",
      postal_code: "10001",
      is_default_shipping: true,
      is_default_billing: true,
    },
  ],
})
data
CreateCustomerDTO | CreateCustomerDTO[]
required
Customer data to create
email
string
Customer email address
first_name
string
Customer first name
last_name
string
Customer last name
company_name
string
Company name for B2B
phone
string
Phone number
has_account
boolean
Whether customer has a registered account
addresses
CreateCustomerAddressDTO[]
Initial addresses for the customer
metadata
object
Custom metadata
customer
CustomerDTO | CustomerDTO[]
The created customer(s)

Update Customers

Update customer information.
const customer = await customerModuleService.updateCustomers("cus_123", {
  first_name: "Jane",
  phone: "+0987654321",
})
idOrSelector
string | string[] | FilterableCustomerProps
required
Customer ID(s) or filter selector
data
CustomerUpdatableFields
required
Fields to update

Create Customer Addresses

Add addresses to a customer.
const address = await customerModuleService.createCustomerAddresses({
  customer_id: "cus_123",
  address_name: "Office",
  first_name: "John",
  last_name: "Doe",
  company: "Acme Corp",
  address_1: "456 Business Ave",
  city: "San Francisco",
  country_code: "us",
  postal_code: "94102",
  is_default_shipping: false,
  is_default_billing: false,
})
data
CreateCustomerAddressDTO | CreateCustomerAddressDTO[]
required
Address data
customer_id
string
required
ID of the customer
address_name
string
Name for this address
is_default_shipping
boolean
Set as default shipping address
is_default_billing
boolean
Set as default billing address
first_name
string
First name
last_name
string
Last name
address_1
string
Address line 1
city
string
City
country_code
string
Two-letter ISO country code
postal_code
string
Postal/ZIP code

Update Customer Addresses

Modify existing addresses.
const address = await customerModuleService.updateCustomerAddresses(
  "addr_123",
  {
    is_default_shipping: true,
    phone: "+1234567890",
  }
)

Delete Customer Addresses

Remove addresses from a customer.
await customerModuleService.deleteCustomerAddresses(["addr_123", "addr_456"])

Create Customer Groups

Create customer groups for segmentation.
const group = await customerModuleService.createCustomerGroups({
  name: "VIP Customers",
  metadata: {
    discount_percentage: 10,
  },
})
data
CreateCustomerGroupDTO | CreateCustomerGroupDTO[]
required
Customer group data
name
string
required
Customer group name
metadata
object
Custom metadata

Add Customers to Group

Assign customers to a customer group.
await customerModuleService.addCustomerToGroup([
  {
    customer_id: "cus_123",
    customer_group_id: "cgroup_vip",
  },
  {
    customer_id: "cus_456",
    customer_group_id: "cgroup_vip",
  },
])
data
GroupCustomerPair | GroupCustomerPair[]
required
Customer-group associations
customer_id
string
required
ID of the customer
customer_group_id
string
required
ID of the customer group

Remove Customers from Group

Remove customer group associations.
await customerModuleService.removeCustomerFromGroup([
  {
    customer_id: "cus_123",
    customer_group_id: "cgroup_vip",
  },
])

Integration Examples

With Cart Module

Associate carts with customers.
import { Modules } from "@medusajs/framework/utils"

const customerModule = container.resolve(Modules.CUSTOMER)
const cartModule = container.resolve(Modules.CART)

// Retrieve customer
const customer = await customerModule.retrieveCustomer("cus_123", {
  relations: ["addresses"],
})

// Create cart with customer data
const cart = await cartModule.createCarts({
  customer_id: customer.id,
  email: customer.email,
  currency_code: "usd",
  shipping_address: customer.addresses.find(a => a.is_default_shipping),
})

With Order Module

Link orders to customers.
import { Modules } from "@medusajs/framework/utils"

const orderModule = container.resolve(Modules.ORDER)

// List customer orders
const orders = await orderModule.listOrders({
  customer_id: "cus_123",
})

// Create order for customer
const order = await orderModule.createOrders({
  customer_id: customer.id,
  email: customer.email,
  // ... other order data
})

With Auth Module

Manage customer authentication.
import { Modules } from "@medusajs/framework/utils"

const authModule = container.resolve(Modules.AUTH)
const customerModule = container.resolve(Modules.CUSTOMER)

// Create customer with account
const customer = await customerModule.createCustomers({
  email: "[email protected]",
  first_name: "John",
  last_name: "Doe",
  has_account: true,
})

// Create auth identity
await authModule.create({
  entity_id: customer.id,
  provider: "emailpass",
  provider_metadata: {
    email: customer.email,
  },
})

With Pricing Module

Customer group-based pricing.
import { Modules } from "@medusajs/framework/utils"

const pricingModule = container.resolve(Modules.PRICING)

// Calculate prices with customer group context
const prices = await pricingModule.calculatePrices(
  { id: ["variant_123"] },
  {
    context: {
      customer_group_id: "cgroup_vip",
      currency_code: "usd",
    },
  }
)

Best Practices

  1. Email Uniqueness: Enforce unique emails for accounts by using the has_account flag. Guests can share emails, but registered customers must have unique email/has_account combinations.
  2. Address Management: Use is_default_shipping and is_default_billing to mark primary addresses for quick access.
  3. Customer Groups: Leverage customer groups for:
    • Price list targeting
    • Promotion eligibility
    • Custom business logic
    • Reporting and analytics
  4. Searchable Fields: Take advantage of searchable fields (email, first_name, last_name, company_name, phone) for customer lookup.
  5. Guest to Account Conversion: When converting a guest to a registered customer, update has_account to true and ensure email uniqueness.
  6. Metadata Usage: Store custom attributes in metadata for flexibility without schema changes.

Build docs developers (and LLMs) love