Schema & fields

This section documents the current Solr line (10.0; 9.10.x the maintained 9.x branch), written and verified against the Apache Solr Reference Guide. No specific patch version is pinned. Some capabilities (the Solr Operator on Kubernetes, the package-manager ecosystem, Learning To Rank model training, and expert plugin development) are linked, not documented in depth.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Every collection has exactly one schema: the list of fields (or field-name patterns) it accepts, the type each one is stored as, and which field is the document’s identity. Solr can hold that schema as a hand-edited schema.xml, or — the default and recommended path — as a managed schema you change through the Schema API instead of editing a file. This page covers that distinction, the API itself, schemaless mode and the Schema Designer that build on top of it, uniqueKey, the three schema element kinds (field, dynamicField, copyField), the flags a field declares, and how to stop an open-ended schema from growing without bound. Field types covers the fieldType every field here points at.

schema.xml vs. the managed schema

Classic Solr configsets shipped a hand-edited schema.xml: a plain file under conf/, versioned with the rest of the configset, changed by editing XML and reloading the core or collection. It still works, but every field, dynamic field, copy field, and field type in it has to be edited by hand and kept consistent across every node and replica by whatever deploys the configset.

The managed schema (managed-schema.xml, the default since Solr 5) is functionally the same document, but Solr treats it as generated state: it is stored in ZooKeeper (SolrCloud) or the core’s conf/ directory (user-managed mode), and the supported way to change it is the Schema API below, not a text editor. Hand-editing a managed schema is possible but discouraged — the API validates each change against the fields already in use and keeps every node in a SolrCloud collection in sync, which a manually copied file does not. Whether a configset uses the classic or the managed form is set once, per configset, by the managed-schema update handler config; new configsets created with bin/solr create are managed by default. See Schema Elements for the full XML structure shared by both forms.

The Schema API

The Schema API reads and writes a managed schema over HTTP as JSON, at /solr/<collection>/schema. Reads are GET requests against sub-paths; writes are a single POST whose body names one or more commands — add-field, delete-field, replace-field, add-dynamic-field, add-copy-field, add-field-type, and their delete-/replace- counterparts. Several commands can be batched into one POST, and each is applied and, in SolrCloud, propagated to every replica before the call returns.

# Add a new explicit field.
curl -X POST -H 'Content-Type: application/json' \
  "http://localhost:8983/solr/books/schema" \
  -d '{
        "add-field": {
          "name": "rating_f",
          "type": "pfloat",
          "indexed": true,
          "stored": true,
          "docValues": true
        }
      }'

# Batch a dynamic field and a copy field in one call.
curl -X POST -H 'Content-Type: application/json' \
  "http://localhost:8983/solr/books/schema" \
  -d '{
        "add-dynamic-field": { "name": "*_txt", "type": "text_general", "indexed": true, "stored": false },
        "add-copy-field":    { "source": "*_txt", "dest": "text" }
      }'

# Read the schema back -- the whole thing, or one section at a time.
curl "http://localhost:8983/solr/books/schema?wt=json"
curl "http://localhost:8983/solr/books/schema/fields?wt=json"
curl "http://localhost:8983/solr/books/schema/uniquekey?wt=json"
# https://solr.apache.org/guide/solr/latest/indexing-guide/schema-api.html

Field types (text_general, pint, pfloat, and the rest) are declared and changed the same way, with add-field-type / replace-field-type / delete-field-type — see Field types for what goes inside one. A replace-field or replace-field-type on a field already holding data is restricted to changes Lucene can apply without a reindex (for example widening stored); anything that changes how existing values were already analyzed or encoded needs a full reindex into the corrected field, the same irreversibility Elasticsearch mappings have — see Mapping & field types. Full command and response reference: Schema API.

Schemaless mode

Schemaless mode is not a separate schema format — it is three ordinary features of a managed schema wired together: an update request processor chain that runs on every add, in which a field-guessing processor inspects each unmapped field’s JSON value, infers a type (string, plong, pdouble, boolean, date), and issues the equivalent of an add-field Schema API call before the document is indexed. bin/solr start -e schemaless (or bin/solr create -c <name> with no configset, which defaults to the _default configset in schemaless mode) turns it on out of the box.

