Model or dataset
linkml/linkml avatar
linkml/linkml

LinkML: write the model once, generate every schema flavour

Linked Open Data Modeling Language

667 stars198 forksPythonApache-2.0

At a glance

What is it?
LinkML is a modelling language that lets you describe your data once in YAML and then generate JSON Schema, SHACL, OWL, GraphQL, JSON-LD contexts, Protocol Buffers and Python classes from that single source, which is the part that changes how a schema team works.
Who is it for?
LinkML fits a team that maintains a data model and needs it in several serialisations at once, because the value is in generating JSON Schema, SHACL, OWL, GraphQL, JSON-LD contexts, Protocol Buffers and Python classes from one YAML file rather than maintaining each by hand.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One YAML model, many output formats

LinkML is a linked data modelling language following object-oriented and ontological principles. Models are typically authored in YAML, and can be converted to other schema representation formats such as JSON or RDF. That sentence is the whole pitch, and the examples directory shows how far it goes. For one example organization model, the repository holds the derived Python classes, a JSON Schema, a SHACL shapes file, GraphQL, an OWL file in Turtle syntax, a JSON-LD context, a Protocol Buffers definition and the data serialised in a couple of formats, plus a PersonSchema example and a tutorial directory. The generators are separate command line tools, one per target, and the Makefile wires them together so that regenerating every artefact from a schema is a single make invocation. For a team that has to publish a JSON Schema for an API, a SHACL file for validation and an OWL file for a knowledge graph, the alternative is three artefacts that drift.

The tool and the metamodel live in different repositories

A distinction worth understanding before you read the code. This repository holds the tools for generating and working with LinkML, while the LinkML schema itself, the metamodel, is in a separate repository at linkml/linkml-model. The full documentation is at linkml.io/linkml, and the repository also carries a SPECIFICATION.md, a UML.md document and a ModelChanges.md, which is where you would look for what changed in the language between versions. The consequence is that the metamodel evolves on its own schedule, and this repository has to accommodate that. The Makefile has a target for it, download-metamodel, which clones the latest metamodel from linkml-model, copies the schema yaml files into the test input directory and rewrites the imports in them so the local copy can be used, and there is a separate test-metamodel target that runs the compatibility tests with the slow marker enabled. That is a compatibility suite for the language itself, which is a reasonable thing for a language with a metamodel to have.

The uv workspace, and how the package is laid out

The packaging is a uv workspace with two members, packages/linkml and packages/linkml_runtime, and the tool source configuration points at both as workspace sources, so the runtime and the main package are always installed together. The project requires uv 0.9.17 or newer, and it sets an exclude-newer window of seven days, which is a deliberate reproducibility measure so a fresh resolve does not pick up a release published in the last week. Constraint dependencies pin click and pillow to narrow ranges. The Dockerfile builds on python:3.12-bookworm with uv 0.7.13 installed, runs uv build for all packages, and then a slim-bookworm runner stage that installs the resulting wheel, creates a non-root user and starts a shell. The runtime package is separate for a reason: a generated model that only needs to load and validate data should not drag in the code generation stack.

Building the container image

The Dockerfile is a two stage build, and the split is the point. The builder stage copies the whole source tree, which the comment says is needed for uv-dynamic-versioning, and produces the distributions.

dockerfile
FROM python:3.12-bookworm AS builder
RUN pip install "uv==$UV_VERSION"
RUN uv build --all-packages

The runner stage then copies the built wheels out of the builder and installs them, and the container starts a bash shell as an unprivileged user rather than as root.

