Self-hosted service
foxundermoon/vs-shell-format avatar
foxundermoon/vs-shell-format

shell-format: formatting shell scripts, Dockerfiles and ignore files in VS Code

the shellscript、Dockerfile、properties ...... format extension

550 stars65 forksShellMIT

At a glance

What is it?
The shell-format extension gives VS Code a Format Document command for shell scripts, Dockerfiles, gitignore and dockerignore files, Java properties, JVM options, hosts files, dotenv files and Bats tests, by driving the shfmt binary underneath. It is a thin wrapper, and the interesting decision is which file types it claims.
Who is it for?
Adopt shell-format if you edit shell scripts, Dockerfiles or ignore files and want one consistent formatter across them without configuring a separate tool per language. Do not adopt it expecting a built-in formatter, because the extension is a front end for shfmt and the binary has to be on your machine and pointed at with shellformat.path.
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 Shell, 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

What the extension actually is, and what it delegates

shell-format is described as a formatter for shell scripts, Dockerfile, properties and other file types, and the repository description is a bit more blunt about the scope: the shellscript, Dockerfile and properties format extension.

The dependency list has exactly one entry, shfmt. That single fact defines the whole design. The extension does not contain a shell parser or a formatter of its own. It registers itself as a document formatting provider in VS Code and, when you ask for it to format a document, it runs shfmt on the file and hands the result back.

That is a good trade for this category of tool. Writing a correct shell formatter is a serious undertaking, because shell has enough quoting and heredoc and command substitution edge cases to defeat a naive implementation, and mvdan/sh is a well known Go implementation of the shell parser that already handles them. By delegating, the extension inherits that correctness instead of reimplementing it.

The cost is that you need shfmt installed separately. The extension does not bundle it, and the configuration section tells you how to point at it if it is not on your path, with a full path example for mac and Linux of /usr/local/bin/shfmt and for Windows of a shfmt.exe under a bin directory.

The package description names the file types it covers: shell scripts, Dockerfile, gitignore, dotenv, the hosts file, jvmoptions, and other file types, and the keyword list adds bashrc, zshrc, azure cli tool and bats.

The licence is MIT, the primary language is Shell, the last push was on 2026-10-22, and the recent releases are 7.2.8 and 7.2.7 on 2025-07-15 with 7.2.5 from 2023-02-21.

The file types it claims, and the ones VS Code did not know about

The supported file types table is the most informative part of the README, because half of it is about teaching VS Code what these files are rather than about formatting them.

The list pairs a language identifier with the extensions it covers. shellscript covers .sh and .bash files. dockerfile covers Dockerfile files. ignore covers .gitignore and .dockerignore. properties covers .properties files, java properties files. jvmoptions covers .vmoptions and jvm.options files. hosts covers the hosts file, which the table gives as the absolute path /etc/hosts. And bats covers .bats test files.

The reason the extension bothers to claim these languages is visible in the package.json. The activation events are a list of onLanguage entries for shellscript, dotenv, dockerfile, ignore, hosts, jvmoptions, properties, spring-boot-properties, azcli and bats. VS Code only loads an extension when one of its activation events fires, so an extension that wants to format .bats files has to register for that language id, and if VS Code does not have one, the extension has to contribute it.

The contributes section shows exactly that. There is a language contributed with the id shellscript. The dockerfile language has aliases of docker and Dockerfile, plus filename patterns covering Dockerfile, Dockerfile.* and *.dockerfile, so a file named Dockerfile.prod is recognised. The ignore language has aliases of gitignore and dockerignore, and filenames listing .dockerignore and .gitignore, so those dotfiles are matched by name rather than by pattern.

So the extension is two things at once: a formatting driver for shfmt, and a set of language definitions that make VS Code treat dotfiles and unusual extensions as the languages they are. The second half is what makes the Format Document command appear at all on a .gitignore.

Note that the two extras beyond the documented table are spring-boot-properties and azcli, the Azure CLI tool configuration, which appear in the activation events and in the keyword list even though the README table does not mention them.

Using it, and the two ways to invoke the formatter

The usage section gives two routes, and they cover the two different situations you hit.

The first is a keyboard shortcut, shift with option and f, which is the macOS binding for Format Document. The second is the command palette route, shift with command and p, then type Format Document. The second is the one that works everywhere, and it is the route to remember if the shortcut does not fire on your platform or if you have rebound it.

The configuration section has two settings and nothing else. shellformat.path is the full path to the shfmt binary, with the example given for mac and Linux and for Windows. shellformat.flag is where you pass flags through, and the instruction is to run shfmt -h to see the detailed usage.

That second setting is where the extension becomes useful rather than merely convenient. shfmt has options for indentation style, for switching between tabs and spaces, and for the dialect of shell being targeted, and because the extension passes flags straight through, all of them are available without the extension needing to know about them. The documentation for the flag setting pointing at shfmt's own help rather than duplicating the list is a good sign, because shfmt's flags change over time and a copied list in a README goes stale.

The extension declares itself a document formatting provider, and it is categorised as a Formatter in the marketplace listing, which is how VS Code surfaces it to people browsing for formatting tools rather than by language.