# No "genre_s" field declared yet -- schemaless mode adds it from the first value it sees.
curl "http://localhost:8983/solr/books/update?commit=true" \
  -H 'Content-Type: application/json' \
  -d '[{"id": "5", "title": "The Dispossessed", "genre_s": "science fiction"}]'

curl "http://localhost:8983/solr/books/schema/fields/genre_s?wt=json"
# https://solr.apache.org/guide/solr/latest/indexing-guide/schemaless-mode.html

It is well suited to prototyping and to the tutorial round-trip on Getting started, but the same trade-off Elasticsearch’s dynamic mapping makes applies here: the first document Solr sees for a given key decides that field’s type for the life of the collection, and an unbounded key space guessed this way is exactly what leads to the field explosion covered below. Most production schemas disable field guessing (remove or edit the add-unknown-fields-to-the-schema processor in solrconfig.xml) once the real field set is known, and declare fields — or the dynamicField patterns below — explicitly instead. See Schemaless Mode for the processor chain in full.

The Schema Designer

The Schema Designer, in the Admin UI under Schema Designer, is an interactive front end for building a new managed schema from sample documents without writing Schema API calls by hand: paste or upload sample JSON/CSV/XML, it guesses fields and types the same way schemaless mode does, and lets you edit each field’s type and flags, preview the analysis chain, and run test queries — all against a disposable temporary collection — before publishing the result as a real configset. It is a design-time tool for a schema that does not exist yet; once a published schema has indexed data, the same reindex restrictions as any other schema change apply. See Schema Designer.

uniqueKey

Every schema declares one field, almost always named id, as the uniqueKey: the field Solr uses to detect whether an incoming document is a new insert or an update-by-replacement of an existing one, and the field /update deletes and atomic/partial updates (Partial updates & concurrency) address by. It must be a single-valued, indexed, stored field, typically string or one of the numeric types, and it cannot be changed once documents exist without reindexing the collection.

<!-- inside schema.xml / managed-schema.xml -->
<uniqueKey>id</uniqueKey>

See Schema Elements for the uniqueKey element and how it interacts with overwrite on /update.

field, dynamicField, and copyField

The schema declares fields three ways. The XML below is what a managed schema looks like under the hood — illustrative of the model even though the Schema API, not a text editor, is the supported way to write it:

<!-- An explicit field: exact name, always present with this shape. -->
<field name="id"    type="string"      indexed="true" stored="true" required="true"/>
<field name="title" type="text_general" indexed="true" stored="true"/>
<field name="text"  type="text_general" indexed="true" stored="false" multiValued="true"/>

<!-- A dynamic field: a name *pattern*, matched against any field Solr has not seen an
     explicit declaration for. Exactly one wildcard, at the start or the end of the name. -->
<dynamicField name="*_i"  type="pint"        indexed="true" stored="true"/>
<dynamicField name="*_s"  type="string"      indexed="true" stored="true" docValues="true"/>
<dynamicField name="*_ss" type="string"      indexed="true" stored="true" docValues="true" multiValued="true"/>
<dynamicField name="*_dt" type="pdate"       indexed="true" stored="true"/>

<!-- A copy field: duplicates a source value into a destination field at index time,
     before analysis, so the same text can be analyzed two different ways. -->
