{
  "id": "indexing",
  "title": "Create an index",
  "url": "https://redis.io/docs/latest/develop/get-started/search-tutorial/indexing/",
  "summary": "Create a search index over your JSON documents with FT.CREATE, choose the right field types, and understand how Redis indexes arrays.",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-08-03T12:11:45-07:00",
  "page_type": "content",
  "content_hash": "98249ae577e705a126a487befd826a00c9a133b8e813fc979213c8f7401e98b0",
  "sections": [
    {
      "id": "what-an-index-does",
      "title": "What an index does",
      "role": "content",
      "text": "When you create an index, you give Redis three things:\n\n1. **What to index** &mdash; which keys belong to the index, selected by a key prefix (here, `product:`).\n2. **The data type** &mdash; whether those keys hold hashes (`ON HASH`) or JSON documents (`ON JSON`).\n3. **The schema** &mdash; which fields to index, the path to each one, and what type each field is.\n\nOnce the index exists, Redis keeps it up to date automatically. Any `product:` document you add or change after creating the index is indexed immediately, and the documents you loaded earlier are indexed right away."
    },
    {
      "id": "field-types",
      "title": "Field types",
      "role": "content",
      "text": "Redis Search has a few core field types. Choosing the right one for each field determines how you can query it:\n\n| Field type | Use it for | Example query |\n| --- | --- | --- |\n| `TEXT` | Human language you want to search by words and partial matches. | find products whose description contains *wireless* |\n| `TAG` | Exact-value labels and categories you filter on as a whole. | find products where category is exactly *Audio* |\n| `NUMERIC` | Numbers you filter by range or sort by. | find products priced between 0 and 100 |\n| `VECTOR` | Embeddings for similarity search (covered in the [last step](https://redis.io/docs/latest/develop/get-started/search-tutorial/vector-search)). | find products similar in meaning to a query |\n\nFor the catalog, a good mapping is: `name` and `description` are `TEXT` (you want word search), `brand` and `category` are `TAG` (exact labels), and `price`, `rating`, `review_count`, `stock`, and `release_year` are `NUMERIC`. The `features` field is a list of exact labels, so it is also a `TAG`."
    },
    {
      "id": "create-the-index",
      "title": "Create the index",
      "role": "content",
      "text": "Use [FT.CREATE](https://redis.io/docs/latest/commands/ft.create) to define the index. Because the data is JSON, each field is identified by a [JSONPath](https://redis.io/docs/latest/develop/data-types/json/path) expression, and `AS` gives it a short alias to use in queries:\n\nFoundational: Create an index over JSON documents with FT.CREATE, mapping JSONPaths to TEXT, TAG, and NUMERIC fields\n\n**Difficulty:** Beginner\n\n**Commands:** FT.CREATE\n\n**Complexity:**\n- FT.CREATE: O(K)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nA few things to notice:\n\n- **`PREFIX 1 product:`** means \"index every key that starts with `product:`\". The `1` is the number of prefixes that follow.\n- **`AS name`, `AS price`, ...** define the alias you use in queries (`@name`, `@price`). Without an alias, you would have to write the full JSONPath in every query.\n- **`SORTABLE`** on a field lets you sort results by it efficiently. Add it to fields you expect to sort by, such as `price` and `rating`.\n- **`$.features[*]`** ends in `[*]`, which matters for arrays. More on that next.\n\nYou only create an index once. If you make a mistake, remove it with [FT.DROPINDEX](https://redis.io/docs/latest/commands/ft.dropindex) (this deletes the index, not your documents) and create it again."
    },
    {
      "id": "indexing-arrays-the-you-should-not-forget",
      "title": "Indexing arrays: the `[*]` you should not forget",
      "role": "content",
      "text": "The `features` field is a JSON array like `[\"wireless\", \"bluetooth\", \"waterproof\"]`. To index each element as its own tag, the JSONPath ends in `[*]`:\n\n[code example]\n\nThis is the single most common point of confusion when indexing JSON, so it is worth understanding:\n\n- **With `$.features[*]`**, Redis indexes `wireless`, `bluetooth`, and `waterproof` as three separate tags. A query for `@features:{waterproof}` matches the document.\n- **With `$.features`** (no `[*]`) on a JSON array, the behavior is not what you want for filtering element-by-element.\n\n\nThis behavior differs between hashes and JSON, which trips up many newcomers. In a **hash**, a `TAG` field splits on commas by default, so `\"wireless,bluetooth\"` becomes two tags automatically. In **JSON**, there is no automatic splitting: index array elements with `[*]`, or if you store a comma-separated string, add `SEPARATOR \",\"` to the field definition. For the full explanation, see [Index JSON arrays as TAG](https://redis.io/docs/latest/develop/ai/search-and-query/indexing#index-json-arrays-as-tag)."
    },
    {
      "id": "check-the-index",
      "title": "Check the index",
      "role": "content",
      "text": "After creating the index, you can confirm it picked up your documents. [FT.INFO](https://redis.io/docs/latest/commands/ft.info) reports details about an index, including how many documents it contains:\n\nFoundational: Inspect an index with FT.INFO to confirm it exists and see how many documents it contains\n\n**Difficulty:** Beginner\n\n**Commands:** FT.INFO\n\n**Complexity:**\n- FT.INFO: O(1)\n\n**Available in:** Redis CLI, Python\n\n##### Redis CLI\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nLook for `num_docs` in the output; it should be `12`, one for each product you loaded.\n\n\nIn the [Redis Insight Search workspace](https://redis.io/docs/latest/develop/tools/insight/search-workspace), your new `idx:catalog` index appears in the list of indexes. Selecting it shows the schema you just defined &mdash; the fields, their types, and their aliases &mdash; without having to read the raw `FT.INFO` output."
    },
    {
      "id": "next-steps",
      "title": "Next steps",
      "role": "content",
      "text": "Your data is indexed. Continue to [searching and filtering](https://redis.io/docs/latest/develop/get-started/search-tutorial/search) to start asking questions of it."
    }
  ],
  "examples": [
    {
      "id": "create-the-index-ex0",
      "language": "plaintext",
      "code": "> FT.CREATE idx:catalog ON JSON PREFIX 1 product: SCHEMA $.name AS name TEXT $.brand AS brand TAG SORTABLE $.category AS category TAG $.description AS description TEXT $.price AS price NUMERIC SORTABLE $.rating AS rating NUMERIC SORTABLE $.review_count AS review_count NUMERIC $.stock AS stock NUMERIC $.release_year AS release_year NUMERIC SORTABLE $.features[*] AS features TAG\nOK",
      "section_id": "create-the-index"
    },
    {
      "id": "create-the-index-ex1",
      "language": "python",
      "code": "schema = (\n    TextField(\"$.name\", as_name=\"name\"),\n    TagField(\"$.brand\", as_name=\"brand\", sortable=True),\n    TagField(\"$.category\", as_name=\"category\"),\n    TextField(\"$.description\", as_name=\"description\"),\n    NumericField(\"$.price\", as_name=\"price\", sortable=True),\n    NumericField(\"$.rating\", as_name=\"rating\", sortable=True),\n    NumericField(\"$.review_count\", as_name=\"review_count\"),\n    NumericField(\"$.stock\", as_name=\"stock\"),\n    NumericField(\"$.release_year\", as_name=\"release_year\", sortable=True),\n    TagField(\"$.features[*]\", as_name=\"features\"),\n)\nindex = r.ft(\"idx:catalog\")\nindex.create_index(\n    schema,\n    definition=IndexDefinition(prefix=[\"product:\"], index_type=IndexType.JSON),\n)",
      "section_id": "create-the-index"
    },
    {
      "id": "indexing-arrays-the-you-should-not-forget-ex0",
      "language": "plaintext",
      "code": "$.features[*] AS features TAG",
      "section_id": "indexing-arrays-the-you-should-not-forget"
    },
    {
      "id": "check-the-index-ex0",
      "language": "plaintext",
      "code": "> FT.INFO idx:catalog",
      "section_id": "check-the-index"
    },
    {
      "id": "check-the-index-ex1",
      "language": "python",
      "code": "info = r.ft(\"idx:catalog\").info()\nprint(\"Documents indexed:\", info[\"num_docs\"])  # >>> Documents indexed: 12",
      "section_id": "check-the-index"
    }
  ]
}
