> ## Documentation Index
> Fetch the complete documentation index at: https://www.twicecommerce.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Design your attributes before you import

> The custom fields your stock, listings, customers and orders are described by — decided once, before an import creates them for you.

Part of step 3 of the [launch path](/docs/guides/launch/overview), [Set up your business](/docs/guides/launch/set-up-the-foundation). Attributes are the custom fields that describe what you sell: size, frame height, grade, cost centre, membership number. You define them once under **Settings → Attributes & Tags**, and from then on they are how you filter, group, report, and bind a listing to the stock that fulfils it.

This is the step most often skipped, and the one that is most expensive to retrofit — because two of the decisions on this page cannot be changed afterwards, and because the import will make them for you if you have not.

<Warning>
  **An attribute's type is fixed the moment it is created.** The **Type** field is disabled on an existing attribute, and the helper text says so: *Type cannot be changed after an attribute is created. Delete it and create a new one to use a different type.* Deleting removes the definition **and every value stored against it**, across every record.

  The resource is fixed too — an attribute belongs to inventory, catalog, customers or orders, and never moves between them.
</Warning>

<Warning>
  **If you do not design the set, the import designs it for you.** In the stock item import, every column you do not map to a built-in field becomes a **new attribute** on your account, and its format defaults to **Text**. Import first and you own a set of text fields named after your spreadsheet headers, each one permanently the wrong type.
</Warning>

## Attribute or tag

Both are things you add yourself under **Settings → Attributes & Tags**, and they are not interchangeable.

|                                   | Attribute                             | Tag                                 |
| --------------------------------- | ------------------------------------- | ----------------------------------- |
| What it is                        | A named field with a type and a value | A label, with nothing behind it     |
| Configured with                   | Type, options, group, key             | A value, and the area it belongs to |
| A listing's rules can match on it | **Yes**                               | No                                  |
| Filter and group a table by it    | Yes                                   | Yes                                 |
| Comes in on an import             | Yes, on the stock item import         | No — no import carries tags         |

Use a tag for a loose label a human applies and reads — *summer range*, *needs a photo*. Use an attribute for anything the system has to act on. A tag that turns out to need a rule behind it has to be re-entered as an attribute on every record carrying it.

## One resource each

Every attribute belongs to exactly one resource, and cannot be reused across them. Similar fields on two resources are two attributes.

| Resource      | Describes                                | Groups                                   |
| ------------- | ---------------------------------------- | ---------------------------------------- |
| **Inventory** | Stock items and the SKUs they roll up to | Yes                                      |
| **Catalog**   | Listings                                 | Yes                                      |
| **Customers** | Customer profiles                        | Yes                                      |
| **Orders**    | Individual orders                        | **No** — order attributes have no groups |

Inventory attributes carry one further choice, made where the attribute is filled in rather than where it is defined: a value set on the **SKU** is read by every stock item under it, and a value set on the **stock item** belongs to that unit alone. Brand on the SKU, serial number on the unit.

Order attributes are the ones to settle alongside your checkout, not your inventory — a cost centre or a PO number is usually [collected at checkout](/docs/guides/customers/collect-customer-data-at-checkout) rather than typed by staff.

## Pick the type, because the type is permanent

Eight types, as the attribute drawer lists them:

| Type             | Use it for                                                      | Rules and filters see                                                                                         |
| ---------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Text**         | Free prose, and identifiers constrained by an accepted format   | The values already in use                                                                                     |
| **Number**       | Anything measured or counted — weight, length, capacity         | A number, with `greater than` / `less than`                                                                   |
| **Yes / No**     | Flags — insured, refurbished, staff-only                        | Both values, always                                                                                           |
| **Date**         | Calendar dates — purchased on, warranty until                   | A date, with before / after                                                                                   |
| **Date & Time**  | Timestamps where the hour matters                               | As above, to the minute                                                                                       |
| **Select**       | One value from a fixed list you define                          | **Your full option list**, whether or not a record uses it yet                                                |
| **Multi-select** | Several values from a fixed list                                | As above                                                                                                      |
| **Formula**      | A value computed from other fields — `item_income - item_costs` | Nothing: a formula attribute is read-only, and is offered neither as a rule condition nor as an import column |

**The choice that matters is Select versus Text.** They look equivalent while you are typing the first few records, and they are not:

* A **Select** attribute offers your configured options in a listing's rule builder, so you can write a rule for a value before a single unit carries it — which is exactly what launch is.
* A **Text** attribute offers only the values already stored. Before the import there are none, so the rule cannot be written. After the import there are `Good`, `good`, `GOOD` and `Godo`, and each is a different value.

Anything with a small, known set of values — grade, size, colour, department — wants **Select**. Reserve **Text** for values that are genuinely unique per record, such as a serial number.

Options themselves are safe to grow: adding an option later is fine, and renaming an option's label does not touch the records using it, because what is stored is the option's key.

## Anything a listing must match on has to be an attribute

A listing's fulfilment rules select stock on exactly five things:

| A rule can match on                                     |
| ------------------------------------------------------- |
| **Attribute** — any attribute on the inventory resource |
| **Item Code**                                           |
| **Item Name**                                           |
| **SKU Code**                                            |
| **SKU Name**                                            |