<copyField source="title" dest="text"/>
<copyField source="*_txt" dest="text" maxChars="30000"/>
  • field is an exact, explicitly named field — what id, title, and text are above. It is the most predictable option: no pattern matching, no guessing.

  • dynamicField matches by name pattern rather than an exact name — year_i, rating_f, and genre_ss above in Core concepts & architecture all resolved through a i/*_f/*_ss-style pattern, not an explicit field declaration. It is the idiomatic way to accept a bounded family of similarly-typed fields (price, *_dt) without declaring each one, and Solr always prefers a longer, more specific match over a shorter one. See Dynamic Fields.

  • copyField copies a value into a second field before analysis runs, so the two fields can be analyzed completely differently — the classic use is a catch-all text field, analyzed for broad full-text search, fed from several typed source fields the application still queries individually. Copies cannot be chained (A → B → C does not propagate to C), and maxChars caps how much of a long value is copied. See Copy Fields.

curl -X POST -H 'Content-Type: application/json' \
  "http://localhost:8983/solr/books/schema" \
  -d '{ "add-copy-field": { "source": "title", "dest": "text" } }'
// SolrJ: the same add-field call as above, through the Schema API's Java client wrapper.
try (SolrClient client = new Http2SolrClient.Builder("http://localhost:8983/solr").build()) {
    SchemaRequest.AddField addField = new SchemaRequest.AddField(Map.of(
            "name", "rating_f",
            "type", "pfloat",
            "stored", true,
            "docValues", true));
    addField.process(client, "books");
}

Field flags

Both field and dynamicField accept the same set of boolean flags, either declared directly or inherited from the referenced `fieldType’s own defaults (an explicit flag on the field always wins).

Flag Effect

indexed

The field is written into the inverted index and can appear in q / fq. Turn it off for a field you only ever retrieve, never search or filter on.

stored

The original value is kept and returned in the response.docs[] of a search hit. Off saves disk for a field you never need back verbatim.

docValues

Also builds the columnar, document-to-value structure sorting, faceting, and function queries read from — far cheaper for those than reading indexed postings or uninverting stored values at query time. See DocValues.

multiValued

The field accepts more than one value per document (an array in the JSON body, several <field> elements in XML) — genre_ss in the getting-started round-trip is one.

required

/update rejects any document missing a value for this field. Used almost exclusively on id, or on fields a downstream process depends on unconditionally.

useDocValuesAsStored

When both docValues and stored are true (or stored is false but docValues is true), governs whether the field is returned in search results at all and, if so, whether it is read from the stored value or reconstructed from docValues — default true since schema version 1.7, letting a docValues-only field (not stored) still come back in results without paying for stored-field storage too.

curl -X POST -H 'Content-Type: application/json' \
  "http://localhost:8983/solr/books/schema" \
  -d '{
        "add-field": {
          "name": "internal_note_s",
          "type": "string",
          "indexed": false,
          "stored": true
        }
      }'
# indexed:false, stored:true -- retrievable, never searchable or filterable.

Full property reference, including the analysis-related flags (omitNorms, omitTermFreqAndPositions, termVectors) not covered here: Fields.

Preventing field explosion

An open-ended source of field names — schemaless mode left on in production, or a dynamicField pattern too broad for what it actually matches — creates the same problem Elasticsearch’s dynamic mapping does: every distinct key becomes its own field in the schema, cluster state (here, ZooKeeper) grows without bound, and Schema API calls and node startup both slow down as the field count climbs into the thousands. Solr has no single total_fields.limit-style setting; the guardrails are structural instead:

  • Turn field guessing off once the real field set is known — remove or restrict the add-unknown-fields-to-the-schema update request processor in solrconfig.xml so an unexpected key is dropped or rejected rather than silently minted into a new field.

  • Prefer a handful of dynamicField patterns (_s, *_i, *_dt) that route many keys onto a small number of *types, over letting schemaless mode create one bespoke field per key.

  • Fold sparse, rarely-queried, or high-cardinality-of-key data into a copyField catch-all or a single stored, non-indexed field holding the raw value, instead of indexing every key on its own — the same schema-on-write trade-off Elasticsearch’s own mapping-explosion guardrails make, since both sit on Lucene.

  • Audit the live field count periodically with the Schema API’s field list (GET /schema/fields?wt=json) or the Admin UI’s Schema tab, rather than discovering it from a slow node restart.

# Count fields on a collection -- a quick smell test, not a hard limit.
curl "http://localhost:8983/solr/books/schema/fields?wt=json" | grep -o '"name"' | wc -l

Continue with Field types for what a fieldType itself configures (analyzers, numeric precision, similarity), or Indexing & updates for how documents are written against the schema defined here.