diff --git a/fern/versions/v26.04.yml b/fern/versions/v26.04.yml
index 0c6e47f03c..5dfba861c5 100644
--- a/fern/versions/v26.04.yml
+++ b/fern/versions/v26.04.yml
@@ -276,6 +276,9 @@ navigation:
- page: Inference Server
path: ./v26.04/pages/curate-text/synthetic/inference-server.mdx
slug: inference-server
+ - page: NeMo Data Designer
+ path: ./v26.04/pages/curate-text/synthetic/nemo-data-designer.mdx
+ slug: nemo-data-designer
- page: Multilingual Q&A
path: ./v26.04/pages/curate-text/synthetic/multilingual-qa.mdx
slug: multilingual-qa
diff --git a/fern/versions/v26.04/pages/about/release-notes/index.mdx b/fern/versions/v26.04/pages/about/release-notes/index.mdx
index abb0382825..5315b6f658 100644
--- a/fern/versions/v26.04/pages/about/release-notes/index.mdx
+++ b/fern/versions/v26.04/pages/about/release-notes/index.mdx
@@ -146,6 +146,17 @@ Standardized return type for all deduplication workflows:
Added tqdm progress bars to `RayActorPoolExecutor` for real-time visibility into task completion during stage processing and shuffle inserts. Progress bars are enabled by default and can be configured with `show_progress` and `progress_interval` parameters. This is particularly useful for long-running deduplication jobs where progress is not otherwise apparent.
+### NeMo Data Designer Integration
+
+Integrated the NeMo Data Designer (NDD) client with NeMo Curator for declarative synthetic data generation at scale:
+
+- **`DataDesignerStage`**: New processing stage that wraps NDD's `DataDesigner.preview()` to generate structured synthetic data within Curator pipelines. Accepts a `DataDesignerConfigBuilder` or YAML config file and supports sampler columns (Faker names, UUIDs, dates), expression columns (Jinja templates), and LLM text columns.
+- **NDD-backed Nemotron-CC stages**: Drop-in replacements for the five Nemotron-CC stages (`WikipediaParaphrasingStage`, `DiverseQAStage`, `DistillStage`, `ExtractKnowledgeStage`, `KnowledgeListStage`) that route generation through NDD instead of `AsyncOpenAIClient`. Import from `nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc`.
+- **Token metric collection**: `DataDesignerStage` automatically reports `input_tokens_median_per_record` and `output_tokens_median_per_record` from NDD's analysis, enabling throughput tracking without manual instrumentation.
+- **Local and remote inference**: Supports both the built-in `InferenceServer` (Ray Serve + vLLM) via custom `ModelProvider` and remote endpoints (NVIDIA NIM).
+
+Learn more in the [NeMo Data Designer](/curate-text/synthetic/nemo-data-designer) documentation.
+
### S3 Transport for CommonCrawlWARCReader (PR #1604)
Added S3 as an alternative transport for `CommonCrawlWARCReader`, which fetches individual WARC records using byte-range requests:
diff --git a/fern/versions/v26.04/pages/curate-text/synthetic/index.mdx b/fern/versions/v26.04/pages/curate-text/synthetic/index.mdx
index 0647a27e2d..e6fe404ab0 100644
--- a/fern/versions/v26.04/pages/curate-text/synthetic/index.mdx
+++ b/fern/versions/v26.04/pages/curate-text/synthetic/index.mdx
@@ -37,6 +37,10 @@ Improve or restructure existing data using LLM capabilities. The Nemotron-CC sta
- Condensed knowledge distillations
- Extracted factual content
+### Declarative Mode (NeMo Data Designer)
+
+Define data generation pipelines declaratively using [NeMo Data Designer](/curate-text/synthetic/nemo-data-designer) (NDD). Instead of writing imperative LLM call logic, you configure structured column generation (samplers, expressions, LLM text columns) through a builder API or YAML file. NDD handles execution, batching, and token metric collection. This mode supports both standalone generation and NDD-backed versions of Nemotron-CC stages.
+
## Architecture
The following diagram shows how SDG pipelines process data through preprocessing, LLM generation, and postprocessing stages:
@@ -95,6 +99,7 @@ Nemotron-CC pipelines use the `transformers` library for tokenization, which is
| `DistillStage` | Create condensed, information-dense paraphrases | Document text |
| `ExtractKnowledgeStage` | Extract knowledge as textbook-style passages | Document text |
| `KnowledgeListStage` | Extract structured fact lists | Document text |
+| `DataDesignerStage` | Declarative generation via NeMo Data Designer | Seed data (any schema) |
---
@@ -120,6 +125,12 @@ quickstart
tutorial
+
+Declarative data generation with structured columns and NDD-backed Nemotron-CC stages
+ndd
+declarative
+
+
Advanced text transformation and knowledge extraction workflows
advanced
diff --git a/fern/versions/v26.04/pages/curate-text/synthetic/nemo-data-designer.mdx b/fern/versions/v26.04/pages/curate-text/synthetic/nemo-data-designer.mdx
new file mode 100644
index 0000000000..8b04468964
--- /dev/null
+++ b/fern/versions/v26.04/pages/curate-text/synthetic/nemo-data-designer.mdx
@@ -0,0 +1,316 @@
+---
+description: "Scale synthetic data generation using NeMo Data Designer (NDD) with declarative configuration and structured column generation"
+categories: ["how-to-guides"]
+tags: ["nemo-data-designer", "ndd", "synthetic-data", "data-designer", "declarative-config", "structured-generation"]
+personas: ["data-scientist-focused", "mle-focused"]
+difficulty: "intermediate"
+content_type: "how-to"
+modality: "text-only"
+---
+
+# NeMo Data Designer Integration
+
+[NeMo Data Designer (NDD)](https://nvidia-nemo.github.io/DataDesigner/latest/) is a declarative data generation framework that integrates with NeMo Curator to scale synthetic data pipelines. Instead of writing imperative LLM call logic, you define a configuration that describes what columns to generate, how to sample structured fields, and which LLM to use. NDD handles execution, batching, and token metric collection automatically.
+
+## How It Works
+
+NeMo Curator wraps NDD through the `DataDesignerStage`, which accepts a `DataDesignerConfigBuilder` or a YAML config file. The stage:
+
+1. Takes input records from a `DocumentBatch`
+2. Passes them to NDD as a seed dataset
+3. Calls `DataDesigner.preview()` to generate new columns (samplers, expressions, LLM text)
+4. Returns the enriched dataset as a new `DocumentBatch` with token usage metrics
+
+```mermaid
+flowchart LR
+ A["Seed Data
(JSONL/Parquet)"] --> B["DataDesignerStage"]
+ B --> C["NDD Engine
(Samplers, Expressions,
LLM Generation)"]
+ C --> D["Enriched Output
(JSONL/Parquet)"]
+
+ E["LLM Endpoint
(Local InferenceServer
or NVIDIA NIM)"] -.->|"API Calls"| C
+
+ classDef stage fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#000
+ classDef infra fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#000
+ classDef output fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px,color:#000
+
+ class A,B stage
+ class D output
+ class C,E infra
+```
+
+## Prerequisites
+
+Install the NDD dependency:
+
+```bash
+uv pip install --extra-index-url https://pypi.nvidia.com nemo-curator[text_cuda12]
+```
+
+The `data-designer` package is included in the text extras. For local model serving, also install:
+
+```bash
+uv pip install nemo-curator[inference_server]
+```
+
+## DataDesignerStage
+
+The `DataDesignerStage` is the core integration point between NeMo Curator and NDD.
+
+### Parameters
+
+| Parameter | Type | Default | Description |
+| --- | --- | --- | --- |
+| `config_builder` | `DataDesignerConfigBuilder` | None | NDD configuration builder. Mutually exclusive with `data_designer_config_file`. |
+| `data_designer_config_file` | str | None | Path to a YAML config file. Mutually exclusive with `config_builder`. |
+| `model_providers` | list | None | Custom `ModelProvider` instances for local or test endpoints. If None, NDD uses its default providers. |
+| `verbose` | bool | False | When True, show full NDD log output. |
+
+### Metrics
+
+`DataDesignerStage` automatically collects and reports:
+
+- `ndd_running_time`: Wall-clock time for the NDD `preview()` call
+- `num_input_records` / `num_output_records`: Record counts before and after generation
+- `input_tokens_median_per_record` / `output_tokens_median_per_record`: Median token counts across all LLM columns
+
+## Building a Configuration
+
+NDD configurations use a builder pattern. You add columns of three types:
+
+
+For full documentation for building NDD configuration, see the [NDD config builder reference](https://nvidia-nemo.github.io/DataDesigner/latest/code_reference/config_builder/).
+
+
+### Sampler Columns
+
+Generate structured data using built-in samplers (Faker names, UUIDs, dates):
+
+```python
+import data_designer.config as dd
+
+config_builder = dd.DataDesignerConfigBuilder(model_configs=[model_config])
+
+config_builder.add_column(
+ dd.SamplerColumnConfig(
+ name="patient_name",
+ sampler_type=dd.SamplerType.PERSON_FROM_FAKER,
+ params=dd.PersonFromFakerSamplerParams(),
+ )
+)
+
+config_builder.add_column(
+ dd.SamplerColumnConfig(
+ name="patient_id",
+ sampler_type=dd.SamplerType.UUID,
+ params=dd.UUIDSamplerParams(prefix="PT-", short_form=True, uppercase=True),
+ )
+)
+```
+
+### Expression Columns
+
+Derive values from other columns using Jinja templates:
+
+```python
+config_builder.add_column(
+ dd.ExpressionColumnConfig(
+ name="first_name",
+ expr="{{ patient_name.first_name }}",
+ )
+)
+```
+
+### LLM Text Columns
+
+Generate text using an LLM with prompts that reference other columns:
+
+```python
+config_builder.add_column(
+ dd.LLMTextColumnConfig(
+ name="physician_notes",
+ prompt="""\
+You are a primary-care physician who just had an appointment with {{ first_name }}.
+{{ patient_summary }}
+Write careful notes about your visit. Respond with only the notes.
+""",
+ model_alias="local-llm",
+ )
+)
+```
+
+## End-to-End Example
+
+This example generates synthetic medical notes from seed symptom data using a local `InferenceServer`:
+
+```python
+import data_designer.config as dd
+
+from nemo_curator.backends.ray_data import RayDataExecutor
+from nemo_curator.core.client import RayClient
+from nemo_curator.core.serve import InferenceModelConfig, InferenceServer
+from nemo_curator.pipeline import Pipeline
+from nemo_curator.stages.synthetic.nemo_data_designer.data_designer import DataDesignerStage
+from nemo_curator.stages.text.io.reader.jsonl import JsonlReader
+from nemo_curator.stages.text.io.writer.jsonl import JsonlWriter
+
+# Start Ray cluster
+client = RayClient(num_cpus=16, num_gpus=4)
+client.start()
+
+# Start local inference server
+server_config = InferenceModelConfig(
+ model_identifier="google/gemma-3-27b-it",
+ deployment_config={"autoscaling_config": {"min_replicas": 1, "max_replicas": 1}},
+ engine_kwargs={"tensor_parallel_size": 4},
+)
+inference_server = InferenceServer(models=[server_config])
+inference_server.start()
+
+# Configure NDD model
+model_config = dd.ModelConfig(
+ alias="local-llm",
+ model="google/gemma-3-27b-it",
+ provider="local",
+ skip_health_check=True,
+ inference_parameters=dd.ChatCompletionInferenceParams(
+ temperature=1.0, top_p=1.0, max_tokens=2048,
+ ),
+)
+
+model_provider = dd.ModelProvider(
+ name="local",
+ endpoint=inference_server.endpoint,
+ api_key="unused",
+)
+
+# Build config with sampler and LLM columns
+config_builder = dd.DataDesignerConfigBuilder(model_configs=[model_config])
+
+config_builder.add_column(
+ dd.SamplerColumnConfig(
+ name="patient_name",
+ sampler_type=dd.SamplerType.PERSON_FROM_FAKER,
+ params=dd.PersonFromFakerSamplerParams(),
+ )
+)
+
+config_builder.add_column(
+ dd.LLMTextColumnConfig(
+ name="physician_notes",
+ prompt="You are a physician. Write notes for {{ patient_name.first_name }} "
+ "who has {{ diagnosis }}. {{ patient_summary }}",
+ model_alias="local-llm",
+ )
+)
+
+# Build and run pipeline
+pipeline = Pipeline(name="ndd_medical_notes")
+pipeline.add_stage(JsonlReader(file_paths="seed_data/*.jsonl", fields=["diagnosis", "patient_summary"]))
+pipeline.add_stage(DataDesignerStage(config_builder=config_builder, model_providers=[model_provider]))
+pipeline.add_stage(JsonlWriter(path="./synthetic_output"))
+
+pipeline.run(executor=RayDataExecutor())
+
+inference_server.stop()
+client.stop()
+```
+
+## Using a Remote Provider
+
+To use NVIDIA NIM or another hosted endpoint instead of a local server, configure the `ModelProvider` with the remote URL and API key:
+
+```python
+import os
+
+import data_designer.config as dd
+
+from nemo_curator.stages.synthetic.nemo_data_designer.data_designer import DataDesignerStage
+
+model_config = dd.ModelConfig(
+ alias="nim-llm",
+ model="meta/llama-3.3-70b-instruct",
+ provider="nvidia",
+ inference_parameters=dd.ChatCompletionInferenceParams(
+ temperature=0.5, top_p=0.9, max_tokens=1600,
+ ),
+)
+
+model_provider = dd.ModelProvider(
+ name="nvidia",
+ endpoint="https://integrate.api.nvidia.com/v1",
+ provider_type="openai",
+ api_key=os.environ["NVIDIA_API_KEY"],
+)
+
+config_builder = dd.DataDesignerConfigBuilder(model_configs=[model_config])
+# Add columns as needed...
+
+stage = DataDesignerStage(
+ config_builder=config_builder,
+ model_providers=[model_provider],
+)
+```
+
+## NDD-Backed Nemotron-CC Stages
+
+The Nemotron-CC synthetic data stages have NDD-backed equivalents that replace the `AsyncOpenAIClient` with NDD execution. These stages accept the same `input_field`, `output_field`, and prompt parameters, but route generation through `DataDesignerStage` internally.
+
+| Stage | Import Path | Output Field |
+| --- | --- | --- |
+| `WikipediaParaphrasingStage` | `nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc` | `rephrased` |
+| `DiverseQAStage` | `nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc` | `diverse_qa` |
+| `DistillStage` | `nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc` | `distill` |
+| `ExtractKnowledgeStage` | `nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc` | `extract_knowledge` |
+| `KnowledgeListStage` | `nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc` | `knowledge_list` |
+
+These stages inherit from `NDDBaseSyntheticStage`, which auto-builds an NDD config from the prompt fields. You configure the LLM through `model_configs` and `model_providers` instead of an `AsyncOpenAIClient`:
+
+```python
+import os
+
+import data_designer.config as dd
+
+from nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc import DiverseQAStage
+
+model_config = dd.ModelConfig(
+ alias="meta/llama-3.3-70b-instruct",
+ model="meta/llama-3.3-70b-instruct",
+ provider="nvidia",
+ inference_parameters=dd.ChatCompletionInferenceParams(
+ temperature=0.5, top_p=0.9, max_tokens=1600,
+ ),
+)
+
+model_provider = dd.ModelProvider(
+ name="nvidia",
+ endpoint="https://integrate.api.nvidia.com/v1",
+ provider_type="openai",
+ api_key=os.environ["NVIDIA_API_KEY"],
+)
+
+stage = DiverseQAStage(
+ input_field="text",
+ output_field="diverse_qa",
+ model_alias="meta/llama-3.3-70b-instruct",
+ model_configs=[model_config],
+ model_providers=[model_provider],
+)
+```
+
+## YAML Configuration
+
+Instead of building configs in Python, you can define the entire NDD configuration in a YAML file and pass it to `DataDesignerStage`:
+
+```python
+stage = DataDesignerStage(data_designer_config_file="config.yaml")
+```
+
+This is useful for reproducible pipelines where the generation config is versioned alongside data artifacts.
+
+---
+
+## Next Steps
+
+- [Inference Server](/curate-text/synthetic/inference-server): Co-locate model serving with your pipeline
+- [Nemotron-CC Pipelines](/curate-text/synthetic/nemotron-cc): Advanced text transformation tasks
+- [Synthetic Data Generation](/curate-text/synthetic): Overview of all SDG capabilities
diff --git a/fern/versions/v26.04/pages/curate-text/synthetic/nemotron-cc/index.mdx b/fern/versions/v26.04/pages/curate-text/synthetic/nemotron-cc/index.mdx
index 695cbd2e17..45531325bd 100644
--- a/fern/versions/v26.04/pages/curate-text/synthetic/nemotron-cc/index.mdx
+++ b/fern/versions/v26.04/pages/curate-text/synthetic/nemotron-cc/index.mdx
@@ -300,6 +300,52 @@ client.stop()
---
+## NDD-Backed Stages
+
+All five Nemotron-CC tasks have NDD-backed equivalents that replace the `AsyncOpenAIClient` with [NeMo Data Designer](/curate-text/synthetic/nemo-data-designer) execution. These stages share the same `input_field`, `output_field`, and prompt interface, but configure the LLM through NDD's `ModelConfig` and `ModelProvider` instead of an `AsyncOpenAIClient`.
+
+Import the NDD-backed stages from `nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc`:
+
+```python
+import os
+
+import data_designer.config as dd
+
+from nemo_curator.pipeline import Pipeline
+from nemo_curator.stages.synthetic.nemotron_cc.nemo_data_designer.nemotron_cc import DiverseQAStage
+
+model_config = dd.ModelConfig(
+ alias="meta/llama-3.3-70b-instruct",
+ model="meta/llama-3.3-70b-instruct",
+ provider="nvidia",
+ inference_parameters=dd.ChatCompletionInferenceParams(
+ temperature=0.5, top_p=0.9, max_tokens=600,
+ ),
+)
+
+model_provider = dd.ModelProvider(
+ name="nvidia",
+ endpoint="https://integrate.api.nvidia.com/v1",
+ provider_type="openai",
+ api_key=os.environ["NVIDIA_API_KEY"],
+)
+
+pipeline = Pipeline(name="nemotron_cc_ndd_diverse_qa")
+pipeline.add_stage(
+ DiverseQAStage(
+ input_field="text",
+ output_field="diverse_qa",
+ model_alias="meta/llama-3.3-70b-instruct",
+ model_configs=[model_config],
+ model_providers=[model_provider],
+ )
+)
+```
+
+The NDD backend provides automatic token metric collection and supports both local `InferenceServer` and remote NVIDIA NIM endpoints. See the [NeMo Data Designer](/curate-text/synthetic/nemo-data-designer) guide for full configuration details.
+
+---
+
## Detailed Reference
@@ -310,4 +356,10 @@ reference
api
+
+Declarative generation with NDD-backed Nemotron-CC stages
+ndd
+declarative
+
+