A stock item also has a built-in **Condition** field. It is free text, it filters and groups the inventory table, and **it is not one of the five**. A grade recorded only there can be read by a person and never bind a listing to the stock it describes.

So if you resell, or run any pool where units differ in state, the grading scale is an attribute — **Select**, with the grades as its options — decided before intake starts. Keep the **Condition** field for the free-text detail beside it: *scuff on left fork*. [Take used stock in and grade it](/docs/guides/inventory/intake-and-grading) covers the scale itself; [control what stock a listing draws from](/docs/guides/catalog/listing-inventory-rules) covers writing the rule.

## Group them, and name the keys

Groups are presentation, not structure, and they are the cheap part of this page: an attribute's group and its order can be changed at any time.

* Attributes with no group appear under **Details**.
* Inventory carries one built-in group, **Sustainability**, for the fields TWICE Commerce manages there.
* Orders have no groups at all.

Two or three groups per resource is usually enough — a *Dimensions* group and a *Purchase* group beat fifteen fields in one list.

The **Attribute key** is the name your exports and API responses use. Leave it blank and it is derived from the name; type one and it is corrected as you type, to lowercase letters, digits, `-` and `_`. Set it deliberately for anything an integration will read.

One more switch on the drawer: **Save as global attribute**. A global attribute appears on every record of its resource, empty or not. A non-global one appears on a record only once that record has a value for it. Make the handful of fields your staff fill in every time global; leave the long tail off, or every stock item's detail view becomes a wall of blank fields.

## Then, and only then, import

Only the **stock item** import touches attributes. The listing, SKU and customer imports carry their built-in columns alone: a column that matches none of them is left out rather than turned into an attribute, so attribute values on those three are entered after the import, not during it.

In the stock item import (**Inventory → Stock items → Register Items → Import CSV**), at the **Match Columns** step:

| What you do with a column       | What happens                                                                                                                  |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Map it to a built-in field      | Filled into **Code**, **Item Name**, **SKU Code**, **SKU Name**, **Status**, **Quantity**, **Location** or **Available from** |
| Map it to an existing attribute | The value is parsed against that attribute's type, and a cell that does not parse is reported before anything is written      |
| Leave it unmapped               | A **new attribute** is created — you pick its **Attribute group** and **Attribute format** in the same step                   |

Existing attributes are matched to your headers by name or key automatically, exact spellings first and close spellings after, so a header called `Frame height` finds the attribute you already made. Formula attributes are not offered — they are computed, not imported.

<Note>
  **Do not pick Select or Multi-select for a new column in the import.** Both types are offered in the **Attribute format** list, and both fail: the import cannot supply the option list those types require, so the run stops on a bare *Something went wrong* with nothing written. Create select attributes under **Settings → Attributes & Tags** first, then map your column onto one.
</Note>

The mechanics of the import itself — the required columns, how a row's Quantity decides pooled versus individually-tracked stock — are in [import inventory from a CSV](/docs/guides/inventory/import-inventory-csv).

## Done when

* Every field your stock, listings, customers and orders need exists under **Settings → Attributes & Tags**, on the right resource.
* Every attribute with a known set of values is **Select** or **Multi-select**, with its options entered — not **Text**.
* The grading scale, if you take in used stock, is a Select attribute on the inventory resource, and a rule written against one of its grades reports matches in inventory.
* Each inventory attribute is filled in at the level its value belongs to: shared values on the SKU, unit-specific values on the stock item.
* The fields staff fill in every time are marked **Save as global attribute**; the rest are not.
* Attribute keys are set for anything an export or integration reads.
* Your import file's headers have been checked against the attribute list, and every column is either a built-in field, an existing attribute, or a column you intend to become a new **Text**, **Number**, **Yes / No** or **Date** attribute.
* Nothing has been imported yet.

## Related articles

<CardGroup cols={2} className="doc-rows-condensed">
  <Card title="Set up your business" href="/docs/guides/launch/set-up-the-foundation">
    The launch step this guide belongs to.
  </Card>

  <Card title="Attributes" href="/docs/concepts/admin/attributes">
    Every property an attribute definition carries, in full.
  </Card>

  <Card title="Attribute Groups" href="/docs/concepts/admin/attribute-groups">
    How grouping works across the admin.
  </Card>

  <Card title="Attributes & Tags settings" href="/docs/settings/attributes-tags">
    The settings page itself.
  </Card>

  <Card title="How to take used stock in and grade it" href="/docs/guides/inventory/intake-and-grading">
    The grading scale, and why it cannot live in Condition.
  </Card>

  <Card title="How to control what stock a listing draws from" href="/docs/guides/catalog/listing-inventory-rules">
    Writing the rules your attributes feed.
  </Card>

  <Card title="How to import inventory from a CSV" href="/docs/guides/inventory/import-inventory-csv">
    The import this guide comes before.
  </Card>

  <Card title="Bring in your data" href="/docs/guides/launch/bring-in-inventory-and-catalog">
    The next step, once the fields exist.
  </Card>
</CardGroup>
