Develop a Blueprint

What means develop a blueprint

Developing a Blueprint in Blindata means designing a reusable, production-ready template that standardizes how data products are created across your organization.

At a high level, a Blueprint is not just code - it’s a codified set of best practices. It captures how infrastructure, pipelines, governance, and configuration should be defined, validated, and deployed, and makes that knowledge available as a self-service asset for other teams.

Blueprints rely on the Apache Velocity template engine to render dynamic content. Files in the repository can include template expressions and use the .vm suffix. During instantiation, these templates are processed by replacing variables with the values provided through the manifest parameters, producing fully configured files in the generated data product repository.

When you develop a Blueprint, you are:

  • Abstracting complexity into a reusable template
  • Defining inputs (parameters) that make the template flexible
  • Embedding governance and controls directly into the setup
  • Automating provisioning of data product components
  • Enabling consistency across all generated data products

From a practical perspective, developing a Blueprint consists of three main activities:

  • Structuring the repository: Organizing your Git repository to include all the assets needed to provision a data product (infrastructure, pipelines, CI/CD, etc.).
  • Defining the Blueprint Manifest: Writing the manifest.yaml, which acts as the contract between the template and its users-declaring parameters, validation rules, UI behavior, composition, and instantiation strategy.
  • Designing for reuse: Ensuring the template is generic, configurable, and versioned so it can be instantiated multiple times across different contexts.

Blueprint repository layout

A blueprint is a regular Git repository. Blindata only needs a few known files to register, publish, and instantiate it - specifically the Blueprint Manifest, the README, and (optionally) the Data Product Descriptor template written in Apache Velocity. Everything else in the repository is fully under your control: you are free to organize folders, tooling, and assets as your team sees fit.

A possible example of a well-structured blueprint repository is shown below. Treat it as a reference layout, not a requirement: Blindata does not enforce, validate, or manage any of the non-blueprint folders (infrastructure, pipelines, notebooks, CI/CD, etc.) - they live in your Git repository and are maintained by you like any other codebase.

repository/
├── blueprint/
│   ├── manifest.yaml     # Blueprint Manifest
│   └── README.md         # Rendered in the "Documentation" tab
├── descriptor.json.vm    # Apache Velocity descriptor template
├── infrastructure/       # Example folder — Terraform, or any IaC you ship with the template
├── pipeline/             # Example folder — transformations (dlt, dbt, ...), jobs, notebooks
├── .github/workflows/    # Example folder — CI/CD
└── ... (any other content your template needs)

Only the paths to the manifest, the README, and the descriptor template are known to Blindata, and they are configurable when you register the blueprint . All other files and folders shown above are just illustrative examples of content you might ship with a blueprint - their structure, naming, and lifecycle are entirely managed inside your Git repository.

The Blueprint Manifest (blueprint/manifest.yaml by convention) is the single source of truth that drives how Blindata renders, validates, and instantiates the blueprint. Everything else in the repository is template content, rendered on instantiation with the parameters collected from the user.

Blueprint Manifest

The manifest is a YAML file conforming to the odm-blueprint-manifest specification. YAML is recommended over JSON because it supports comments, multi-line strings, and is the industry standard for infrastructure configuration.

A copy of the manifest - complete with the resolved parameter values and versioning metadata - is stored in every instantiated data product repository, so lineage back to the source blueprint is always preserved.

Below are showed the main sections that odm-blueprint-manifest specification supports.

Core schema

The following top-level keys are supported.

Field Type Required Description
spec String Yes Specification name. Must be odm-blueprint-manifest.
specVersion String Yes Version of the manifest schema itself (e.g. 1.0.0).
name String Yes Machine-readable identifier of the blueprint.
displayName String No Human-readable name.
version String Yes Semantic version of the blueprint release (e.g. 1.2.0).
description String No Short summary of what the blueprint provisions.
parameters Array<Parameter> No Inputs collected from the user at instantiation time.
protectedResources Array<ProtectedResource> No Files or globs marked immutable after generation.
composition Array<Module> No Child blueprints to instantiate alongside the parent.
instantiation Object Yes Target strategy and layout for generated output.

Parameters

Each parameter declares a key that the template may reference, its type, validation constraints, and presentation hints for the collection form.

Field Type Required Description
key String Yes Variable name to inject into templates.
type Enum No One of string, integer, boolean, array, object. Defaults to string.
required Boolean No Marks the parameter as mandatory. Defaults to false.
default Any No Fallback value when none is provided. Must match type.
validation Object No Strict constraints evaluated before instantiation.
ui Object No Presentation metadata used by Blindata to render the form.

