Model or dataset
ludwig-ai/ludwig avatar
ludwig-ai/ludwig

Ludwig: a YAML-first framework for LLM fine-tuning and tabular models

Low-code framework for building custom LLMs, neural networks, and other AI models

11,758 stars1,216 forksPythonApache-2.0

At a glance

What is it?
Ludwig turns model training into a declarative config file: one YAML block describes the base model, adapter and trainer, and one command runs the job. It fits teams that want PyTorch-level control without writing the training loop.
Who is it for?
Adopt Ludwig if your team already runs PyTorch workloads and wants LLM fine-tuning, PEFT adapters and tabular or multimodal models driven by a config file instead of a hand-written training loop. Skip it if you need a stable 1.0 API surface, since pyproject.toml still declares Development Status 4 - Beta, or if your workflow depends on a GUI.
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 last received commits 15 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

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

Editorial analysis

The problem Ludwig solves, and who ends up using it

Training a model in plain PyTorch means writing the same scaffolding every time: dataset loading, tokenization, a training loop, checkpointing, metric logging and an inference path. That code is rarely the interesting part of the project, and it drifts between teams. Ludwig replaces it with a configuration file. The README describes the project as a declarative deep learning framework for LLMs, multimodal models and tabular AI, and the pitch is that you train, fine-tune and deploy models using a YAML config and zero boilerplate Python.

The intended user is not a researcher who wants to modify attention kernels. It is an engineer or data scientist who already knows what model they want and would rather spend the day on data than on the loop. The examples directory backs this up: alongside llm_finetuning and llm_instruction_tuning there are folders for anomaly_detection, calibration, class_imbalance, kfold_cv and forecasting. That spread suggests Ludwig is aimed at people who move between problem types and do not want to relearn a training stack each time.

The trade-off is real. A config-driven framework can only express what its schema exposes. If your idea needs a custom loss that sits outside the trainer, or a data pipeline that does not map onto input_features and output_features, you are back in Python, now fighting a layer of indirection you did not write.

How the config, features and trainer fit together

A Ludwig run has three moving parts visible in the README examples. The top-level keys describe the model: model_type, base_model, adapter, quantization, prompt and trainer. Then input_features and output_features declare the columns of your dataset and what encoder or decoder handles each one. Finally, a backend block decides where the work runs.

The feature list is the part that differs most from a hand-written script. Each entry names a column and a type, and the type determines the encoder. In the multimodal example the README shows a text column routed to a bert encoder next to a star_rating column, so a single model can consume a review and a numeric score together. For LLM work the input is simpler: a prompt column and an output column, with a prompt.template string that formats the instruction, input and response sections before tokenization.

On the training side, trainer.type selects the algorithm rather than a flag. The README lists finetune for supervised fine-tuning and dpo, kto, orpo and grpo for alignment, with adapter.type covering lora, dora and vera. That naming is the core abstraction: swapping dpo for finetune is a one-line edit, and the framework supplies the corresponding objective. The backend block, shown as type: local in the examples, is where Ray and the serving shims attach when you move off a single machine.

Installing Ludwig and running a first fine-tune

Installation is a pip install with optional extras. The README gives three variants: core, full for all optional dependencies, and llm if you only need fine-tuning. Python 3.12 or newer is required, and pyproject.toml pins torch>=2.11 and transformers>=5.0, so a modern environment is assumed rather than optional.

bash
pip install ludwig[llm]

With the package in place, write a config file. The README's instruction-tuning example uses a LoRA adapter on a Llama base model with three epochs. Keep the file small on the first run; you can add quantization and scheduler settings once the pipeline works.

yaml
model_type: llm
base_model: meta-llama/Llama-3.1-8B
adapter:
  type: lora
trainer:
  type: finetune
  epochs: 3
input_features:
  - name: instruction
    type: text
output_features:
  - name: response
    type: text

Gated models need a token in the environment before training starts. The README exports HUGGING_FACE_HUB_TOKEN and then points the dataset flag at a hosted dataset, ludwig://alpaca, rather than a local CSV. If your data is local, pass the path to your own file with the same --dataset flag.

bash
export HUGGING_FACE_HUB_TOKEN="<your_token>"
ludwig train --config model.yaml --dataset "ludwig://alpaca"

What you should see is a training run driven entirely by the YAML: the base model loads, the LoRA adapter is attached, and progress is reported through the usual console output. The README does not document how to resume an interrupted run, so treat a long fine-tune as something you plan around rather than restart mid-way.

