prettierd keeps a warm Prettier process so your editor does not pay startup cost
prettier, as a daemon, for improved formatting speed.
At a glance
- What is it?
- prettierd is a small TypeScript daemon that wraps Prettier, built on core_d.js, and it exposes formatting over standard input so editor plugins can call it without paying Node startup on every save. It is a narrow tool with a clear purpose and a small configuration surface.
- Who is it for?
- prettierd suits developers who format on save in Vim, Neovim, Sublime Text or Zed and who feel Node startup on every keystroke-triggered format. It does not suit a CI pipeline or a one-shot script, where a plain Prettier invocation is simpler and leaves no daemon behind.
- Can I use it commercially?
- Yes. ISC 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 10 days 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
The problem is process startup, not formatting speed
Prettier is fast at formatting, but invoking it from an editor usually means launching a fresh Node process, loading the parser, and exiting again. On format-on-save that cost is paid repeatedly, on every save, for every file. prettierd's description puts it plainly: prettier, as a daemon, for improved formatting speed.
The project is written in TypeScript and sits on top of core_d.js. The package publishes a single binary named prettierd, and the whole design follows from that one choice.
The audience is narrow and well defined: developers who already use Prettier, already have a formatter plugin wired into their editor, and want the format-on-save path to be cheaper. It is not aimed at teams that need a formatter on a build server, where the process cost is amortised across a whole run anyway.
Formatting happens over standard input, with the filename as an argument
The contract with the daemon is small and worth reading carefully, because every editor integration in the documentation is a variation on it. The prettierd script always takes the file on standard input, and the file name as a positional parameter:
$ cat file.ts | prettierd file.tsTwo details matter here. The name is passed on the command line as well, because Prettier needs it to decide which parser to use and to resolve ignore rules and configuration, while the content arrives on standard input so the daemon can reuse an already running process. The stdout of the daemon is the formatted result, which is what an editor plugin writes back to the buffer.
For a plugin that supports the standard Prettier flags, the equivalent is to pass the file name with the stdin-filepath flag, as the Sublime Text Fmt example does:
{
"rules": [
{
"selector": "source.ts",
"cmd": ["prettierd", "--stdin-filepath", "$file"],
"format_on_save": true,
},
],
}The filename is what tells the daemon which language it is looking at. A wrapper that sends content without a name has nothing to go on.
The bundled Prettier and your local Prettier are two different paths
The dependency list in package.json names prettier at 3.9.5 and core_d at 6.1.1, with optional dependencies on @babel/parser and @typescript-eslint/typescript-estree. The packaged binary therefore carries a Prettier of its own, which is the source of the one genuinely confusing decision in the project.
The local instance rule is short: if you have prettier installed locally in your package, prettierd uses that one. Otherwise it uses the bundled copy. Most parsers ship with prettierd, including JavaScript, TypeScript, GraphQL, CSS, HTML and YAML, so the common case works without extra work.
Since version 0.12.0 the daemon can also invoke your local version of Prettier directly, and the guidance is to rely on that rather than waiting for new languages to be added to prettierd. Plugins work the same way: install the plugin, then reference it in your Prettier configuration.
{
// ... other settings
"plugins": ["@prettier/plugin-ruby"],
}If you want to forbid the bundled copy entirely, the environment variable PRETTIERD_LOCAL_PRETTIER_ONLY with any truthy value, `true` or `1` for example, restricts the daemon to the local package. The README does not document what happens when the local Prettier is missing while that variable is set, so treat it as a hard switch rather than a fallback.
Two environment variables control the whole configuration surface
prettierd does not have a configuration file of its own. Everything is driven by two environment variables, which is a genuine design decision rather than an omission.
PRETTIERD_DEFAULT_CONFIG takes the exact path of a Prettier configuration file and uses it as the default configuration. That matters for editors that do not pass configuration on the command line, and the Vim example sets it inside a Lua table:
local prettier = {
formatCommand = 'prettierd "${INPUT}"',
formatStdin = true,
env = {
string.format('PRETTIERD_DEFAULT_CONFIG=%s', vim.fn.expand('~/.config/nvim/utils/linter-config/.prettierrc.json')),
},
}The second, PRETTIERD_LOCAL_PRETTIER_ONLY, was covered above. Together they mean that a user moving between editors can carry one configuration file and one environment variable rather than reconfiguring Prettier in each editor, and that a shared machine can be pinned to a single Prettier version by setting the variable in a shell profile.
The flip side is that a daemon is a long-lived process, and a long-lived process reads its environment at start. The documentation does not explain how the daemon reloads environment variables, so a change to PRETTIERD_DEFAULT_CONFIG may require restarting the daemon before it takes effect.
Each editor needs its own wiring, and the Zed path is absolute
The editor integration section is the longest part of the documentation, and reading it shows how much of the work lands on the user. Neovim users are pointed at the LSP client via efm-langserver, or at prettierme for direct integration with other editors, or at plugins such as formatter.nvim and vim-codefmt configured in stdin mode:
require('formatter').setup({
logging = false,
filetype = {
javascript = {
-- prettierd
function()
return {
exe = "prettierd",
args = {vim.api.nvim_buf_get_name(0)},
stdin = true
}
end
},
}
})Sublime Text has two routes, a dedicated Prettierd Format package that enables format-on-save for anything Prettier supports, and Fmt for per-language scopes. Zed requires language_overrides entries with a format_on_save command for each language, and the example hardcodes an absolute path to the binary:
{
"language_overrides": {
"TypeScript": {
"format_on_save": {
"external": {
"command": "/opt/homebrew/bin/prettierd",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
}
}
}That absolute path is the most fragile point in the whole setup. A Homebrew prefix that differs, a Linux install, or a binary somewhere else on the path will simply fail, and the documentation's advice is to check with which prettierd. For editors other than these, the author states plainly that he does not know much and invites pull requests, which is an honest marker of where support ends.
A daemon is a long-lived process, and that is where the risk sits
The failure mode of this kind of tool is not a crash during formatting but a stale or mismatched daemon surviving a configuration change. If a project upgrades its local Prettier, a daemon started before the upgrade may keep serving the older version, and the symptom is formatting that disagrees with what the project expects. There is no documented command for restarting or inspecting the daemon, and no health check or status endpoint in the documentation.
There is a second, quieter risk in the local Prettier path. Because the daemon resolves the local package per invocation, a repository that has not installed Prettier at all falls back to the bundled copy, which is a different version from what the project would use on the command line. In a monorepo where directories have different Prettier versions, the daemon will pick up whichever local installation it finds for a given file.
Set against that, the tool is small and easy to remove. The repository holds src, bin, a tsconfig.json, a package-lock.json, a .prettierignore and a .npmrc, and the build is a plain TypeScript compile. The package publishes only bin, dist, LICENSE and README.md, and declares Node 22 or newer as its engine requirement.
Release cadence is steady, and the licence is permissive
Maintenance looks healthy on the evidence available. The repository is not archived, and the last push was on 2026-10-13. The three most recent tagged releases are v0.29.0 and v0.28.0, both on 2026-07-26, and v0.27.0 on 2026-02-07, with the current package.json version at 0.29.0.
The licence is ISC, one of the shortest permissive licences, and the package.json records the same value in its license field. The third party surface is small: core_d, prettier, and the two optional parser packages. There is no build of native code to compile, since the build script is tsc -b, which means an upgrade across a major Prettier version is a matter of reinstalling the package rather than rebuilding a toolchain.
The repository also carries a CHANGELOG.md, a CLAUDE.md and a .github directory, and the package scripts include a prepare hook that runs the build, a run script for the daemon, a start script that passes the start argument, and prettier:check and prettier:fix scripts for the project's own source. The project formats itself with Prettier, which is a reasonable default for a tool whose entire purpose is to front-run Prettier.
Editorial conclusion
prettierd suits developers who format on save in Vim, Neovim, Sublime Text or Zed and who feel Node startup on every keystroke-triggered format. It does not suit a CI pipeline or a one-shot script, where a plain Prettier invocation is simpler and leaves no daemon behind. Before adopting it, check that your formatter plugin can pass the file path on standard input, decide whether the daemon should use your local Prettier or the bundled one, and verify the path to the prettierd binary in Zed, where the configuration hardcodes an absolute path such as /opt/homebrew/bin/prettierd.
Frequently asked questions
How do I install prettierd?
Install it globally from npm with `npm install -g @fsouza/prettierd`, or use Homebrew with `brew install prettierd`. The package requires Node 22 or newer, and npm ships with Node.
How do I make prettierd use my project's own Prettier version?
If prettier is installed locally in your package, prettierd uses that version, and otherwise it falls back to the copy bundled with the package. Setting the environment variable PRETTIERD_LOCAL_PRETTIER_ONLY to a truthy value such as `true` or `1` restricts the daemon to the local install only.
Which languages does prettierd support out of the box?
Many parsers ship with prettierd, including JavaScript, TypeScript, GraphQL, CSS, HTML and YAML. Since version 0.12.0 it can also invoke your local version of Prettier, so plugins such as @prettier/plugin-ruby work once installed and listed in the Prettier configuration.
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/fsouza-prettierd)Was this useful?