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

# Solr Indexer Stage

export const schema = {
  "type": "object",
  "title": "Solr Indexer",
  "description": "Sends pipeline documents to a Solr collection for indexing, optionally buffering them into batches for improved throughput. Configure schema enforcement, field listing, date formats, and update request parameters to control how documents are written to Solr. Place this stage at the end of an index pipeline after all field transformations are complete.",
  "properties": {
    "skip": {
      "type": "boolean",
      "title": "Skip This Stage",
      "description": "Controls whether this stage executes during pipeline processing at runtime. When set to `true`, the stage is completely bypassed and documents pass through unchanged to the next stage. Useful for A/B testing, gradual rollouts, or temporarily disabling a stage without removing it from the pipeline.",
      "default": false,
      "hints": ["advanced"]
    },
    "label": {
      "type": "string",
      "title": "Label",
      "description": "Human-readable identifier displayed in the Fusion Admin UI, monitoring dashboards, and log messages. Use descriptive labels like `Parse Product PDFs` to aid debugging and team collaboration. Labels appear in performance metrics and error reports, making it easier to identify which stage failed.",
      "hints": ["advanced"],
      "maxLength": 255
    },
    "condition": {
      "type": "string",
      "title": "Condition",
      "description": "JavaScript expression evaluated at runtime on each document to conditionally execute this stage. The expression must return `true` to execute or `false` to skip. Access document fields using `doc.getFieldValue('fieldName')` and request parameters via `request.getFirstParam('paramName')`. For example, `doc.getFieldValue('type') === 'premium'` executes this stage only for premium content.",
      "hints": ["code", "code/javascript", "advanced"]
    },
    "enforceSchema": {
      "type": "boolean",
      "title": "Map to Solr Schema",
      "default": true
    },
    "fieldsList": {
      "type": "boolean",
      "title": "Add a field listing all document fields",
      "description": "Controls whether a multi-valued field `_lw_fields_ss` listing all field names sent to Solr is added to the document. Use this field to audit which fields are indexed or for debugging field mapping issues. Disable in production if the extra field is not needed to reduce document size.",
      "default": true
    },
    "dateFormats": {
      "type": "array",
      "title": "Additional Date Formats",
      "hints": ["advanced"],
      "items": {
        "type": "string"
      }
    },
    "params": {
      "type": "array",
      "title": "Additional Update Request Parameters",
      "hints": ["advanced"],
      "items": {
        "type": "object",
        "required": ["key"],
        "properties": {
          "key": {
            "type": "string",
            "title": "Parameter Name"
          },
          "value": {
            "type": "string",
            "title": "Parameter Value"
          }
        }
      }
    },
    "bufferDocsForSolr": {
      "type": "boolean",
      "title": "Buffer Documents and Send Them to Solr in Batches",
      "default": true,
      "hints": ["advanced"]
    },
    "bufferSize": {
      "type": "integer",
      "title": "Buffer Size",
      "description": "Sets the maximum number of documents held in the buffer before flushing to Solr when document buffering is enabled. When empty, the search cluster's default buffer size is used. Increase this value to reduce the number of Solr update requests at the cost of higher memory usage.",
      "hints": ["advanced"]
    },
    "bufferFlushInterval": {
      "type": "integer",
      "title": "Buffer Flush Interval (milliseconds)",
      "description": "Sets the maximum time in milliseconds documents are held in the buffer before being flushed to Solr, regardless of whether the buffer is full. When empty, the search cluster's default flush interval is used. Lower values reduce indexing latency. Higher values improve throughput.",
      "hints": ["advanced"]
    },
    "allowBlacklistedRequestParameters": {
      "type": "boolean",
      "title": "Allow expensive request parameters",
      "description": "Controls whether `commit=true` and `optimize=true` Solr request parameters passed into the pipeline are forwarded to Solr. When `false`, these parameters are blocked to prevent accidental hard commits or expensive optimize operations triggered by upstream callers. Enable only when pipeline callers need direct commit control.",
      "default": false,
      "hints": ["advanced"]
    },
    "unmapped": {
      "type": "object",
      "title": "Unmapped Fields Mapping",
      "required": ["source"],
      "properties": {
        "source": {
          "type": "string",
          "title": "Source Field",
          "description": "Specifies the name of the pipeline document field to be processed by the unmapped fields mapping operation. This field's value is read and then moved, copied, or transformed according to the configured operation. The source field must exist on the document for the mapping to apply.",
          "hints": ["advanced"]
        },
        "target": {
          "type": "string",
          "title": "Target Field",
          "description": "Specifies the name of the Solr document field that receives the value from the source field during unmapped field mapping. For `copy` and `move` operations, the source value is written to this field. Leave empty for `delete` operations where no target field is needed.",
          "hints": ["advanced"]
        },
        "operation": {
          "type": "string",
          "title": "Operation",
          "description": "Specifies the transformation applied to the unmapped source field: `copy` duplicates the value to the target field, `move` transfers and removes the source, `set` writes a static value, `add` appends to the target, `delete` removes the source field, and `keep` preserves the field unchanged. Choose the operation that matches your field normalization intent.",
          "enum": ["copy", "move", "set", "add", "delete", "keep"],
          "default": "copy",
          "hints": ["advanced"]
        }
      },
      "hints": ["advanced"]
    }
  },
  "category": "Indexing",
  "categoryPriority": 5,
  "unsafe": false
};

