|
| 1 | +--- |
| 2 | +date: 2026-05-05 |
| 3 | +authors: |
| 4 | + - jgreco |
| 5 | + - etramel |
| 6 | +--- |
| 7 | + |
| 8 | +# **Have It Your Way: Customizing Data Designer with Plugins** |
| 9 | + |
| 10 | +*A plugin framework for the custom pieces every real project ends up needing* |
| 11 | + |
| 12 | +Data Designer is built around a simple idea: describe the dataset you want, and let the framework handle execution. A config points to seed data, defines generated columns, picks models, and shapes the final records — no orchestration code required. |
| 13 | + |
| 14 | +That separation works well, right up until the point your project needs something specific to its corpus, its domain, or its training stack. |
| 15 | + |
| 16 | +Your seed data is not in a neat Parquet file — it lives behind an internal API, in a document store, or across a filesystem layout only your team understands. The value you need in a column does not come from a simple prompt; it comes from a simulator, a rules engine, a geospatial library, a retrieval stack, or a model call wrapped in domain-specific validation. And the final records do not quite match the shape your training pipeline expects, so there is one more transformation before the dataset is actually usable. |
| 17 | + |
| 18 | +Data Designer now ships a plugin framework for exactly that layer of customization. Package the custom behavior, install it, import its config class, and use it in a normal workflow. Data Designer discovers the plugin automatically, validates it with the same config system, wires it through the registries, and runs it on the standard execution path. |
| 19 | + |
| 20 | +<!-- more --> |
| 21 | + |
| 22 | +{ width=100% } |
| 23 | + |
| 24 | +This is the practical problem plugins solve: no core library can predict every data source, generator, validator, simulator, processor, or output format users will need. The goal is not to absorb every specialized capability into Data Designer itself. It's to make custom behavior easy to package and reuse, without turning every project into a tangle of project-specific glue code. |
| 25 | + |
| 26 | +!!! tip "TL;DR - What plugins give you" |
| 27 | + |
| 28 | + 1. Plugins expose custom behavior through the same Data Designer config and runtime paths as built-in components. |
| 29 | + |
| 30 | + 2. A plugin is a Python package discovered through the `data_designer.plugins` entry point group. Once installed, there is no manual registration step in user code. |
| 31 | + |
| 32 | + 3. Plugin configs use the same typed config model and serialization behavior as core config types. The engine receives an implementation through the plugin registry. |
| 33 | + |
| 34 | + 4. Plugins can start as a local editable install, move to an internal package index, and later be published publicly. |
| 35 | + |
| 36 | + 5. NVIDIA-maintained plugins now live in [NVIDIA-NeMo/DataDesignerPlugins](https://github.com/NVIDIA-NeMo/DataDesignerPlugins), separate from the core repo and installed as packages. |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## **Customization Is the Normal Case** |
| 41 | + |
| 42 | +Synthetic data work rarely stays generic for long. A useful dataset usually reflects the system it is meant to improve: product taxonomy, compliance rules, document structure, simulator outputs, training format, evaluation policy, privacy constraints, task distribution, and other domain-specific requirements. |
| 43 | + |
| 44 | +Those details are where the value comes from. They are also where framework boundaries get tested. |
| 45 | + |
| 46 | +Without a plugin boundary, customization tends to leak into notebooks and wrapper scripts. Someone patches a file reader for one corpus. Someone else copies a generator into a project folder. A formatting step lives after generation because it did not fit anywhere else. The pipeline works, but the behavior is not really part of the Data Designer workflow. It is harder to validate, harder to share, harder to version, and easier to lose. |
| 47 | + |
| 48 | +Plugins put that work behind a reusable package boundary. A custom capability gets a name, a typed config, a runtime implementation, and tests that travel with the package. Users still declare the dataset they want; the custom logic stays behind a clean interface. |
| 49 | + |
| 50 | +The result is straightforward for users. Once installed, a seed reader for your internal corpus is just another seed source. A generator backed by a domain simulator uses the normal column path. A processor that emits your team's SFT format runs as a normal processor. |
| 51 | + |
| 52 | +--- |
| 53 | + |
| 54 | +## **From Glue Code to a Capability** |
| 55 | + |
| 56 | +Consider a markdown seed reader. The one-off version might be a helper function that walks a directory, splits files into sections, returns a DataFrame, and then gets copied into the next project that needs it. |
| 57 | + |
| 58 | +That can work for one project. It becomes a problem when the reader needs options, tests, documentation, versioning, or reuse across teams. At that point, the helper has become a capability whether or not it is packaged like one. |
| 59 | + |
| 60 | +A plugin packages the same idea as a small Python project: |
| 61 | + |
| 62 | +- A user-facing config class describes the options. |
| 63 | +- An implementation class does the work. |
| 64 | +- A `Plugin` object connects the config to the implementation. |
| 65 | +- A Python entry point exposes the plugin to Data Designer. |
| 66 | + |
| 67 | +The entry point exposes the plugin package to Data Designer: |
| 68 | + |
| 69 | +```toml |
| 70 | +[project.entry-points."data_designer.plugins"] |
| 71 | +markdown-sections = "data_designer_markdown_sections.plugin:plugin" |
| 72 | +``` |
| 73 | + |
| 74 | +The plugin object tells Data Designer what kind of extension this is and where to find the config and implementation: |
| 75 | + |
| 76 | +```python |
| 77 | +from data_designer.plugins import Plugin, PluginType |
| 78 | + |
| 79 | +plugin = Plugin( |
| 80 | + config_qualified_name="data_designer_markdown_sections.config.MarkdownSectionSeedSource", |
| 81 | + impl_qualified_name="data_designer_markdown_sections.impl.MarkdownSectionSeedReader", |
| 82 | + plugin_type=PluginType.SEED_READER, |
| 83 | +) |
| 84 | +``` |
| 85 | + |
| 86 | +After that, users do not import engine internals or run registration code. They import the config class and use it: |
| 87 | + |
| 88 | +```python |
| 89 | +import data_designer.config as dd |
| 90 | +from data_designer.interface import DataDesigner |
| 91 | +from data_designer_markdown_sections.config import MarkdownSectionSeedSource |
| 92 | + |
| 93 | +builder = dd.DataDesignerConfigBuilder() |
| 94 | +builder.with_seed_dataset( |
| 95 | + MarkdownSectionSeedSource( |
| 96 | + path="docs/", |
| 97 | + file_pattern="*.md", |
| 98 | + ) |
| 99 | +) |
| 100 | +builder.add_column( |
| 101 | + dd.LLMTextColumnConfig( |
| 102 | + name="question", |
| 103 | + model_alias="nvidia-text", |
| 104 | + prompt="Write a question about this section: {{ section_content }}", |
| 105 | + ) |
| 106 | +) |
| 107 | + |
| 108 | +results = DataDesigner().preview(builder, num_records=5) |
| 109 | +``` |
| 110 | + |
| 111 | +No custom orchestration. No separate DataFrame preparation step. The reader is part of the Data Designer workflow. |
| 112 | + |
| 113 | +--- |
| 114 | + |
| 115 | +## **Where Plugins Fit** |
| 116 | + |
| 117 | +The first plugin boundaries match the places where real projects most often need customization. |
| 118 | + |
| 119 | +**Seed reader plugins** bring new source systems into Data Designer. Use them for databases, document stores, object stores, internal APIs, file collections, or corpus layouts that need custom hydration before generation can begin. |
| 120 | + |
| 121 | +**Column generator plugins** create new column types. Use them when a value should be produced during generation and should participate in dependency ordering like any other column. This is the right place for simulators, domain libraries, retrieval-backed generation, deterministic rule systems, or custom model-backed generation. |
| 122 | + |
| 123 | +**Processor plugins** transform records before or after generation. Use them for redaction, cleanup, deduplication, export views, organization-specific schemas, or training formats that should not be hidden inside prompts. |
| 124 | + |
| 125 | +These boundaries are intentionally narrow. A plugin should own the behavior that is specific to your use case. Data Designer should keep owning the pipeline responsibilities: validation, dependency resolution, batching, model calls, logging, previews, output handling. |
| 126 | + |
| 127 | +That split lets custom components use the normal workflow without moving orchestration into the project. |
| 128 | + |
| 129 | +--- |
| 130 | + |
| 131 | +## **Start Local, Share When Useful** |
| 132 | + |
| 133 | +A plugin does not need to start as a public package. Most should start locally. |
| 134 | + |
| 135 | +Start with a local Python package and install it in editable mode: |
| 136 | + |
| 137 | +```bash |
| 138 | +uv pip install -e . |
| 139 | +``` |
| 140 | + |
| 141 | +That is enough for Data Designer to discover the entry point. You can iterate on the config class and implementation while testing the plugin in a real preview loop. When the shape stabilizes, the same package can move to an internal index, a GitHub repo, or PyPI. |
| 142 | + |
| 143 | +This is useful inside teams. A data platform group can maintain seed readers for internal systems. An applied science group can maintain generators for its domain. A training group can maintain processors that emit exactly the record shapes its trainers consume. Everyone else installs a package and uses typed configs in the same workflow they already know. |
| 144 | + |
| 145 | +It is useful for the broader community too. If you build a plugin that should be discoverable by other Data Designer users, publish it and follow the instructions in [Available Plugins](../../plugins/available.md) to request a catalog listing. |
| 146 | + |
| 147 | +--- |
| 148 | + |
| 149 | +## **A Repository for First-Party Plugins** |
| 150 | + |
| 151 | +We also created [NVIDIA-NeMo/DataDesignerPlugins](https://github.com/NVIDIA-NeMo/DataDesignerPlugins), a dedicated repository for NVIDIA-maintained plugins. |
| 152 | + |
| 153 | +The core Data Designer repo should stay focused on the framework: the config API, engine execution, model integration, validation behavior, and the stable plugin interface. Plugin packages often have different needs. They may depend on optional libraries, target narrower use cases, or move at a different release pace than the core library. |
| 154 | + |
| 155 | +The plugin repo separates those packages from the core release cycle. It is where we will publish NVIDIA-maintained plugins, recommended packaging examples, and plugin-specific docs as the catalog grows. The packages install separately, but they use the same plugin interface once installed. |
| 156 | + |
| 157 | +This keeps the core lean while specialized packages evolve around a stable extension surface. |
| 158 | + |
| 159 | +--- |
| 160 | + |
| 161 | +## **Start with One Capability** |
| 162 | + |
| 163 | +If you have custom Data Designer code that keeps getting copied between projects, it is a strong candidate for a plugin. |
| 164 | + |
| 165 | +Pick one capability. Give it a typed config. Write the implementation behind the matching plugin boundary. Add an `assert_valid_plugin(...)` test so structural problems fail early: |
| 166 | + |
| 167 | +```python |
| 168 | +from data_designer.engine.testing import assert_valid_plugin |
| 169 | +from data_designer_markdown_sections.plugin import plugin |
| 170 | + |
| 171 | +assert_valid_plugin(plugin) |
| 172 | +``` |
| 173 | + |
| 174 | +Then run a tiny `preview` before you trust it in a larger generation job. |
| 175 | + |
| 176 | +For implementation details, see: |
| 177 | + |
| 178 | +- [Plugins overview](../../plugins/overview.md) |
| 179 | +- [Build Your Own](../../plugins/build_your_own.md) |
| 180 | +- [Using Models in Plugins](../../plugins/models.md) |
| 181 | +- [Available Plugins](../../plugins/available.md) |
| 182 | +- [Markdown Section Seed Reader recipe](../../recipes/plugin_development/markdown_seed_reader.md) |
| 183 | + |
| 184 | +Moving plugins out of experimental mode means Data Designer no longer has to predict every customization users will need. The framework provides the pipeline. Plugins supply the custom pieces. |
| 185 | + |
| 186 | +👋 Thanks for reading and happy plugin building! |
0 commit comments