How do .proto imports and JSON Schema $ref translate to Schema Registry references? How do you register a schema that depends on another?
answer
- Reference = {name, subject, version}
- name = import path (proto) or $ref URL (json)
- Register leaves first, parent last
- google/protobuf/* built-in, don't register
- JSON Schema = Draft-07
basics
~20 sEach imported .proto or $ref'd JSON Schema is registered as its own subject/version, then the dependent schema declares schema references: a list of {name, subject, version} so the registry can resolve the import. Register the dependencies first, then the parent with its references array.
solid answer
~50 sBoth Protobuf import and JSON Schema $ref are supported via Schema Registry schema references. A reference is a {name, subject, version} triple stored alongside the parent schema. For Protobuf, name is the import path used in the .proto (e.g. "google/protobuf/timestamp.proto" or your "common/address.proto"); for JSON Schema, name is the URL/identifier used in the $ref. You register dependencies bottom-up: register the referenced schema under its own subject first, then register the parent passing references:[{name, subject, version}]. The registry validates that every import/$ref resolves. The Maven/Gradle Schema Registry plugins automate this with a references block per schema. With CSFLE/normalization aside, referenced schemas are de-duplicated and independently evolvable. Common built-ins like google/protobuf/* and confluent/meta.proto are provided by the serializer and need not be registered. Use auto.register.schemas carefully — auto-registration of references can register transitive deps in dependency order.
code
json · 9 lines// Register the child first: subject "common.address"
// Then register the parent with a references array:
{
"schemaType": "PROTOBUF",
"schema": "syntax = \"proto3\"; import \"common/address.proto\"; message User { string name = 1; common.Address address = 2; }",
"references": [
{ "name": "common/address.proto", "subject": "common.address", "version": 1 }
]
}go deeper
Know that imports/$refs become registry references and dependencies are registered separately.
Explain the {name, subject, version} triple and bottom-up registration order.
Map .proto import paths and JSON $ref strings to the name field, and reason about version pinning and built-ins.
Design a shared-type governance model: common-types subjects, reference versioning policy, auto-register-off in prod, and compatibility across the reference graph.
## What a schema reference is A **schema reference** lets one registered schema point at another registered schema instead of inlining it. It is stored in the registry as part of the parent schema's registration, as an array of objects with three fields: - **name** — the identifier the *parent* uses to refer to the dependency, in the parent's own syntax. - **subject** — the registry subject under which the dependency is registered. - **version** — the specific version of that subject to bind to. ## Protobuf: `import` A `.proto` file references another with `import "path/to/other.proto";`. When you register the parent, each `import` path becomes a reference whose **name** is exactly that import string, **subject** is wherever you registered the imported `.proto`, and **version** pins it. Example: a `User` message importing `common/address.proto` -> reference `{ name: "common/address.proto", subject: "common.address", version: 1 }`. **Built-in imports** like `google/protobuf/timestamp.proto`, `google/protobuf/wrappers.proto`, and Confluent's `confluent/meta.proto` / `confluent/type/decimal.proto` are bundled with the serializer (`protobuf-provider`) and are resolved automatically — you do **not** register them as subjects. ## JSON Schema: `$ref` JSON Schema (Confluent uses **Draft-07**) composes schemas via `$ref`, e.g. `{ "$ref": "https://example.com/address.json" }` or a relative `{ "$ref": "address.json" }`. The **name** of the reference is the `$ref` string/URL, **subject**/**version** point at the registered child schema. At resolution time the registry assembles the full schema so validation can run. ## Registration order (bottom-up) Because a parent cannot resolve unregistered dependencies, you register **leaves first**: 1. `POST /subjects/common.address/versions` with the address schema. 2. `POST /subjects/<topic>-value/versions` with the User schema and a `references` array binding `common/address.proto` (or the `$ref`) to `common.address` v1. The registry validates that all references resolve before accepting the parent. ## Tooling The **Confluent Schema Registry Maven plugin** (`schema-registry:register`) and the **Gradle plugin** let you declare a `references` block per schema and register in dependency order automatically. `auto.register.schemas=true` will auto-register the parent and, with reference auto-registration, its transitive deps — convenient in dev, discouraged in prod (you want governed, reviewed registration). ## Why references over inlining - **De-duplication / reuse**: shared types (Address, Money, Timestamp) live once and many schemas bind to them. - **Independent evolution**: the child evolves under its own subject and compatibility rules; consumers pinned to a version are unaffected until they re-pin. - **Smaller payloads of governance**: the registry stores the graph, not N copies. ## Edge cases - **Version pinning**: a reference binds a specific version; bumping the child does not auto-upgrade parents — you re-register the parent against the new version. - **Circular imports** are not allowed. - **Compatibility**: changing a referenced schema is checked under that child subject's compatibility level; the parent's compatibility is evaluated with references resolved. - For Protobuf, the `import` path string must match the reference `name` exactly or resolution fails.
- Do you need to register google/protobuf/timestamp.proto as its own subject before importing it?No. Common well-known types (google/protobuf/*) and Confluent's confluent/meta.proto are bundled with the Protobuf provider and resolved automatically; only your own imported .proto files need to be registered as subjects and referenced.
- If you publish a new version of a referenced Address schema, do all parent schemas automatically use it?No. A reference pins a specific version. Parents continue to resolve the pinned version until you re-register the parent with the reference bumped to the new child version (subject to the parent subject's compatibility check).
saying these in an interview costs you the question
- Registering the parent before its dependencies — resolution fails because the referenced subject/version doesn't exist yet.
- Saying imports/$refs are inlined into one big schema at registration — the registry stores references and resolves them on demand.
- Manually registering google/protobuf/* — these are bundled built-ins.
- Claiming a reference floats to the latest child version — it pins an explicit version.