export const SchemaParamFields = ({schema}) => {
  const sanitize = str => {
    if (typeof str !== "string") return str;
    return str.replace(/^"(.*)"$/s, "$1").replace(/\\/g, "").replace(/"/g, "'");
  };
  const renderMd = str => {
    const s = sanitize(str);
    const text = (/[.!?]\)*$/).test(s) ? s : `${s}.`;
    return text.split(/(\*\*[^*]+\*\*|_[^_]+_|`[^`]+`)/g).map((part, i) => {
      if (part.startsWith("**")) return <strong key={i}>{part.slice(2, -2)}</strong>;
      if (part.startsWith("_")) return <em key={i}>{part.slice(1, -1)}</em>;
      if (part.startsWith("`")) return <code key={i}>{part.slice(1, -1)}</code>;
      return part;
    });
  };
  const {description, properties = {}, required: requiredProps = []} = schema;
  const visibleProps = useMemo(() => Object.entries(properties).filter(([, prop]) => !prop.hints?.includes("hidden")), [properties]);
  const renderProp = ([name, prop]) => {
    const isRequired = requiredProps.includes(name);
    const hasDefault = prop.default !== undefined;
    const rawDefault = prop.default;
    const hints = prop.hints || [];
    const isComplexDefault = hasDefault && (typeof rawDefault === "object" || typeof rawDefault === "string" && (rawDefault.length > 20 || rawDefault.includes('"')));
    const postBadges = [];
    if (prop.title) {
      postBadges.push(<><span className="text-stone-400 dark:text-stone-500">API property: </span>{name}</>);
    }
    const constraints = [];
    if (prop.minimum !== undefined && prop.maximum !== undefined) {
      constraints.push(`Range: ${prop.minimum} – ${prop.maximum}`);
    } else if (prop.minimum !== undefined) {
      constraints.push(`Min: ${prop.minimum}`);
    } else if (prop.maximum !== undefined) {
      constraints.push(`Max: ${prop.maximum}`);
    }
    if (prop.minLength !== undefined && prop.maxLength !== undefined) {
      constraints.push(`Length: ${prop.minLength} – ${prop.maxLength}`);
    } else if (prop.minLength !== undefined) {
      constraints.push(`Min length: ${prop.minLength}`);
    } else if (prop.maxLength !== undefined) {
      constraints.push(`Max length: ${prop.maxLength}`);
    }
    const fieldProps = {
      key: name,
      body: prop.title || name,
      type: prop.type,
      ...postBadges.length > 0 && ({
        post: postBadges
      }),
      ...isRequired && ({
        required: true
      }),
      ...!isComplexDefault && hasDefault ? {
        default: sanitize(String(rawDefault))
      } : {}
    };
    const isObject = prop.type === "object" && prop.properties;
    const isArrayOfObjects = prop.type === "array" && prop.items?.type === "object" && prop.items.properties;
    return <ParamField {...fieldProps}>
        {prop.description && <p>{renderMd(prop.description)}</p>}

        {prop.enum && <p>
            Allowed values: 
            {prop.enum.map((v, i) => <>{i > 0 && ", "}<code key={i}>{String(v)}</code></>)}
          </p>}

        {constraints.length > 0 && <p className="text-stone-500 dark:text-stone-400 text-sm">
            {constraints.join(" · ")}
          </p>}

        {isComplexDefault && <div className="flex">
            <p>
              <strong>Default:</strong>
            </p>
            <pre className="!my-0">
              <code>
                {JSON.stringify(rawDefault, null, 2)}
              </code>
            </pre>
          </div>}

        {isArrayOfObjects && <Expandable title="item properties">
            <SchemaParamFields schema={{
      properties: prop.items.properties,
      required: prop.items.required
    }} />
          </Expandable>}

        {isObject && <Expandable title="properties">
            <SchemaParamFields schema={{
      properties: prop.properties,
      required: prop.required
    }} />
          </Expandable>}
      </ParamField>;
  };
  return <div>
      {description && <p>{renderMd(description)}</p>}

      {visibleProps.map(renderProp)}
    </div>;
};

