> For the complete documentation index, see [llms.txt](https://docs.durohub.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.durohub.com/advanced-topics/search-query-syntax.md).

# Search Query Syntax

The Duro search bar supports a structured `key:value` query syntax that lets you build precise filters by typing. Queries are parsed into filter pills that you can further refine visually.

{% hint style="info" %}
This page covers the **manual search syntax** (Normal mode). For AI-powered natural language search, toggle "AI Mode On" in the search bar and type freely. For the programmatic API, see [Searching and Filtering](/advanced-topics/searching-and-filtering.md).
{% endhint %}

## How It Works

1. Type a query like `type:part status:design` in the search bar
2. Press **Enter**
3. Your query is parsed into filter pills on the components page
4. Results update immediately

Multiple filters separated by spaces combine with **AND** logic. You can switch to **Any** (OR) mode using the toggle in the filter pill bar.

***

## Quick Reference

| Key          | Aliases        | Description                              | Example                 |
| ------------ | -------------- | ---------------------------------------- | ----------------------- |
| `type`       |                | Component type                           | `type:part`             |
| `status`     |                | Status name                              | `status:design`         |
| `state`      |                | Released or modified                     | `state:released`        |
| `category`   |                | Category name                            | `category:capacitor`    |
| `label`      | `labels`       | Label / tag name                         | `labels:"Needs Review"` |
| `cpn`        |                | Part number (CPN)                        | `cpn:212-00001`         |
| `name`       |                | Component name                           | `name:"Mountain Bike"`  |
| `desc`       | `description`  | Description text                         | `desc:ceramic`          |
| `created`    | `createdAt`    | Creation date                            | `created:>2025-01-01`   |
| `modified`   | `updatedAt`    | Last modified date                       | `modified:>2025-01-01`  |
| `createdBy`  |                | Creator name                             | `createdBy:dustin`      |
| `modifiedBy` |                | Last modifier name                       | `modifiedBy:rachel`     |
| `rev`        | `revision`     | Revision value                           | `rev:>A`                |
| `pinned`     |                | Pinned status                            | `pinned:true`           |
| `bookmarked` |                | Bookmarked status                        | `bookmarked:true`       |
| `attr:`      |                | Attribute value                          | `attr:capacitance:>10`  |
| `mfg`        | `manufacturer` | Manufacturer on the component's sourcing | `mfg:vishay`            |
| `mpn`        |                | Manufacturer part number                 | `mpn:PC10K-240CT`       |
| `dist`       | `distributor`  | Distributor on the component's quotes    | `dist:digi-key`         |
| `vendor`     | `supplier`     | Manufacturer **or** distributor          | `vendor:acme`           |
| `dpn`        |                | Distributor part number                  | `dpn:DK-1234-ND`        |

Free text without a key prefix searches across name, CPN, and description simultaneously.

Text values support the `*` wildcard for pattern matching (e.g. `cpn:401-*`, `name:*widget*`, or the free-text `401-*`). See [Wildcards](#wildcards).

***

## Operators

| Syntax           | Meaning               | Example                          |
| ---------------- | --------------------- | -------------------------------- |
| `key:value`      | equals                | `status:design`                  |
| `key!:value`     | not equals            | `status!:design`                 |
| `key:val1,val2`  | any of (OR)           | `status:design,prototype`        |
| `key!:val1,val2` | none of               | `modifiedBy!:dustin,yuri`        |
| `key:>value`     | greater than / after  | `created:>2025-01-01`            |
| `key:<value`     | less than / before    | `rev:<C`                         |
| `key:>=value`    | greater than or equal | `attr:weight:>=100`              |
| `key:<=value`    | less than or equal    | `attr:capacitance:<=10`          |
| `key:val1..val2` | range (inclusive)     | `created:2025-01-01..2025-06-01` |

### Quoting

Use double quotes for values that contain spaces:

```
labels:"Needs Review"
name:"Mountain Bike Frame"
```

Commas and colons inside quotes are treated as literal characters:

```
labels:"A, B"        (one label named "A, B", not two labels)
name:"Part: Rev A"   (colon is part of the name)
```

***

## Wildcards

Use `*` as a wildcard to match **zero or more characters** at any position. Wildcards work in free-text searches and in the `name`, `cpn`, `desc`, and `label` keys, as well as the [sourcing keys](#sourcing-keys) (`mfg`, `mpn`, `dist`, `vendor`, `dpn`).

Component search and the CPN / EID autocompletes all use the same wildcard rules, so a pattern typed in the search bar behaves the same when typing a CPN or EID into a picker.

| Query           | Matches                                                                    |
| --------------- | -------------------------------------------------------------------------- |
| `401-*`         | `401-00001`, `401-00002`, `401-WIDGET` (starts with "401-")                |
| `*-00001`       | `ABC-00001`, `401-00001`, `XYZ-00001` (ends with "-00001")                 |
| `*401*`         | `ABC401XYZ`, `401-Widget`, `PREFIX-401-SUFFIX` (contains "401")            |
| `401-*01`       | starts with "401-" and ends with "01"                                      |
| `*401*00*`      | contains "401" then "00", in that order                                    |
| `*-00100`       | `PCBA-00100`, `PCB-00100`, `EBOM-00100` (same counter, different prefixes) |
| `cpn:401-*`     | components whose CPN starts with "401-"                                    |
| `name:*widget*` | components with "widget" anywhere in the name                              |
| `labels:*-Beta` | components with a label ending in "-Beta"                                  |
| `mpn:PC10K-*`   | components with a manufacturer part number starting with "PC10K-"          |

### Position

Wildcards can appear anywhere — at the start (prefix), end (suffix), in the middle (internal), or several at once:

```
*00001          (suffix — ends with "00001")
401-*           (prefix — starts with "401-")
401-*01         (internal — starts with "401-", ends with "01")
*401*00*        (multiple)
```

### Wildcards vs. exact match

For the text keys, a value **without** a `*` is matched literally:

* `name:widget` — matches the exact name "widget" (case-insensitive)
* `name:*widget*` — matches any name that **contains** "widget"
* `name:widget*` — matches any name that **starts with** "widget"

`desc:` and free text always search within the content, so `desc:ceramic` already behaves like a "contains" search.

A leading `*` is the way to search by the **end** of a value — useful when several components share a counter but differ by prefix (for example, an Altium PCBA, PCB, and EBOM that all end in `-00100`):

```
*-00100                  (free text)
cpn:*-00100              (CPN only)
```

### Escaping

To match a literal asterisk, escape it with a backslash:

```
Part\*Model     (matches the literal name "Part*Model")
```

`*` is the only wildcard character. `%`, `_`, and `\` are escaped before matching, so they are always treated as literal characters:

```
50\%             (matches the literal text "50%")
REV_A            (matches "REV_A", not "REVxA")
```

### Notes

* Consecutive wildcards collapse to one: `401-**01` is treated as `401-*01`.
* Quote values that contain spaces, keeping the wildcards inside the quotes: `name:"*mountain bike*"`.
* Leading wildcards (`*00001`) are supported. They scan more broadly, so they can be slower on large libraries.

***

## Keys in Detail

### type

Filter by component type. Values: `part`, `assembly`, `document`.

```
type:part
type:assembly
type:document
type:part,assembly       (parts OR assemblies)
```

### status

Filter by the component's custom status name. Uses the exact status names configured in your library.

```
status:design
status:production
status!:obsolete         (not in obsolete status)
status:design,prototype  (in design OR prototype)
```

### state

Filter by release state. Values: `released`, `modified`.

```
state:released
state:modified
```

### category

Filter by category name. Uses the exact category names configured in your library.

```
category:capacitor
category:resistor
category!:connector       (not connectors)
category:diode,transistor (diodes OR transistors)
```

### label / labels

Filter by label (tag) name. Uses the exact label names in your library. Supports `*` wildcards to match label names by pattern (see [Wildcards](#wildcards)).

```
label:urgent
labels:"Needs Review"
labels!:deprecated
labels:*-Beta            (labels ending in "-Beta")
```

### cpn

Filter by component part number (CPN). Matches the displayed CPN value. Supports `*` wildcards (see [Wildcards](#wildcards)).

```
cpn:212-00001
cpn:RES-001
cpn:401-*                (CPNs starting with "401-")
cpn:*-00001              (CPNs ending with "-00001")
```

### name

Filter by component name. Without a wildcard, the match is **exact** (case-insensitive). Use `*` wildcards for partial matching (see [Wildcards](#wildcards)).

```
name:LM7805              (exact name "LM7805")
name:"Mountain Bike"     (exact name "Mountain Bike" — quotes for spaces)
name:*widget*            (name contains "widget")
name:LM78*               (name starts with "LM78")
name:"*mountain bike*"   (contains "mountain bike"; wildcards stay inside quotes)
```

### desc / description

Search within component descriptions. Uses full-text search with word stemming (e.g., "capacitor" matches "capacitors"). Also supports `*` wildcards for literal pattern matching (see [Wildcards](#wildcards)).

```
desc:ceramic
description:"high voltage"
desc!:obsolete            (description does not contain "obsolete")
desc:*ceramic*            (description contains the literal string "ceramic")
```

### created / modified

Filter by creation or modification date. Supports comparison operators and ranges.

```
created:>2025-01-01           (created after Jan 1, 2025)
modified:<2025-06-01          (modified before Jun 1, 2025)
created:2025-01-01..2025-06-01  (created between Jan 1 and Jun 1)
modified:>2025-03-01          (modified after Mar 1, 2025)
```

### createdBy / modifiedBy

Filter by the user who created or last modified the component. Matches against user names in your library.

```
createdBy:dustin
modifiedBy:rachel
modifiedBy!:dustin,yuri   (not modified by dustin or yuri)
```

### rev / revision

Filter by revision value. Supports comparison operators for ordering.

```
rev:A
rev:>B           (revisions after B)
rev:<5           (revisions before 5)
rev:A..D         (revisions A through D)
```

### pinned / bookmarked

Filter by pin or bookmark status.

```
pinned:true
pinned:false
bookmarked:true
```

### attr: (Attributes)

Filter by user-defined attribute values. The `attr:` prefix is required to distinguish from built-in keys. Attribute names are matched case-insensitively against your library's configured attributes.

```
attr:capacitance:>10
attr:color:black
attr:weight:>=100
attr:material:steel
attr:cost:<50
```

{% hint style="info" %}
Attribute filters require the component to **have** the attribute. For example, `attr:color!:black` returns components that have a color attribute but where the value is not black. Components without a color attribute are excluded.
{% endhint %}

### Sourcing keys

The sourcing keys search a component's [sourcing](/core-concepts/sourcing.md) — its manufacturer parts and distributor quotes — not its own name or description. `mfg:bosch` finds a part sourced from Bosch even when the word "Bosch" appears nowhere on the component.

| Key      | Aliases        | Matches                                                                     |
| -------- | -------------- | --------------------------------------------------------------------------- |
| `mfg`    | `manufacturer` | The manufacturer of any of the component's parts                            |
| `mpn`    |                | The manufacturer part number of any of its parts                            |
| `dist`   | `distributor`  | The distributor on any of its quotes                                        |
| `vendor` | `supplier`     | A company in **either** role — one that makes the part or one that sells it |
| `dpn`    |                | The distributor part number on any of its quotes                            |

```
mfg:vishay
manufacturer:"Texas Instruments"
mpn:PC10K-240CT
mpn:PC10K-*              (every part number in the PC10K- family)
dist:digi-key
dist:digi-key,mouser     (bought from Digi-Key OR Mouser)
vendor:acme              (Acme makes it OR sells it)
supplier:acme            (same as vendor:acme)
dpn:DK-1234-ND
```

#### Company names match exactly, aliases included

`mfg`, `dist`, and `vendor` compare the whole name, case-insensitively, against the vendor's canonical name **and** its aliases. If McMaster-Carr has the alias "McMaster", then `mfg:mcmaster` finds it; if it doesn't, use a wildcard:

```
mfg:mcmaster*            (any manufacturer whose name starts with "mcmaster")
mfg:*mcmaster*           (any manufacturer whose name contains "mcmaster")
```

Prefer a trailing `*` over a surrounding one for short names. `mfg:*st*` also matches "Texas Instruments", because "st" is inside "Instruments".

#### Use `vendor` when you don't know the role

A company is often both: you buy a part from McMaster-Carr, and McMaster-Carr is also listed as its manufacturer. `mfg:` only checks the manufacturer, and `dist:` only checks the distributor. `vendor:` (or `supplier:`) checks both, so it's the right key for "anything we get from Acme".

#### Part numbers are literal

`mpn` and `dpn` match the full part number, case-insensitively. `_` and `%` in a part number are ordinary characters, so `mpn:WE_744_31` doesn't also match `WEX744X31`. Use `*` for families: `mpn:PC10K-*`.

#### Negation means "has none"

A component can have many parts and quotes. A negated sourcing key excludes the component if **any** of them matches, so `mfg!:mcmaster` drops a component that has one McMaster part and one Vishay part. It doesn't return the component just because one of its parts comes from somewhere else.

`vendor!:acme` is the broadest exclusion: it drops every component that Acme makes **or** sells.

```
dist!:digi-key           (components with no Digi-Key quote)
vendor!:acme,globex      (nothing made or sold by Acme or Globex)
```

{% hint style="info" %}
A component with no sourcing at all matches every negated sourcing key, because it has no part or quote that could match.
{% endhint %}

***

## Free Text Search

Any text without a `key:` prefix is treated as a free-text search across component name, CPN, and description.

```
mountain bike            (searches name, CPN, and description)
LM7805                   (finds by name or CPN match)
ceramic                  (finds in name or description)
```

Free text also supports `*` wildcards, applied across name, CPN, and description (see [Wildcards](#wildcards)):

```
401-*                    (name/CPN/description starting with "401-")
*00001                   (ending with "00001")
*401*                    (containing "401")
```

Free text can be combined with key:value filters:

```
ceramic type:part        (free text "ceramic" AND type is part)
```

***

## Combining Filters

Multiple space-separated filters combine with **AND** logic:

```
type:part status:design modifiedBy:dustin created:>2025-01-01
```

This finds **parts** in **design** status, modified by **dustin**, created **after Jan 1, 2025** — all conditions must match.

After parsing, you can switch to **Any** (OR) mode using the All/Any toggle in the filter pill bar.

***

## Common Scenarios

### Find all parts in a specific status

```
type:part status:design
```

### Find components not modified by a specific user

```
modifiedBy!:john
```

### Find released resistors and capacitors

```
state:released category:resistor,capacitor
```

### Find components modified in the last quarter

```
modified:>2025-01-01
```

### Find components by date range

```
created:2025-01-01..2025-03-31
```

### Find components by description keyword

```
desc:automotive
```

### Find all components in a CPN series (wildcard)

```
cpn:401-*
```

### Find every component ending in the same counter (leading wildcard)

```
cpn:*-00100
```

### Find components with a name pattern (wildcard)

```
name:*bracket*
```

### Find parts where an attribute exceeds a threshold

```
type:part attr:capacitance:>100
```

### Find components where color is not black

```
attr:color!:black
```

### Exclude multiple users from results

```
modifiedBy!:dustin,yuri
```

### Find components with a specific revision or higher

```
rev:>B type:part
```

### Find pinned favorites in production

```
pinned:true status:production
```

### Find everything you get from a supplier

```
vendor:mcmaster-carr
```

### Find released parts in a manufacturer part-number family

```
state:released mpn:PC10K-*
```

### Find components with no Digi-Key quote

```
dist!:digi-key
```

### Combine free text with structured filters

```
ceramic type:part status:design
```

***

## Error Handling

If a key is unrecognized, the search bar highlights the problematic segment and suggests a correction. For example:

* `weight:100` — suggests `attr:weight:100` (attribute prefix required)
* `foobar:xyz` — shows "Unknown key" error

Partially valid queries still work. If 3 of 4 segments parse successfully, the 3 valid filters are applied and the 1 error is shown.

***

## API Equivalent

The search bar syntax maps to the `buildFilterFromQuery` GraphQL query. API consumers can use this directly:

```graphql
query {
  component {
    buildFilterFromQuery(input: { query: "type:part status:design" }) {
      filterValues {
        field
        comparator
        value
        displayLabel
      }
      filterInput {
        and {
          status { id { eq } }
          category { type { eq } }
        }
      }
      success
      errors {
        segment
        message
        suggestion
      }
    }
  }
}
```

Or execute the search in one call:

```graphql
query {
  component {
    filterWithQuery(input: { query: "type:part status:design", limit: 50 }) {
      components {
        id
        name
      }
      totalCount
      pageInfo {
        hasNextPage
        endCursor
        resultsReturnedCount
      }
      interpretation
    }
  }
}
```

To paginate through results, pass the `endCursor` from the previous page as `after`:

```graphql
query {
  component {
    filterWithQuery(input: {
      query: "type:part status:design"
      limit: 50
      after: "eyJ2IjoiMjAyNi0wMy0yM1..."
    }) {
      components { id name }
      pageInfo { hasNextPage endCursor }
    }
  }
}
```

{% hint style="success" %}
The `filterWithQuery` API accepts the same syntax as the search bar, making it easy to build integrations that mirror the web app's search experience.
{% endhint %}

***

## Next Steps

* [Searching and Filtering API Reference](/advanced-topics/searching-and-filtering.md) — programmatic filtering with the Advanced Filter API and AI search
* [Components](/core-concepts/components.md) — component data model and CRUD operations
* [Authentication](/getting-started/authentication.md) — setting up API access


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.durohub.com/advanced-topics/search-query-syntax.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
