Mainsail: a Vue front end for Klipper that runs from a browser or a container
Mainsail is the popular web interface for managing and controlling 3D printers with Klipper.
At a glance
- What is it?
- The most widely deployed Klipper interface, built as a static Vite bundle that Moonraker can serve directly or that nginx can serve from a multi-stage Docker build.
- Who is it for?
- Mainsail is the sensible default if you run Klipper and want a browser instead of an LCD screen, and it is a particularly good fit for a printer farm because the multi-printer support and the Docker path are both first-class. It is the wrong choice if you want a desktop application or need offline control of a printer with no network at all, since the interface assumes it can reach Moonraker's API.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Vue, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A Vue app that compiles down to static files
The architecture is the first thing to understand about Mainsail, because it determines how you install and update it. The repository is Vue with Vite, and the package manifest sets the package as private with an ES module type. The build script is the giveaway:
npm run build
npm run serve`build` runs the Vite build and then a second script that zips the output directory, producing a distributable archive rather than only a build artifact. `serve` runs the dev server. That zip is what makes the project easy to deploy: Mainsail is a static bundle of HTML, JavaScript and CSS, with no server-side component of its own.
What it talks to is Moonraker, the HTTP API that Klipper's author maintains alongside the firmware. Mainsail's own description is that it makes Klipper more accessible by adding a lightweight, responsive web user interface. So the division of labour is clean: Klipper owns motion control, Moonraker owns the HTTP and websocket API, and Mainsail is the browser client for that API.
The default branch is `develop`, which is unusual for a repository whose releases are tagged from it, and worth knowing if you clone the wrong branch and wonder why your checkout differs from the running interface.
Building the Docker image with its health check and unprivileged port
The Dockerfile is a three-stage build and it says something about the maintainer's priorities. The builder stage is `node:20-alpine`, which runs `npm ci` and then the build:
RUN apk add zip
RUN npm ciThe `apk add zip` line is not incidental: the build script shells out to `zip` when producing the archive, so the tool has to exist in the image or the build fails.
The second target is `nginx-unprivileged`. It runs as the `nginx` user rather than root, and the config is rewritten from the checked-in `nginx.conf` with a sed pass that swaps port 80 for 8080. The comment in the Dockerfile explains why: to set the port above 1024 so the container can run as a non-root user. The third stage is the plain `nginx:stable-alpine` variant for people who want root inside the container.
Both runner stages define a health check with the same shape:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -qO- http://127.0.0.1:8080/healthz >/dev/null || exit 1That means there is a `/healthz` endpoint served from the frontend, so an orchestrator can tell a working Mainsail container from one that is up but not answering. For a service you run on a printer that sits on a shelf for months, having a real health signal is worth the extra line in the Dockerfile.
The features aimed at people running more than one printer
The feature list is long, but it separates into printer-farm concerns and single-printer quality of life. The farm side starts with the Printer Farm support for multiple 3D printers, then the Job Queue, which lets you queue several jobs and add them directly from your slicer. Statistics answer the question a farm operator actually asks, which is how much time each printer has been in use and how many jobs succeeded or failed.
The single-printer side is where the interface earns its reputation. A File Manager deletes, renames and uploads G-Code and config files, and a File Editor edits G-Code and config in the browser with syntax highlighting. Print History lists previous prints and their status. A G-Code Viewer renders your print in 3D so you can watch progress, and multi-webcam support gives you several angles on the same build. Timelapse recording is handled by a separate project, `moonraker-timelapse`, which Mainsail links rather than reimplements.
Bed Mesh Visualisation is worth calling out because it uses `@jaames/iro` as a dependency, an interactive 3D library, to draw the bed as a mesh graph rather than a flat heatmap. Alongside it, a temperature preset manager, power control for relays and TP-Link and Tasmota devices, macro management, a configurable dashboard, custom theming with logos and CSS, and extra sensors on the temperature graph.
One feature carries its own warning in the README: Exclude Objects, which excludes parts of a print, is marked as not officially supported by Klipper yet. Read that as a work in progress that happens to be switched on, not as a documented capability.
Localization covers 12 languages, maintained through Weblate rather than by pull request, which is the pattern that keeps a UI project translating at all once it passes a handful of contributors.
Test setup that says how the project is maintained
The tree contains `cypress/`, `cypress.config.ts` and a `tests/` directory, and the package manifest wires three distinct test commands. The end-to-end test builds the app, previews it, and drives Cypress against a local server:
npm run test
npm run lintThere is a separate `test:ui` for opening Cypress interactively and a `test:unit` that runs Vitest, so the project mixes component-level unit tests with full browser end-to-end tests. For an interface that talks to a live printer API, end-to-end coverage is the only kind that catches the failures that actually happen, such as a websocket that stops reconnecting.
Other files in the root describe an unusually documented workflow. `AGENTS.md`, `CLAUDE.md` and an `agent_docs/` directory sit alongside `CONTRIBUTING.md` and a `.prettierrc`, which means the project now instructs automated coding agents as well as human contributors. `cliff.toml` and `cliff-release.toml` configure generated changelogs, and the `changelog` script shells out to `git cliff` to regenerate `CHANGELOG.md` from tagged commits. Formatting and linting are enforced through scripts rather than left to contributors' own editors.
Version 2.19.0 in the manifest matches the most recent release tag, and the last push was on 2026-09-26, so the source tree and the shipped release are in step. The license is GPL-3.0, which is the norm for this ecosystem but does constrain redistribution of a modified bundle.
Where Fluidd comes up, and why the comparison is close
Search traffic around this project repeatedly pairs Mainsail with Fluidd, the other widely used Klipper interface, and both appear in the project's own comparison lists in search results. The honest summary is that they solve the same problem with different emphases, and the deciding question is usually deployment rather than features.
The structural difference is visible in what each project is. Mainsail is a Vue and Vite application that ships as a zip you can drop into Moonraker's web directory, and the repository treats the containerised nginx path as a first-class target. That combination suits a Raspberry Pi running Moonraker, where you want to unzip a release and restart nothing. A versioned Docker image suits someone running a fleet of printers who would rather pin a tag than copy files.
Where Mainsail leans toward breadth is the farm and queue story: multiple printers, job queue, print history and per-printer statistics in one interface. That is the case to evaluate first, because a single-printer user will find either project adequate and the difference will not matter to them.
There is also a hosted remote mode at `my.mainsail.xyz`, described in the README as remote mode, which lets you reach the interface over the internet rather than only your LAN. That solves the convenience problem of checking a print from outside the house, and it introduces a question about exposing a printer control interface to a network you do not own. Mainsail's sponsor links and the partner section point at BIGTREETECH as the mainboard partner, which tells you who the project is aimed at commercially as well.
Two things the repository does not settle
First, some of the README badges still point at the old repository location. Several badge image URLs reference `meteyou/mainsail` rather than `mainsail-crew/mainsail`, including the last commit, repository size and Patreon badges. The project itself now lives under the mainsail-crew organisation, and the README text credits meteyou as the primary developer, so the two are consistent facts about an organisational move rather than a contradiction about the code. It does mean some badge images may render stale or not at all.
Second, the README does not document the API contract Mainsail depends on. Everything the interface shows comes from Moonraker, and Moonraker's endpoints and websocket message shapes are not described in this repository. Anyone embedding Mainsail, scripting against the same API, or debugging a broken panel will end up reading Moonraker's documentation instead, and the Mainsail docs site is the place to start. The same applies to Klipper itself: the configuration files Mainsail edits are Klipper's, and the interface is careful to label the Exclude Objects feature as unsupported by the firmware rather than presenting it as settled.
That split is the honest shape of the project. Mainsail is a well-tested client with a broad feature set and a real deployment story, and it deliberately holds no printer logic of its own, which is why it stays compatible when Klipper moves.
Editorial conclusion
Mainsail is the sensible default if you run Klipper and want a browser instead of an LCD screen, and it is a particularly good fit for a printer farm because the multi-printer support and the Docker path are both first-class. It is the wrong choice if you want a desktop application or need offline control of a printer with no network at all, since the interface assumes it can reach Moonraker's API. Two details deserve a look before you commit. The repository is licensed GPL-3.0, which matters if you intend to rebrand or resell a bundled interface. And it now ships AGENTS.md, CLAUDE.md and an agent_docs directory alongside a Cypress suite, so the project is documenting itself partly for automated coding agents as well as people. Install by pointing Moonraker's web directory at a release zip, or build the Docker image if you would rather not hand a browser static files.
Frequently asked questions
What is Mainsail for Klipper printers?
Mainsail is a browser-based user interface for Klipper firmware, built with Vue and Vite. It talks to Moonraker, the API Klipper ships with, and gives you a printer farm view, job queue, file manager, G-Code viewer, bed mesh visualisation and print history instead of a small character LCD.
How do I install Mainsail on my Klipper printer?
The setup documentation at docs.mainsail.xyz/setup is the authoritative path, and the repository deliberately keeps the README to links rather than duplicating it. In practice you either point Moonraker at an unpacked release zip or run the Docker image, which builds with node and serves the static bundle from nginx with a health check on /healthz.
Is Mainsail or Fluidd the better Klipper interface?
They cover the same ground, so decide on deployment. Mainsail builds as a static zip for Moonraker's web directory and ships a Dockerfile for people who would rather pin a container image. If you run several printers, Mainsail's printer farm, job queue and per-printer statistics are the parts to try first.
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/mainsail-crew-mainsail)