Unibeautify puts one configuration and one API in front of a crowd of formatters
One Beautifier to rule them all, One Beautifier to clean them, One Beautifier to bring them all and in the darkness sheen them
At a glance
- What is it?
- Unibeautify is a TypeScript library that abstracts several existing beautifiers behind a single interface, so a project written in several languages can configure formatting the same way and call the same API. The interesting parts of the repository are the build scripts, which generate the language list and the type definitions rather than maintaining them by hand.
- Who is it for?
- Adopt Unibeautify if your repository mixes several languages and you want one formatting configuration and one API rather than a separate tool per language, since that is the entire reason the project exists. Skip it if your project is a single language, because a native formatter will be faster and better documented, and if you need the latest formatter features, since the abstraction tracks whatever the underlying tools support.
- Can I use it commercially?
- Yes. MIT 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 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
An abstraction over other formatters
The project describes itself with a line that is a riff on a Tolkien quote: one beautifier to rule them all, one beautifier to clean them, one beautifier to bring them all and in the darkness sheen them.
Underneath the joke, the Why section gives two bullets, and they are the whole pitch. A single beautifier abstracting multiple beautifiers for multiple languages, and unified beautifier configuration options.
So this is not a formatter in the sense that Prettier or clang-format are formatters. It does not parse your code and re-print it. It is a layer above other formatters, and its job is to pick the right one for the file and to give every one of them the same configuration shape.
That solves a real problem in a polyglot repository. The situation is common: a monorepo with TypeScript, JSON, YAML, Markdown, CSS and shell scripts, where each language has its own formatter, each formatter has its own configuration file, and each formatter has its own opinions about which files to touch. The result is a repository with six configuration files, six ignore files and a pre-commit hook that runs six tools.
Unibeautify replaces that with one configuration and one call. The abstracting part is the interesting engineering, because the underlying tools do not agree on anything. Their configuration keys differ, their command line flags differ, some take a config file and some take flags, and some can only be configured by a file in a specific location.
The project is TypeScript, MIT licensed, with the default branch master, the homepage at unibeautify.com and the last push on 2026-10-20. There are no GitHub releases, and the npm package is at version 0.17.1.
Installing the library and the command line tool separately
The install section is short and it splits the two ways you might use the project.
To use the project programmatically with Node.js:
$ npm install --save unibeautifyAnd the command line interface lives in its own repository, Unibeautify-CLI:
$ npm install --global @unibeautify/cliThat split is worth a moment's thought. The library is the thing you depend on when you want to call the beautifier from your own code, from a script, from an editor plugin or from a test. The CLI is a separate package with a global install, because the two have different lifecycles and different audiences. A project that wants to control formatting from a build step depends on the library, and a developer who wants a command to run over a tree installs the CLI globally.
The package names reflect that. The library is the plain unscoped name unibeautify, while the CLI is scoped as @unibeautify/cli, which is the conventional way to keep the namespace tidy when there is more than one package in a family.
The published entry points are set in the package file. The main field points at dist/src/index.js and the typings field at dist/src/index.d.ts, so the compiled output and the type declarations ship together and the TypeScript definitions are available to consumers without any extra setup.
For usage examples, the documentation points at the test/ directory, which is a reasonable choice for a library of this kind. The tests are the executable documentation, and they double as the specification of what the abstraction is supposed to do for each language.
The build generates the language list and the type definitions
The script list in the package file is the clearest view of how the project works, and two of the scripts are the interesting ones.
The build script is:
"build": "npm-run-all compile copy-languages-json update-type-defs",Which is a chain of three steps. The compile step runs tsc, the copy-languages-json step copies src/languages.json into the dist directory, and the update-type-defs step runs a script from dist/scripts.
So the language data is a JSON file in the source tree that is copied into the build output rather than imported, and the type definitions are generated by a script rather than written by hand. The second script in the list shows the second half of that:
"lint": "tslint '{src,test,script}/**/*.ts'",The lint script uses tslint across the src, test and script directories, with a separate lint-fix variant, and there is a tslint.json at the repository root holding the configuration.
The update-type-defs script is the one to look at closely. It runs node dist/scripts/update-type-defs.js against dist/src/beautifier.d.ts, which means the type definitions for the beautifier interface are derived from something rather than maintained directly. The same pattern appears in update-languages, which runs node dist/scripts/update-languages.js against ./src/languages.json.
The reasoning behind that is easy to reconstruct. The set of languages a beautifier abstraction supports is not a small, stable list. It grows as the project adds support for more underlying tools, and each one contributes its own configuration options. Writing that by hand means maintaining a JSON file of every option for every language, and a TypeScript interface that has to agree with it. Generating both from one source removes the possibility of the two drifting apart.
The other scripts support that structure. The dev script runs tsc in watch mode, the clean script uses rimraf to remove the dist directory, and the test script chains a build-test step with jest. The build-test step itself is a chain of clean, compile and copy-languages-json, which is what makes the tests run against a freshly built dist directory rather than against the sources.
There is a prepublishOnly script that runs the build, so a published package is always built from source at publish time rather than relying on a stale dist directory being committed.
Continuous integration across two providers and a lot of small files
The CI arrangement is a mixture of generations, and reading it tells you something about the project's history.
The build badges are Travis CI for Linux and macOS and AppVeyor for Windows, which is the classic combination from the period when AppVeyor was the standard way to test Windows builds on a Linux-hosted service. The test coverage badge is from CodeClimate, and there is a .codeclimate.yml at the root to configure it. The maintainability badge is also from CodeClimate, so the project is measured by that service for both coverage and maintainability.
Those are the older parts. The newer part is the Renovate badge, and renovate.json at the root is the configuration for it. Renovate is a dependency update bot, and enabling it means the dependency tree is kept current automatically by pull requests rather than by a person remembering to check.
The rest of the repository layout is consistent with a TypeScript library of this vintage. There is a .node-version file pinning the Node version the project expects, a .npmignore controlling what is published, a .unibeautifyrc.yml at the root, and a .vscode/ directory with the editor configuration. There is a jest.config.js for the test runner, a tsconfig.json for the compiler, a netlify.toml for the documentation site, a ROADMAP.md, a CODE_OF_CONDUCT.md and a __mocks__/ directory for the mocked modules the tests need.
The .unibeautifyrc.yml is the file that gives the project its dogfooding credential. A beautifier abstraction that formats its own source with its own configuration is a strong statement about the configuration format, because any option that is awkward to express gets found immediately by the author.
The package file also lists the dev dependencies, and among the type packages you can see the shape of the implementation. There are types for jest, for lodash, for js-yaml, for request, for dedent, for diff and for json-stable-stringify. The yaml types point at the configuration format, lodash at the utility work on the options, request at how the underlying formatters are invoked, and diff at how the tests compare output against expectations.
Contributing, and where this fits against a plain formatter
The contribute section is three commands with a comment above each, and the order is the instruction.
# Be sure to lint
npm run lint
# And build
npm run build
# And test
npm testBe sure to lint, then build, then test. That order matters. Linting first catches the cheap problems before the expensive build, the build catches type errors, and the test only runs against a successfully compiled output.
The last point is worth emphasising for a project whose tests run against dist rather than against src. The test script is npm-run-all build-test jest, so the build is part of the test command and a test run cannot pass against stale output. That is a small structural decision that removes a whole class of confusing failures.
Now the comparison with a plain formatter, which is the question any reader will have.
If your project is a single language, use that language's formatter. Prettier for the web stack, rustfmt for Rust, gofmt for Go, clang-format for C. Each of those is faster, better documented, better integrated with its language's tooling, and better at the formatting decisions it makes. An abstraction layer adds a process, and a process is a cost.
The case for Unibeautify is the polyglot repository and the desire for one configuration. If you have one repository with several languages and you want one place to say how code is formatted, and one command to run, then the abstraction earns its cost. The unified configuration is the thing you are actually buying.
There is a second, quieter benefit. A single tool means a single set of ignore rules and a single pre-commit hook, and it means a new contributor does not have to learn six configuration formats to make their first change.
And there is a limitation to weigh honestly. Because the abstraction sits above the underlying tools, its feature set is the intersection of what they support. A language whose formatter has a distinctive option that the abstraction has not modelled is a gap, and the project's answer to that is the update-languages and update-type-defs scripts, which is to say the gap gets closed by writing more code.
So the practical test is whether the languages you care about are covered and whether the options you actually set are modelled. If they are, this saves you real configuration work. If the language you want is not there, then the abstraction is not for you.
Editorial conclusion
Adopt Unibeautify if your repository mixes several languages and you want one formatting configuration and one API rather than a separate tool per language, since that is the entire reason the project exists. Skip it if your project is a single language, because a native formatter will be faster and better documented, and if you need the latest formatter features, since the abstraction tracks whatever the underlying tools support. Verify first which beautifiers are covered by the version you install, that the configuration file is picked up from the path your tool reads, and whether the generated language list and type definitions need refreshing in your build.
Frequently asked questions
What is Unibeautify and why would you use it?
It is a single beautifier that abstracts multiple beautifiers for multiple languages, with unified beautifier configuration options. It is not itself a formatter that parses and re-prints your code; it selects the right underlying tool per file and gives all of them the same configuration shape, which is the point in a polyglot repository that would otherwise need one config file, one ignore file and one hook per language.
How do I install Unibeautify?
To use it programmatically with Node.js, run `npm install --save unibeautify`. The command line interface is a separate package in its own repository, Unibeautify-CLI, installed globally with `npm install --global @unibeautify/cli`. Usage examples are in the test directory, and the published entry points are dist/src/index.js with type declarations at dist/src/index.d.ts.
How is the Unibeautify project built and tested?
The build chains tsc, copying src/languages.json into the dist directory and running a script to update the type definitions from dist/src/beautifier.d.ts, and there is a matching update-languages script that regenerates the language file. The test script runs a build step before jest, so tests always run against freshly built output. Linting uses tslint across the src, test and script directories, and CI is split between Travis CI for Linux and macOS and AppVeyor for Windows, with Renovate keeping dependencies current.
Official sources
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.
[](https://hysenlabs.com/projects/unibeautify-unibeautify)Was this useful?