The VS Code engine requirement is 1.36.0 or later, which is an old floor, and that matches the age of the release line rather than suggesting anything is wrong with it.

The marketplace listing and what the numbers say about it

The README carries a dense block of badges, and the ones worth reading are the ones that tell you what kind of project this is.

There is the VS Code Marketplace version, download, install and rating badges for the extension named foxundermoon.shell-format. There is a link to the extension page, which is the canonical way to install it, so the repository is a development home rather than the distribution channel.

The licence situation is shown with two badges, and they are not the same licence. One is the MIT badge, which is the licence the README's own text implies. The other is an Anti 996 badge, a licence created in response to the 996 controversy over Chinese open source licences. A project can only hold both if the MIT terms are compatible with the additional terms of the Anti 996 licence, which requires that the project not be used to discriminate against individuals or groups. For a formatting extension that is largely ceremonial, but it is a deliberate choice by the author and it explains the second badge sitting next to the first.

There is also an Open Collective badge for financial contributors, which is the funding model for the wider vsformat family of extensions, and a star and fork badge pointing at the GitHub repository.

The build and release badges point at two separate workflows, CI and a release or CD workflow, so the extension is built and published by automation rather than by hand.

One more thing the badges make clear: the project has a Gitter chat, which is the support channel for the extension alongside the GitHub issues.

None of this tells you how popular the extension is, and it would be wrong to infer that from badge images alone. What it does tell you is that the project is set up for distribution, funding and ongoing maintenance rather than being a personal script.

How it is built, and the project structure behind a small extension

The repository layout shows a TypeScript extension built with webpack, which is the conventional shape for this kind of VS Code extension.

At the top level there is a src/ directory, a test/ directory, a typings/ directory, a webpack.config.js, a tsconfig.json, a package.json and a yarn.lock. The image/ directory holds the screenshot used in the README, along with logo.png and logo.psd, the latter being the editable source for the marketplace icon.

The development tooling is a familiar set. There is a.husky/ directory for git hooks, a.prettierrc and a.prettierignore so the TypeScript source is formatted consistently, a.vscode/ directory with the launch configuration for debugging the extension, and a.vscodeignore that controls what is excluded from the packaged extension. A.yarnclean file is present, and a renovate.json for keeping dependencies current.

The CI setup is split across two workflows referenced in the README badges, a CI badge and a RELEASE badge, the second pointing at a CD workflow. And there is a CHANGELOG.md.

The Go tooling does not appear in the repository, which is worth noting given the project is about shell. The formatting behaviour lives in the shfmt binary, and this repository is the bridge between that binary and the editor, which is why the dependency is a runtime requirement rather than a build dependency.

The funding arrangement is worth a note because it explains the structure of the project family. The README credits financial contributors on Open Collective, with badges for individuals and ten organisation slots, and a link to a Gitter chat. The organisation is named vsformat, while the marketplace publisher is foxundermoon. The contributors and the financial backers are both credited in the README itself.

Editorial conclusion

Adopt shell-format if you edit shell scripts, Dockerfiles or ignore files and want one consistent formatter across them without configuring a separate tool per language. Do not adopt it expecting a built-in formatter, because the extension is a front end for shfmt and the binary has to be on your machine and pointed at with shellformat.path. Before you install, install shfmt and set shellformat.path to its full path, and read the shfmt flags with shellformat.flag so you can pass options such as indentation style through to the formatter.

Frequently asked questions

What file types does the shell-format VS Code extension support?

Shell scripts with .sh and .bash extensions, Dockerfile files, .gitignore and .dockerignore, .properties files, .vmoptions and jvm.options files, the hosts file at /etc/hosts, .bats test files, and also dotenv, spring-boot-properties and azcli language ids according to the activation events.

Does shell-format need any external tool installed?

Yes, it depends on shfmt. The extension is a front end for that binary, and you point it at with the shellformat.path setting, using a full path such as /usr/local/bin/shfmt on mac and Linux or a shfmt.exe on Windows. The shellformat.flag setting passes options through, with shfmt -h for the list.

How do I run the formatter in shell-format?

With the shift, option and f shortcut on macOS, or through the command palette with shift, command and p and then typing Format Document, which works on every platform.

Why does the shell-format extension contribute its own language definitions?

VS Code only loads an extension when one of its activation events fires, so the extension registers onLanguage entries for shellscript, dotenv, dockerfile, ignore, hosts, jvmoptions, properties, spring-boot-properties, azcli and bats, and contributes language definitions with aliases and filename patterns so files like .gitignore and Dockerfile.prod are recognised.

How is the shell-format extension built and released?

It is a TypeScript extension bundled with webpack, with src, test and typings directories and prettier configuration, husky git hooks, a VS Code launch configuration, and separate CI and release workflows. The marketplace publisher is foxundermoon and the version line is 7.2.x, with 7.2.8 released on 2025-07-15.

Official sources

  1. foxundermoon/vs-shell-format on GitHub
  2. Issues
  3. License: MIT
  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/foxundermoon-vs-shell-format.svg)](https://hysenlabs.com/projects/foxundermoon-vs-shell-format)

Was this useful?