> Documentation index: [Saleor](/llms.txt) · [This section](/api-usage/llms.txt)
> Source: https://docs.saleor.io/api-usage/search

# Search

Saleor provides full-text search capabilities across key entities in the system, allowing you to find records by matching terms against multiple fields simultaneously.

**Added in Saleor 3.23**

<a id="supported-modules"></a>

## Supported Modules

| Module | Searchable Fields |
| --- | --- |
| **Products** | Name, description, variant SKU, variant name, attribute values |
| **Orders** | Order number, user email, customer name, customer note, external reference, billing/shipping address, line items, payments, transactions, discounts, invoices, order notes |
| **Customers** | First name, last name, email (including domain), addresses |
| **Gift Cards** | Code (last 4 digits), full code, tags, used by / created by email and name |
| **Checkouts** | Token, email, user name, billing/shipping address, line items, payments, transactions |
| **Pages** | Title, slug, content, page type name and slug, attribute values |

**Field details**

The following sections describe exactly which sub-fields are indexed for shared concepts like addresses, line items, and payments.

<a id="address-fields"></a>

#### Address fields

Applies to: **Orders**, **Customers**, **Checkouts**

-   `firstName`
-   `lastName`
-   `streetAddress1`
-   `streetAddress2`
-   `companyName`
-   `city`
-   `cityArea`
-   `countryArea`
-   `countryName`
-   `countryCode`
-   `postalCode`
-   `phone`

<a id="line-item-fields"></a>

#### Line item fields

Applies to: **Orders**, **Checkouts**

**Orders:**

-   `productSku`
-   `productName`
-   `variantName`
-   `translatedProductName`
-   `translatedVariantName`

**Checkouts:**

-   `variant.sku`
-   `product.name`
-   `variant.name`

<a id="payment-fields"></a>

#### Payment fields

Applies to: **Orders**, **Checkouts**

-   `paymentId`
-   `pspReference`

<a id="transaction-fields"></a>

#### Transaction fields

Applies to: **Orders**, **Checkouts**

-   `transaction.token`
-   `transaction.pspReference`
-   `transaction.events.pspReferences`

<a id="order-specific-fields"></a>

#### Order-specific fields

In addition to the shared fields above, orders also index:

**Discounts:**

-   `discount.name`
-   `discount.translatedName`

**Invoices:**

-   `ID`

**Order notes:**

-   Messages from `NOTE_ADDED` and `NOTE_UPDATED` events

<a id="search-access-points"></a>

## Search Access Points

The enhanced search is available via two entry points:

-   **Root-level `search` argument** — e.g., `orders(search: "coffee")`
-   **`filter.search` field** — e.g., `orders(filter: { search: "coffee" })`

Both use the same underlying full-text search engine.

<a id="search-operators"></a>

## Search Operators

Every search term uses **prefix matching** by default — the query `coff` will match "coffee", "coffeehouse", etc. The only exception is when a term is wrapped in double quotes (`"…"`), which switches to **exact phrase matching** where the full phrase must appear as-is.

Multiple terms can be combined with the following operators:

| Operator | Syntax | Example | Description |
| --- | --- | --- | --- |
| Prefix matching | `term` | `coff` | Matches "coffee", "coffeehouse", etc. (default behavior) |
| AND (implicit) | `term1 term2` | `coffee shop` | Both terms must match; each term is prefix-matched |
| AND (explicit) | `term1 AND term2` | `coffee AND shop` | Same as implicit AND; both terms must match |
| OR | `term1 OR term2` | `coffee OR tea` | Either term matches (uppercase `OR` required); each term is prefix-matched |
| NOT | `-term` | `coffee -decaf` | Excludes results containing prefix matches for "decaf" |
| Exact phrase | `"phrase"` | `"green tea"` | Matches the exact phrase only — no prefix matching |
| Combining | mixed | `-"green tea" coffee` | Exclude an exact phrase and require a prefix-matched term |

<a id="search-behavior"></a>

## Search Behavior

<a id="case-sensitivity"></a>

### Case Sensitivity

Search is **case-insensitive**. Searching for `Coffee`, `coffee`, or `COFFEE` will return the same results.

<a id="accent-insensitive-search"></a>

### Accent-Insensitive Search

Search is **accent-insensitive**. Accented characters are treated the same as their unaccented equivalents, so you can find items regardless of whether their names contain special diacritical marks.

For example, searching for `Magnesium` will also return items named `Magnésium B6`.

This works in both directions — a query with accents will match unaccented content, and a query without accents will match accented content.

<a id="special-characters"></a>

### Special Characters

Certain special characters are automatically converted to spaces during search processing. This ensures search queries work reliably even when they contain punctuation or special symbols.

**Characters converted to spaces:** `( ) & | ! : < > ' *`

For example:

-   Searching for `22:20` is treated as two separate terms: `22` and `20`
-   Searching for `(coffee)` searches for: `coffee`

**Preserved characters:** Letters, numbers, underscore (`_`), hyphen (`-`), at sign (`@`), and period (`.`)