Validation

The validation object, constraints are evaluated against the value supplied by the user before the template is rendered. This object stays in parameters sections.

Field Applies to Description
allowedValues Scalar types Value must equal one of the listed entries.
format Strings Well-known JSON-Schema-style formats (hostname, uri, email, …).
pattern Strings Regular expression the value must match.
min Numbers, strings, arrays Minimum numeric value or minimum length / item count.
max Numbers, strings, arrays Maximum numeric value or maximum length / item count.

UI

The ui object drives how Blindata lays out the parameter form during instantiation and in the Parameters tab of the blueprint detail page. All fields are optional strings.

Field Purpose
group Splits the form into sections using a /-separated path (e.g. Networking / Firewall). Ungrouped parameters are rendered after every grouped section.
label Short title displayed next to the input. When absent, Blindata falls back to key.
description Helper text shown as caption or inline help.
formType Suggests the control style. Combine it with type and validation to drive the rendered widget.

Supported formType values per parameter type:

type Supported formType Notes
string text (default), textarea, dropdown Use dropdown with validation.allowedValues for fixed choices; textarea for multi-line input.
integer number (default), text text still coerces to integer before submit.
boolean checkbox, switch Omit formType to use the default two-state style.
array json (default), stringList stringList renders a row/line-based editor for string arrays.
object json (default) Renders a structured / JSON editor.

Protected resources

protectedResources declares paths (files, directories, or globs) that must stay immutable in the instantiated data product repository. This protects core infrastructure definitions or scaffolding from accidental edits.