Where the declarative approach gets in the way

The clearest limitation is API stability. pyproject.toml still carries the classifier Development Status :: 4 - Beta, and the release history shows a steady 0.17.x line through mid-2026. Config keys have moved across minor versions, and the README's own What's New table for 0.16 lists additions such as PiSSA and EVA initializers, TinyLoRA, OFT, HRA and VBLoRA adapter types, and a native Optuna executor. That pace is good for capability and bad for anyone pinning a config they expect to run unchanged for a year.

Security posture is another place to look at the release notes rather than the feature list. Version v0.17.8 is labelled as a path traversal fix in dataset archive extraction. That is a fix, not a defect in the current release, but it tells you the dataset loading path has had at least one archive-handling issue worth tracking if you accept datasets from outside your team.

Finally, Ludwig is the wrong tool when the model is not the bottleneck. If your task is a handful of rules over a few thousand rows, or a gradient-boosted model on tabular data that already meets the target, the install weight of torch, transformers and the rest is hard to justify. The framework earns its place when you are fine-tuning something large or combining modalities, not when you are fitting a small classifier.

Ludwig against writing the training loop in plain PyTorch

The honest alternative is not another low-code tool. It is a Hugging Face Transformers training script or a PyTorch loop you own. The difference is where the flexibility lives. With a script, every decision is explicit: you write the collator, the optimizer, the scheduler and the checkpoint logic, and you can change any of them without asking whether the framework exposes a key for it. With Ludwig, those decisions are schema entries, and the ones that are not exposed are simply not available.

What you get in return is comparability. Two teams running the same Ludwig config are running the same pipeline, which is difficult to guarantee across two hand-written scripts. The README's config-generation feature, ludwig generate_config, pushes this further by having an LLM draft the YAML from a task description. Treat that as a starting point for review, not an authority: a generated config still has to be checked against the schema and your data columns.

The choice usually comes down to how often you change the training internals. If you tune the loop weekly, own it. If you fine-tune models on a schedule and want the recipe stored next to the dataset, the config file is the better artifact.

Licence, maintenance and the cost of upgrading

Ludwig is Apache-2.0, and the LICENSE file sits at the repository root alongside a NOTICE file. For most teams that means permissive use, including in commercial products, with the usual obligations around attribution and the NOTICE contents. The project is hosted by the Linux Foundation AI & Data, which the README states directly. This is a description of the licence and the hosting arrangement, not legal advice; if you redistribute Ludwig inside a product, have your own counsel read the LICENSE and NOTICE.

Maintenance is visible. The last push to the default branch was on 2026-09-07, and releases v0.17.7 through v0.17.9 landed between July and August 2026. The repository is not archived. That is a healthy cadence, but it also defines your upgrade cost: expect to re-read RELEASES.md before bumping the pin, because minor releases in this line have added and changed config keys. The pyproject.toml dependency floor of torch>=2.11 and transformers>=5.0 means an upgrade can pull a large part of your environment with it, so test in a separate environment rather than in place.

Editorial conclusion

Adopt Ludwig if your team already runs PyTorch workloads and wants LLM fine-tuning, PEFT adapters and tabular or multimodal models driven by a config file instead of a hand-written training loop. Skip it if you need a stable 1.0 API surface, since pyproject.toml still declares Development Status 4 - Beta, or if your workflow depends on a GUI. Before committing, verify that your Python and torch versions satisfy requires-python >=3.12 and torch>=2.11, and read RELEASES.md for the current 0.17.x notes.

Frequently asked questions

How do I install Ludwig?

Install it with pip. The README gives three variants: pip install ludwig for the core, pip install ludwig[full] for all optional dependencies, and pip install ludwig[llm] for LLM fine-tuning only. Python 3.12 or newer is required.

Which Python version does Ludwig require?

Python 3.12 or newer. pyproject.toml sets requires-python to >=3.12 and lists only Python 3.12 under the Programming Language classifiers.

Does Ludwig support LoRA and QLoRA fine-tuning?

Yes. The README lists LoRA, DoRA and VeRA under adapter.type, with PiSSA available through the LoRA initializer, and 4-bit QLoRA through a quantization block with bits: 4.

Official sources

  1. License: Apache-2.0
  2. ludwig-ai/ludwig 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/ludwig-ai-ludwig.svg)](https://hysenlabs.com/projects/ludwig-ai-ludwig)