<a id="unclosed-quotes"></a>

### Unclosed Quotes

If you forget to close a quoted phrase, the search will treat everything after the opening quote as part of the phrase:

-   `"green tea` (missing closing quote) → searches for the phrase `"green tea"`

<a id="empty-or-invalid-queries"></a>

### Empty or Invalid Queries

-   **Empty search string** — Returns no results
-   **Only special characters** — If the query contains only special characters that get converted to spaces (e.g., `::::`), it returns no results
-   **Whitespace only** — Returns no results

<a id="examples"></a>

## Examples

<a id="simple-product-search"></a>

### Simple product search

Use the root-level `search` argument to find products:

**Query**

```graphql
query SearchProducts($search: String) {
  products(first: 10, search: $search) {
    edges {
      node {
        id
        name
      }
    }
  }
}
```

**Variables**

```json
{
  "search": "coffee"
}
```

**Result**

```json
{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "id": "UHJvZHVjdDox",
            "name": "Premium Coffee Beans"
          }
        },
        {
          "node": {
            "id": "UHJvZHVjdDoy",
            "name": "Coffee Maker"
          }
        },
        {
          "node": {
            "id": "UHJvZHVjdDoz",
            "name": "Coffeehouse Blend"
          }
        }
      ]
    }
  }
}
```

<a id="search-with-operators-on-checkouts"></a>

### Search with operators on checkouts

Use `filter.search` with operators to refine results:

**Query**

```graphql
query SearchCheckouts($filter: CheckoutFilterInput) {
  checkouts(first: 10, filter: $filter) {
    edges {
      node {
        id
        email
      }
    }
  }
}
```

**Variables**

```json
{
  "filter": {
    "search": "coffee -decaf"
  }
}
```

**Result**

```json
{
  "data": {
    "checkouts": {
      "edges": [
        {
          "node": {
            "id": "Q2hlY2tvdXQ6MQ==",
            "email": "customer@example.com"
          }
        },
        {
          "node": {
            "id": "Q2hlY2tvdXQ6Mg==",
            "email": "buyer@example.com"
          }
        }
      ]
    }
  }
}
```

<a id="explicit-relevance-sorting"></a>

### Explicit relevance sorting

Use the `RANK` sort field to explicitly sort by relevance:

**Query**

```graphql
query SearchCustomers($filter: CustomerFilterInput, $sortBy: UserSortingInput) {
  customers(
    first: 10
    filter: $filter
    sortBy: $sortBy
  ) {
    edges {
      node {
        id
        firstName
        lastName
        email
      }
    }
  }
}
```

**Variables**

```json
{
  "filter": {
    "search": "john"
  },
  "sortBy": {
    "field": "RANK",
    "direction": "DESC"
  }
}
```

**Result**

```json
{
  "data": {
    "customers": {
      "edges": [
        {
          "node": {
            "id": "VXNlcjox",
            "firstName": "John",
            "lastName": "Smith",
            "email": "john.smith@example.com"
          }
        },
        {
          "node": {
            "id": "VXNlcjoy",
            "firstName": "Johnny",
            "lastName": "Doe",
            "email": "johnny.doe@example.com"
          }
        },
        {
          "node": {
            "id": "VXNlcjoz",
            "firstName": "Johnson",
            "lastName": "Williams",
            "email": "johnson.w@example.com"
          }
        }
      ]
    }
  }
}
```

<a id="overriding-the-default-sort-order"></a>

### Overriding the default sort order

By default, search results are sorted by relevance. You can override this with any other supported `sortBy` field:

**Query**

```graphql
query SearchProductsSorted($search: String, $sortBy: ProductOrder) {
  products(
    first: 10
    search: $search
    sortBy: $sortBy
  ) {
    edges {
      node {
        id
        name
      }
    }
  }
}
```

**Variables**

```json
{
  "search": "coffee",
  "sortBy": {
    "field": "NAME",
    "direction": "ASC"
  }
}
```

**Result**

```json
{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "id": "UHJvZHVjdDoy",
            "name": "Coffee Maker"
          }
        },
        {
          "node": {
            "id": "UHJvZHVjdDoz",
            "name": "Coffeehouse Blend"
          }
        },
        {
          "node": {
            "id": "UHJvZHVjdDox",
            "name": "Premium Coffee Beans"
          }
        }
      ]
    }
  }
}
```

<a id="relevance-ranking"></a>

## Relevance Ranking

-   By default, results are sorted by relevance (`RANK`) when a search query is provided.
-   **Scoring algorithm:**
    -   Exact matches receive **2x weight** in relevance scoring
    -   Prefix matches receive **1x weight** in relevance scoring
    -   For example, searching for "coffee" will rank products with the exact word "coffee" higher than products containing "coffeehouse"
-   The default `RANK` sorting can be overridden using the `sortBy` parameter.
-   A `RANK` sort field is available for explicit relevance sorting.
-   Using `RANK` sort without a search query will result in an error.
