---
title: "Generating extraction schemas | Nutrient Java SDK"
canonical_url: "https://www.nutrient.io/guides/java/extraction/generate-extraction-schema/"
md_url: "https://www.nutrient.io/guides/java/extraction/generate-extraction-schema.md"
last_updated: "2026-07-10T00:00:00.000Z"
description: "Generate JSON schemas for structured data extraction using Nutrient Java SDK."
---

# Generating extraction schemas

Structured extraction starts with a JSON Schema: the schema tells the extraction model exactly which fields to fill, and an LLM's structured-output mode guarantees the result matches it. Writing that schema by hand is the slow part — you study sample documents, name every field, decide what's nullable, what repeats, what's an enum. *Schema generation* drafts it for you: describe the document type, state your requirements in plain language, attach a few example documents, and get back a schema ready for structured-output extraction.

This sample shows how to generate an extraction schema from example documents using Nutrient Java SDK. Generation uses a vision model — by default a local server, so documents don't have to leave your machine.

[Download sample](https://www.nutrient.io/downloads/samples/java/generate-extraction-schema.zip)

## How Nutrient helps

Nutrient Java SDK runs the full schema generation workflow behind a single method call. The SDK handles:

- Rendering the example documents' pages and sending them to the vision model in one request

- Drafting a schema grounded in the document type, your requirement, and the examples

- Validating and hard-clamping the draft — field budget, nesting depth, and the feature set of your target structured-output dialect

- Optionally drafting cross-field constraint rules (sums, orderings) and validating each one against the schema

- Serializing the result to JSON

The result always satisfies the limits you configured, regardless of what the model drafted — the same call with the same settings yields a schema your extraction target accepts.

## How generation works

Three inputs shape the schema:

- **Document type** (required) — The class of documents the schema must represent, such as "invoice" or "application form". It grounds the schema's vocabulary.

- **Requirement** (optional) — A free-form description of what the schema must capture: fields of interest, granularity, naming preferences — anything you'd tell a colleague.

- **Example documents** (optional, up to five) — Opened documents whose pages are rendered and shown to the model as representative samples. The schema is designed so *other* documents of the same type also fit, not just the examples. At most 20 pages are sent in total across all examples; pages beyond that bound aren't rendered.

Generation requires a vision model. By default the SDK talks to a local OpenAI-compatible server at `http://localhost:1234/v1` — configure the connection through `CustomVlmApiSettings` the same way as in the [describe image with local AI](https://www.nutrient.io/guides/java/extraction/describe-image-with-local-ai.md) guide. Schema generation requires the vision schema generation feature in your license.

## Targeting a structured-output dialect

LLM providers each accept a different subset of JSON Schema in their structured-output modes — one rejects `oneOf`, another rejects `maxItems`, a third silently ignores keywords it doesn't know. The `Compatibility` setting picks the target dialect, and the SDK guarantees the generated schema stays inside it:

- **`Portable`** (default) — The intersection accepted by the major structured-output modes and local grammar-constrained inference engines. The safest choice when you don't know where the schema will run.

- **`OpenAI`**, **`Anthropic`**, **`Gemini`** — Unlock the keywords that specific provider documents as supported, while enforcing its documented rejections.

- **`None`** — No dialect filter; any standard JSON Schema feature the other knobs enable.

Every generated schema also satisfies the strict-mode invariants shared by all providers: an object root, every property listed in `required`, `additionalProperties: false` on every object, and optionality expressed as a null type union rather than a missing requirement.

## Bounding the schema

Generated schemas stay within the budgets you set — properties beyond `MaxFields` are truncated and structures deeper than `MaxNestingDepth` are flattened, so a verbose model can't produce an unusable schema. Feature knobs (`AllowEnums`, `AllowNullable`, `AllowStringFormats`, and others) control which JSON Schema features the draft may use.

## Cross-field constraints

A schema describes each field in isolation; it can't say "the subtotal equals the sum of the line item amounts." Enabling `IncludeConstraints` asks the model to also encode such relationships as [JsonLogic](https://jsonlogic.com) constraint rules — inert JSON expressions your validation layer can evaluate after extraction. Every rule is checked against the generated schema: a rule referencing a field that doesn't exist is dropped, so the constraints always match the schema they ship with.

## Complete implementation

Specify a package name and create a new class:

```java

package io.nutrient.Sample;

```

Import the classes used in the sample:

```java

import io.nutrient.sdk.Document;
import io.nutrient.sdk.Vision;
import io.nutrient.sdk.requests.SchemaGenerationRequest;
import io.nutrient.sdk.settings.DocumentSettings;
import io.nutrient.sdk.exceptions.NutrientException;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

```

## Building the request

Open the example documents in a try-with-resources block so resources are cleaned up after processing, then describe what the schema must represent:

```java

public class GenerateExtractionSchema {
    public static void main(String[] args) {
        try (Document firstExample = Document.open("input_forms.pdf");
             Document secondExample = Document.open("input_forms_detection.pdf")) {

            SchemaGenerationRequest request = new SchemaGenerationRequest();
            request.setDocumentType("application form");
            request.setRequirement(
                "Capture the applicant's identity (full name, date of birth, contact details), " +
                "every checkbox group as an enumerated field, and the signature and date block. " +
                "Repeating rows belong in arrays of objects.");
            request.addExampleDocument(firstExample);
            request.addExampleDocument(secondExample);

```

## Configuring the schema shape

Create standalone document settings carrying the schema knobs — bound the field budget and opt in to cross-field constraints:

```java

            DocumentSettings settings = new DocumentSettings();
            var schemaGeneration = settings.getSchemaGenerationSettings();
            schemaGeneration.setMaxFields(40);
            schemaGeneration.setIncludeConstraints(true);

```

## Generating the schema

Call the static `Vision.generateSchema()` with the request and settings:

```java

            String resultJson = Vision.generateSchema(request, settings);

            Files.writeString(Path.of("output.json"), resultJson);
        } catch (NutrientException | IOException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

```

## Understanding the output

`generateSchema()` returns a JSON envelope with two members — the shape is the same whether or not constraints are enabled:

- **`schema`** — The generated JSON Schema, ready to pass to an LLM structured-output mode. Every property carries a `description` telling the extractor what to put there.

- **`constraints`** — Cross-field rules (empty unless `IncludeConstraints` is on). Each carries a short `id`, a one-sentence `description`, and a `rule` — a plain, standard JsonLogic expression that evaluates to `true` when the extracted document is internally consistent, for example, `{"==": [{"var": "total"}, {"+": [{"var": "subtotal"}, {"var": "tax_amount"}]}]}`.

Pass `schema` to your extraction call, and after extraction, evaluate each constraint rule against the extracted data with any JsonLogic implementation — a `false` result flags the document for review. Comparison policy (such as tolerating sub-cent rounding differences in numeric checks) is yours to apply in that evaluation step.

## Error handling

Vision API raises `VisionException` (a `NutrientException`) when generation fails. Common failure scenarios include a missing document type, more than five example documents, an unreachable vision model endpoint, or a model response that isn't valid JSON after a retry. In production code, catch `NutrientException`, return a clear error message, and log failure details for debugging.

## Conclusion

The workflow for generating an extraction schema is:

1. Open up to five representative example documents using try-with-resources for automatic resource cleanup.

2. Build a `SchemaGenerationRequest` with the document type (required), a natural-language requirement, and the examples.

3. Configure the schema shape — field budget, nesting, target dialect, constraints — through the schema generation settings.

4. Call `Vision.generateSchema()` to draft, validate, and clamp the schema.

5. Write the envelope to a file; feed `schema` to your structured-output extraction and `constraints` to your validation layer.

6. Handle `NutrientException` for robust error recovery.

For configuring the vision model connection, refer to the [describe image with local AI](https://www.nutrient.io/guides/java/extraction/describe-image-with-local-ai.md) guide. For related extraction workflows, refer to the [Java SDK guides](https://www.nutrient.io/guides/java.md).

Download [this ready-to-use sample package](https://www.nutrient.io/downloads/samples/java/generate-extraction-schema.zip) to explore schema generation.
---

## Related pages

- [Applying OCR to a PDF page](/guides/java/extraction/apply-ocr-to-pdf-page.md)
- [Applying OCR to a PDF document](/guides/java/extraction/apply-ocr-to-pdf.md)
- [Classifying documents](/guides/java/extraction/classify-document.md)
- [Generating image descriptions using Claude](/guides/java/extraction/describe-image-with-claude.md)
- [Detecting document language](/guides/java/extraction/detect-document-language.md)
- [Extracting data from specific pages](/guides/java/extraction/extract-data-from-specific-pages.md)
- [Generating image descriptions using local AI](/guides/java/extraction/describe-image-with-local-ai.md)
- [Extracting data from images using ICR](/guides/java/extraction/extract-data-from-image-icr.md)
- [Generating image descriptions using OpenAI](/guides/java/extraction/describe-image-with-openai.md)
- [Extracting data from images using vision language models](/guides/java/extraction/extract-data-from-image-vlm.md)
- [Extracting data from images using OCR](/guides/java/extraction/extract-data-from-image-ocr.md)
- [Extracting form fields from images](/guides/java/extraction/extract-form-fields-from-image.md)
- [Nutrient Java SDK extraction guides](/guides/java/extraction.md)
- [Extracting structured data from documents](/guides/java/extraction/extract-structured-data.md)
- [Extracting JSON data from a PDF document](/guides/java/extraction/json-data-extraction.md)
- [Reading barcodes with vision extraction](/guides/java/extraction/read-barcodes-with-vision.md)
- [Extracting text from multilingual images](/guides/java/extraction/read-text-from-image-multi-language.md)
- [Labeling form fields with a vision language model](/guides/java/extraction/label-form-fields-with-vlm.md)
- [Extracting text from PDF documents](/guides/java/extraction/pdf-to-text.md)
- [Extracting text from images](/guides/java/extraction/read-text-from-image.md)
- [Searching document text](/guides/java/extraction/search-document-text.md)
- [Speeding up first ICR operation by predownloading models](/guides/java/extraction/speed-up-first-icr-by-downloading-requirements.md)