dockerfile
FROM python:3.12-slim-bookworm AS runner
RUN pip install /tmp/linkml-whl/*.whl
RUN useradd --create-home linkmluser
CMD [ "bash" ]

The environment variables set in the builder stage are worth noting, since they are the usual suspects when a build behaves oddly: PYTHONFAULTHANDLER, PYTHONUNBUFFERED, PYTHONHASHSEED set to random, pip cache disabled, pip version check disabled and a default timeout of 100. The runner stage sets DEBIAN_FRONTEND to noninteractive and installs gcc, musl-dev and python3-dev, which are there to compile any extension modules that need it at install time.

The generators, one command per output format

The Makefile shows the generator interface clearly, because each derived artefact has its own rule and its own tool. Python classes come from gen-py-classes, and the rule then runs the generated module to prove it imports. SHACL shapes come from gen-shex. JSON Schema comes from gen-json-schema with a type argument. The JSON-LD context comes from gen-jsonld-context, also with a type argument. GraphQL comes from gen-graphql. The rule names are pattern rules keyed on the example name, so a single make target builds every derived product for one example schema, and the all-examples target chains through the set. The commands are run through uv run rather than pipenv run, with a commented-out pipenv line left in place. The pattern is worth internalising because it is how you would wire LinkML into your own build: one generator call per artefact you need, with the schema as the dependency.

Project hygiene, and the parts of the repo that are not code

The repository carries more governance and meta files than a typical tool, and they describe the project as much as the code does. There is a CODE_OF_CONDUCT.md, a CONTRIBUTING.md, a CITATION.cff, an ALUMNI.md, an AGENTS.md, a CLAUDE.md and an AI_COVENANT.md, alongside a .pre-commit-config.yaml, a conftest.py, a .coveragerc and a codecov.yml. The AI_COVENANT.md and the agent instruction files are a newer addition to the ecosystem and tell you that the project expects to be worked on by tools as well as people. There is a .zenodo.json and a DOI badge, which is what you need if you want the project to be citable. The formatting and linting setup is pre-commit plus tox, with the Makefile exposing a lint-fix target that runs the format environment, and black configured with a line length of 120 targeting Python 3.10 through 3.13. A codespell configuration lists words to ignore, with a note that some exemptions are temporary pending fixes upstream in linkml-runtime and linkml-model.

Where LinkML is the wrong choice

Two situations argue against it. The first is a data model simple enough to write once in JSON Schema. If your schema is a handful of objects with no constraints, no ontology and no need for validation rules, then LinkML adds a metamodel, a generation step and a build dependency, and the JSON Schema you would have written by hand is still the thing your consumers read. The second is a team with no appetite for the modelling discipline. LinkML is a language about types, slots, ranges and inheritance, and the value it delivers comes from everyone agreeing on the model rather than on the serialisation. If your organisation already has an established way of describing data, LinkML is a second way to describe it, and second ways cost more than the first. There is also a versioning question to settle early, because the metamodel moves in a separate repository, and knowing how you will track that movement matters when the model is load-bearing.

Editorial conclusion

LinkML fits a team that maintains a data model and needs it in several serialisations at once, because the value is in generating JSON Schema, SHACL, OWL, GraphQL, JSON-LD contexts, Protocol Buffers and Python classes from one YAML file rather than maintaining each by hand. It does not fit a project with a single simple data shape, where a hand-written schema is faster to produce and easier to read, and it does not fit a team that has no appetite for a metamodel, because LinkML models are themselves written against a schema and the metamodel is maintained in a separate repository. Before you start, read SPECIFICATION.md and the UML.md document, install the tool with uv rather than pip so the workspace members resolve correctly, and check the examples/ directory before writing your first model, because the organization example shows what a finished set of generated artefacts looks like.

Frequently asked questions

What is LinkML and what does it generate?

LinkML is a linked data modelling language following object-oriented and ontological principles, with models typically authored in YAML that can be converted to other schema representations. The example directory shows the generated products for one model: Python classes, JSON Schema, SHACL shapes, GraphQL, OWL, a JSON-LD context and a Protocol Buffers definition.

How is the LinkML project packaged?

It is a uv workspace with two members, packages/linkml and packages/linkml_runtime, both resolved as workspace sources. The project requires uv 0.9.17 or newer and excludes releases published in the last seven days so a fresh resolve stays reproducible.

Which command line tools does LinkML provide?

One generator per output format: gen-py-classes for Python classes, gen-shex for SHACL shapes, gen-json-schema for JSON Schema, gen-jsonld-context for a JSON-LD context, gen-graphql for GraphQL, and gen-proto for Protocol Buffers. The Makefile wires them into per-example rules so every derived artefact can be regenerated from the source YAML.

Where does the LinkML metamodel live?

The metamodel is in a separate repository, linkml/linkml-model, while this repository holds the tools for generating and working with LinkML. The Makefile has a download-metamodel target that clones the latest metamodel and rewrites its imports so the local copy can be used by the compatibility tests.

Official sources

  1. License: Apache-2.0
  2. linkml/linkml on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/linkml-linkml.svg)](https://hysenlabs.com/projects/linkml-linkml)

Was this useful?