export const LwTemplate = ({title = "Key questions to get you started", icon = "sparkles", cta = "Powered by Agent Studio", linkHref = "https://lucidworks.com/demo/?utm_source=docs&utm_medium=referral&utm_campaign=docs_cta_ai"}) => {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsLoaded(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);
  return <div className="lw-template-container">
      <Card title={title} icon={icon}>
        {isLoaded && <span dangerouslySetInnerHTML={{
    __html: `<lw-template id="a029c1a9-28be-427e-b0e1-5d918920246a"></lw-template
            >`
  }} />}
        <Link href={linkHref} className="agent-studio-link text-left text-gray-600 gap-2 dark:text-gray-400 text-sm font-medium flex flex-row items-center hover:text-primary dark:hover:text-primary-light group-hover:text-primary group-hover:dark:text-primary-light">Powered by Lucidworks Agent Studio</Link>
      </Card>
    </div>;
};

[localhost link]: http://localhost:3000/docs/5/fusion/reference/config-ref/pipeline-stages/index-stages/solr-indexer-stage

[mintlify link]: https://doc.lucidworks.com/docs/5/fusion/reference/config-ref/pipeline-stages/index-stages/solr-indexer-stage

[old doc.lw link]: https://doc.lucidworks.com/fusion/5.9/227

A Solr Indexer stage transforms a Fusion PipelineDocument into a Solr document and sends it to Solr for indexing into a collection.

A PipelineDocument object contains fields which take as their values either a string or list of strings. Solr fields have a rich variety of types. The Solr Indexer stage transforms PipelineDocument field values into Solr document fields. The Solr Indexer stage can be configured so that it will try to ensure that all document fields are valid Solr fields.

This feature is convenient, but offers very little control over how fields and field values are transformed, especially with respect to dates. A [Date Parsing Index stage](/docs/5/fusion/reference/config-ref/pipeline-stages/index-stages/date-parsing-index-stage) offers greater control over date values. In a similar vein, Lucidworks recommends that you only use safe characters (a-z, \_ ) in field names when using a Solr Indexer stage. Special characters will be automatically converted to an underscore.

<LwTemplate />

## Configuration

<Tip>
  When entering configuration values in the UI, use *unescaped* characters, such as `\t` for the tab character. When entering configuration values in the API, use *escaped* characters, such as `\\t` for the tab character.
</Tip>

<SchemaParamFields schema={schema} />