Field Type Required Description
path String Yes Path relative to the repository root, or a glob (e.g. infrastructure/**).
integrity Object No Cryptographic digest recorded at instantiation time for tamper detection.
integrity.algorithm String Yes (if integrity is set) Hash algorithm (e.g. sha256).
integrity.value String Yes (if integrity is set) Lowercase hex-encoded digest.

integrity is omitted from the source manifest and populated automatically on the copy stored in the instantiated data product repository.

Composition

Composition lets a parent blueprint reference one or more child blueprints (“modules”). The manifest explicitly maps which values flow from the parent to each child — there is no implicit global scope, exactly like Terraform modules.

Field Type Required Description
module String Yes Logical alias for the child module; referenced by instantiation.compositionLayout and instantiation.targets.
blueprintName String Yes Identifier of the child blueprint.
blueprintVersion String Yes Target release version of the child blueprint.
parameterMapping Object No Maps child parameter keys to literals or to parent parameter keys.

Instantiation strategies

The instantiation block declares where the generated output is written.

Field Type Required Description
strategy Enum Yes monorepo (single target repo) or polyrepo (multiple target repos).
compositionLayout Array No Maps each composed module to a directory in the target repo (monorepo + composition).
targets Array Conditional Required when strategy: polyrepo. One entry per deployment slice.

When polyrepo is used, the parent repository name is not a manifest parameter: it is supplied at instantiation time by the user. The platform derives every target repository by concatenating that runtime name with the repositoryNamePostfix declared in each targets entry.

targets entries support two mutually exclusive shapes depending on whether composition is in use.

Field Type Required Description
repositoryNamePostfix String Yes Suffix appended to the runtime parent name to derive the target repository.
createPolicy Enum No create_if_missing or must_exist. Whether Blindata may create the repository.
module String Conditional Polyrepo + composition: must match a composition[].module.
sourcePath String Conditional Polyrepo without composition: path inside the blueprint checkout.
targetPath String Conditional Polyrepo without composition: destination path inside the derived repo.

Repeat the same repositoryNamePostfix on multiple entries if several slices should land in the same derived repository.


Manifest examples

All examples below are source blueprint manifests using spec: odm-blueprint-manifest and specVersion: 1.0.0. Parameter lists are abbreviated; production manifests should declare every input the templates reference.

Monorepo, no composition

A single target repository, parent output only. No composition and no extra instantiation keys beyond strategy.

spec: odm-blueprint-manifest
specVersion: 1.0.0
name: analytics-lakehouse
displayName: Analytics Lakehouse Blueprint
version: 1.0.0
description: Provisions storage and compute defaults for an analytics data product.

parameters:
  - key: environment
    type: string
    required: true
    validation:
      allowedValues: [dev, staging, prod]
    ui:
      group: General Configuration
      label: Environment
      description: Deployment stage for this data product.
      formType: dropdown

  - key: retentionDays
    type: integer
    default: 90
    validation:
      min: 1
      max: 3650
    ui:
      group: Storage
      label: Data retention (days)
      formType: number

protectedResources:
  - path: infrastructure/core/**
  - path: README.md

instantiation:
  strategy: monorepo

Monorepo + composition

Child modules are merged into one target repository using compositionLayout. The parent repository name is chosen at runtime; only the directory layout is fixed in the manifest.

spec: odm-blueprint-manifest
specVersion: 1.0.0
name: full-stack-dp
version: 2.1.0
description: Parent blueprint composing storage and serving modules into one repo.

parameters:
  - key: projectSlug
    type: string
    required: true
    validation:
      pattern: '^[a-z][a-z0-9-]{1,62}$'
    ui:
      group: General Configuration
      label: Project slug
      formType: text

  - key: enablePiiMasking
    type: boolean
    default: true
    ui:
      group: Security
      label: Enable PII masking

composition:
  - module: storage
    blueprintName: odm-blueprint-s3-lake
    blueprintVersion: 3.0.1
    parameterMapping:
      bucketPrefix: projectSlug
      encryptAtRest: enablePiiMasking

  - module: serving
    blueprintName: odm-blueprint-api-skeleton
    blueprintVersion: 1.4.0
    parameterMapping:
      serviceName: projectSlug

instantiation:
  strategy: monorepo
  compositionLayout:
    - module: storage
      targetPath: data-plane/storage
    - module: serving
      targetPath: app/serving

Polyrepo, no composition

Output is split across multiple repositories, each derived from runtime parent name + repositoryNamePostfix. Every targets row uses sourcePath / targetPath (no module).

If the user instantiates with parent repository name acme-customer-360, the platform derives acme-customer-360-infra and acme-customer-360-apps from the postfixes below.

spec: odm-blueprint-manifest
specVersion: 1.0.0
name: split-stack-template
version: 0.5.0

parameters:
  - key: awsRegion
    type: string
    required: true
    validation:
      allowedValues: [eu-west-1, eu-central-1, us-east-1]
    ui:
      label: AWS region
      formType: dropdown

instantiation:
  strategy: polyrepo
  targets:
    - repositoryNamePostfix: "-infra"
      createPolicy: create_if_missing
      sourcePath: terraform/
      targetPath: ./

    - repositoryNamePostfix: "-apps"
      createPolicy: create_if_missing
      sourcePath: application/
      targetPath: ./

    - repositoryNamePostfix: "-infra"
      sourcePath: policies/
      targetPath: policies/

The first and third entries share the -infra postfix, showing how multiple slices can land in the same derived repository.

Polyrepo + composition

Each composed module is deployed to its own repository, identified by parent name (runtime) + postfix. Each targets row sets module (no sourcePath / targetPath).

spec: odm-blueprint-manifest
specVersion: 1.0.0
name: mesh-polyrepo-parent
version: 1.3.0

parameters:
  - key: dataDomain
    type: string
    required: true
    ui:
      group: Governance
      label: Data domain
      formType: text

composition:
  - module: ingest
    blueprintName: odm-blueprint-ingest-batch
    blueprintVersion: 2.0.0
    parameterMapping:
      domain: dataDomain

  - module: consume
    blueprintName: odm-blueprint-consumer-api
    blueprintVersion: 1.1.0
    parameterMapping:
      domain: dataDomain

instantiation:
  strategy: polyrepo
  targets:
    - repositoryNamePostfix: "-pipeline"
      createPolicy: must_exist
      module: ingest

    - repositoryNamePostfix: "-api"
      createPolicy: create_if_missing
      module: consume

Reserved parameters

During instantiation, Blindata pre-fills a handful of reserved parameters with values taken from the data product metadata and the current user profile (see the Instantiation Guide for more information).

You do not need to declare them explicitly: if your templates reference any of the reserved keys below, Blindata will bind the corresponding metadata automatically. You can still override the values in the wizard before launching the instantiation.

Reserved key Source Purpose
dpDomain Data Product metadata Business domain the data product belongs to.
dpName Data Product metadata Technical name (lowercase alphanumeric and dashes).
dpFqn Data Product metadata Unique identifier / URN.
dpDisplayName Data Product metadata Human-readable display name.
dpDescription Data Product metadata High-level description.
dpOwnerId User profile Owner username / user identifier.
dpOwnerName User profile Owner display name.