# textlint: Pluggable Linting for Markdown and Prose

> textlint applies ESLint's rule-and-config model to natural language, shipping with no rules of its own. It is a good fit when you want a specific writing convention enforced in CI, and the wrong tool when you want a general grammar checker.

**textlint/textlint** — textlint is the pluggable linter for natural language text.

- Repository: https://github.com/textlint/textlint
- Website: https://textlint.org
- Stars: 3,192 · Forks: 168
- Language: TypeScript
- License: MIT
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/textlint-textlint

## The problem textlint solves, and who it is for

Spell checkers and grammar services read a document and return suggestions. textlint does something narrower and more mechanical: it parses a document, walks the result, and reports violations of rules you installed. The README describes it as similar to ESLint, but for natural language. That comparison is the whole design. ESLint has no opinions until you add plugins; textlint has no opinions until you add rules. The README states it directly: textlint has no default rules.

The audience follows from that. If you maintain a documentation set, a README, a book manuscript in Markdown, or a blog with a style guide, and you already run a linter in CI, textlint slots into the same habit. You decide that the word "utilize" is banned, that headings must not end in a colon, that a term must be spelled one way throughout, and you encode it. The tool then fails the build when the rule is broken. It is for people who want a specific convention enforced repeatedly, not for people who want someone else's idea of good English.

## How textlint works: rules, plugins and the config file

textlint separates three kinds of package. A rule inspects text and reports problems. A plugin supplies a parser or a set of rules for a file format. A formatter turns the results into output. The README lists Markdown and plain text as supported by default, with HTML and other formats added through processor plugins such as textlint-plugin-html.

Configuration lives in .textlintrc, loaded as JSON, YAML or JS through the rc-config-loader package. The rules key maps a rule name to true, false, or an options object. Setting a rule to false disables it; passing an object sends those options to the rule. Plugins are listed under a plugins array, and a rule belonging to a plugin is addressed as plugin-name/rule-name, which can also be switched off from the same rules block.

The README shows that command-line flags and config are interchangeable. Running textlint with --rule no-todo --rule very-nice-rule README.md is equivalent to running it in a directory whose .textlintrc.json lists both rules. That equivalence matters when you are debugging: if a rule fires locally but not in CI, the config file is the first place to look, because the CLI flag and the file are two spellings of the same thing.

## Installing textlint and running a first rule

The README gives npm as the install path and states one requirement: Node.js 20 or higher. Run node -v if you are unsure. The README recommends a local install rather than a global one, and warns that a globally installed textlint needs every rule installed globally too, and a local install needs every rule installed locally. Mixing the two scopes is the most common way to get a rule that silently never runs.

The example below installs textlint and one rule into the project, then asks textlint to generate a config from the rules it can see.

```bash
npm install --save-dev textlint textlint-rule-no-todo
npx textlint --init
```

The --init flag creates a .textlintrc.json file. According to the README, the generated file looks like this:

```json
{
    "rules": {
        "no-todo": true
    }
}
```

With that file in the current directory, pointing textlint at a file lints it. The README's own example targets README.md, and the tool loads .textlintrc.json from the current directory automatically:

```sh
npx textlint ./README.md
```

Glob patterns work too, but the README is explicit that you must quote them. The example given is npx textlint "docs/**". Unquoted globs are expanded by the shell before textlint sees them, which changes which files are checked. For a first real use, install textlint-rule-no-todo, run --init, and lint one Markdown file. If nothing is reported, add a line containing the literal string TODO to the file and run it again; that is the fastest way to confirm the rule is actually loaded.

## Where textlint stops being the right tool

The absence of bundled rules is a design decision with a real cost. A fresh install reports nothing. There is no baseline quality check, no useful default, and no signal that the tool is working at all until you have chosen and installed at least one rule. For a one-off cleanup of a single document, that overhead is hard to justify; a human editor or a grammar service will get you further with less setup.

Scope confusion is the second failure mode, and the README warns about it rather than hiding it. Because rules are ordinary npm packages resolved at runtime, a rule installed in a different scope from textlint is not found. The symptom is not an error message about a missing rule in every case; it can simply be a rule that never reports. If you are debugging a rule that appears to do nothing, check where it was installed before you check its configuration.

The third constraint is that --fix is only as good as the rule behind it. The CLI exposes --fix and --dry-run, and the README describes --dry-run as showing the result without changing the file. But the README does not document rollback, and it does not guarantee that every rule implements a fixer. A rule that only reports will leave --fix with nothing to do. Run --dry-run first on a large corpus and read the diff before letting it write.

## textlint compared with Vale and with grammar services

Vale is the closest alternative in spirit, and the difference is in how rules are written and distributed. Vale defines style rules in its own YAML-based configuration format, so a rule is a data file you can write without touching JavaScript. textlint rules are npm packages that export a rule object, which means writing a rule means writing code in the same language as the rest of the project. That is a real trade-off in both directions. A team comfortable with npm gets versioning, publishing and dependency resolution for free, and can share a rule the same way it shares any other package. A team that wants to hand a style guide to a technical writer without a build step will find Vale's configuration-only approach shorter to adopt.

Against hosted grammar services, the difference is narrower and more obvious: textlint runs locally, reads your files, and reports deterministically. The same input produces the same output on every machine. It has no model of what you meant to say. It will not catch a sentence that is grammatical but wrong, and it will happily flag a correct sentence that violates a convention you wrote down. That is the point. It enforces the convention, not the language.

## Maintenance, release cadence and licence

The repository is not archived, and the last push was on 2026-08-01. Releases follow a versioned cadence: v15.7.0 on 2026-05-14, v15.7.1 on 2026-05-18, and v15.8.0 on 2026-08-01. The project is a pnpm workspace managed with lerna, and the root package.json exposes scripts for linting, type-checking and a multi-stage test run that covers packages, examples, integration tests and the website. Upgrading the core tool is a version bump in package.json; the larger cost sits in the rules, which are separate packages with their own release schedules and their own compatibility with the current major version.

The licence is MIT. That permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. Nothing here is legal advice, and if you redistribute textlint inside a product, the notice requirement is the part to read carefully. Because rules are independently published packages, each rule carries its own licence, which may differ from the core. Check the licence of every rule you add rather than assuming MIT across the board.

## Conclusion

Adopt textlint if your prose lives in a repository and you want a chosen convention checked on every commit, and if you are willing to pick and configure each rule yourself. Do not adopt it expecting a general grammar checker out of the box; the README states plainly that textlint has no default rules, so an empty config lints nothing. Before committing, verify three things: that your Node.js version is 20 or higher, that every rule you list in .textlintrc.json is installed in the same scope as textlint itself, and whether the rules you pick support --fix, since the CLI exposes the flag but each rule decides what it can repair.

## FAQ

### What is textlint used for?

It lints natural language text by applying rules you install, in the same way ESLint applies rules to JavaScript. The README describes Markdown and plain text as supported by default, with other formats added through processor plugins.

### Is linting the same as formatting?

No. textlint reports violations of rules and, for rules that implement a fixer, can rewrite the file with --fix. Formatting is a separate concern, and the repository uses prettier for formatting files rather than textlint.

### What is a lint rule in textlint?

A rule is an npm package that inspects parsed text and reports problems. textlint ships none of them, so the README notes you install each one separately, for example textlint-rule-no-todo, and enable it in .textlintrc.json.

### What is a textlint alternative if I do not want to write JavaScript rules?

Vale is the closest alternative. It defines style rules in its own YAML-based configuration instead of npm packages, so rules can be written without code. textlint's rules are packages that export a rule object.

## Sources

- [Official documentation](https://textlint.org)
- [Official README](https://github.com/textlint/textlint#readme)
- [Project repository](https://github.com/textlint/textlint)
- [Release notes](https://github.com/textlint/textlint/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/textlint-textlint
