CLI tool
ailyProject/aily-builder avatar
ailyProject/aily-builder

Why aily-builder splits Arduino preprocessing into its own command

Faster Arduino compilation CLI. Arduino快速编译工具,小项目提速50%,大项目提速80%! 时间就是金钱,我的朋友!

2,286 stars5 forksTypeScriptGPL-3.0

At a glance

What is it?
aily-builder is an npm-installed command line front end for the Arduino SDK that treats preprocessing as a separate, cacheable stage and hands the compile to Ninja. The interesting part is the shape of its flags, which are aimed at a build farm rather than at a single sketch on a desk.
Who is it for?
Use aily-builder if you build the same firmware in CI, or if you flash the same board family often enough that preprocessing dominates your build time, because the save-result and preprocess-result pair is the one thing it does that a single-shot compile cannot. Do not adopt it as a teaching front end for beginners, where a single compile with a default board is all the concept involved and a staging flag adds a concept instead of removing one.
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 30 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 September 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

compile is one command, and preprocess is a second one you can keep

Most Arduino build front ends have a single verb. aily-builder has two, and the split is the product. A preprocess subcommand does the work that depends on the sketch's includes and macros: it validates the sketch file, extracts macros, parses the board and platform configuration, prepares the build directory, analyses dependencies, generates the compile configuration, and runs prebuild hooks if any are configured. A compile subcommand does the part that depends on the code you actually changed. The two results can be written to a file and handed back, so a build that changes one source file can skip the discovery phase entirely. That is the whole argument for the design, and it is a real one for continuous integration, where the discovery phase is identical across every commit and only the compile differs. It is a weaker argument for a person compiling a sketch on a desk, where the whole cycle is short enough that saving and reloading a JSON file is more work than the phase it saves. The interesting part is that the tool is honest about this: the documentation lists the use cases as CI pipelines, parallel builds, debugging, and performance optimisation, and debugging means inspecting preprocessing results before compilation, which is a developer use case rather than an end-user one.

Ninja is bundled, and the job default is four

The dependency list is short enough to read in full: commander for the command line, fs-extra for files, glob for matching. There is no compiler in there, and no Arduino library manager, because the project is an orchestrator in front of an SDK you already have rather than a replacement for it. A ninja directory sits at the repository root, so the build backend ships with the tool, and compilation is parallel across files with a documented default of four jobs. Parallelism is where the wall clock actually goes on a large sketch, and four is a conservative default that assumes a laptop rather than a build machine, which is consistent with the project also shipping a jobs flag. Macro handling is the other half of the story: the documentation describes a streaming, macro-aware preprocessor directive scanner used for dependency detection, which is a specific claim worth noting because naive include scanning is exactly what produces spurious rebuilds in a project that defines macros in headers. A caveat follows from the design rather than from the documentation. A tool that caches compiled objects is only as correct as its dependency graph, and the accuracy of that graph is the thing to probe before trusting the incremental path, which the documentation does not quantify.

A first build: install, compile, then look at the cache

Installation is a global npm install and the binary name is aily-builder, which the manifest maps to the compiled entry point:

bash
npm install -g aily-builder
aily-builder --help

The basics then look like this, with the board given as a fully qualified board identifier and the parallel job count as a flag:

bash
aily-builder compile sketch.ino --board arduino:avr:uno
bash
aily-builder compile sketch.ino --jobs 8

Before wiring this into anything, the cache subcommand is the informative one to run, because it tells you whether anything is being reused at all. The documentation also offers a dry run for a selective clear, which is the right habit when the question is what a cache clear would actually delete:

bash
aily-builder cache stats
bash
aily-builder cache clear --unused-7 --dry-run

What you should see on a cold machine is a full compile and a cache that starts empty. What you should see on a second run with an unchanged sketch is a build that skips work. If the second run recompiles everything, the dependency analysis is not doing its job and no other flag on this tool will help. For local development from a clone, the documented path is to clone the repository, install, link the package globally and run the help command, which is the ordinary way to test a globally installed CLI without publishing it.

The CI pattern: preprocess once, compile many times

The documented workflow for a pipeline is two commands, where the first writes a result file and the second consumes it:

bash
aily-builder preprocess sketch.ino --board arduino:avr:uno --save-result ./preprocess.json
aily-builder compile sketch.ino --board arduino:avr:uno --preprocess-result ./preprocess.json

There is a matching output switch that prints the preprocess result as JSON for programmatic use, which is what you want when the pipeline rather than the operator needs to read the dependency information. A build matrix is the case this is built for: preprocess once per board configuration, then compile the same discovery result against several code states, or share one result across parallel workers, both of which the documentation names as reasons for the split. A debugging session is the other case, since inspecting preprocessing output before compilation tells you whether a header was found and whether a macro expanded the way you expected, which is a faster way to diagnose a missing symbol than reading a compiler error. The limitation is that the result file is a snapshot, not a lock. Nothing in the documented workflow records which SDK, tool versions or library paths were in effect when the file was written, so a result produced in one container and compiled in another is only correct if both containers agree, and the tool-versions flag exists to pin part of that but the documentation does not describe any validation of the saved result against the current environment.

Four flags decide whether your build objects leave the machine

The compile options include an archive cloud cache with more switches than most of the rest of the tool combined, and they deserve to be read as a group rather than skimmed. A local archive cloud cache directory is configured, then there is a flag to disable restore and generation, a flag for a remote base URL, a flag to stop fetching cached .a archives from that remote, a flag to restrict the tool to the local cache with no remote request at all, and a flag to generate uploadable entries after a successful build. Read together, they describe a two-tier object cache with an opt-in upload path, which is the sort of feature that is genuinely valuable on a locked-down network with a large firmware matrix and genuinely unwelcome anywhere else, because compiled archives are build outputs derived from your source. The documentation does not say what the remote protocol is, how the cache is keyed, how entries are invalidated when a toolchain version changes, or whether the remote is something you host yourself, and those omissions matter more than usual here, because the answers determine whether the cache is safe to enable and whether the archives it carries are yours to move. If you are evaluating the tool, run the local-only configuration first and read the missing documentation as a blocker rather than a detail.

GPL-3.0-only, a single sketch at a time, and no published releases

Three facts about upkeep deserve to sit together. The manifest declares the licence as GPL-3.0-only, which is a different identifier from the permissive licences most embedded tooling carries, and it is the kind of term that needs a decision from whoever owns your distribution chain rather than from the person running the build. The tool's scope is a sketch file, with libraries supplied through a libraries-path that can be given more than once, plus optional build properties, custom macros and board options; it is not a project manager, it has no dependency resolution of its own, and nothing in the documented command set corresponds to managing a multi-board project. And the repository publishes no GitHub releases at all, so the version you get is whatever npm serves, with the manifest currently reading 1.2.17. For a tool whose whole advantage is caching, an unversioned release history is the practical gap, since a cache built by one version is not obviously safe for another and there is no changelog to check against. The repository description advertises large speedups for small and large projects alike, and the readme states that compilation speed exceeds the Arduino CLI and is superior to PlatformIO, but the repository contains no benchmark table, no hardware description and no measurement script, so treat the numbers as a claim to test on your own sketches rather than a property of the tool. The last push was on 2026-08-31, so the code is being worked on.

Where it sits against a single-shot compile and against PlatformIO

The readme positions this tool between two things it names, the Arduino CLI and PlatformIO, in a single line, and it does not explain the difference. What the documented command set does support is a narrower claim. An Arduino CLI compile is one process that discovers, analyses and compiles, which is the right shape for a single sketch and wrong for a pipeline that repeats discovery on every commit; aily-builder's contribution is to make that phase addressable and skippable, and to put a real parallel build behind it. PlatformIO is a different kind of project in the first place, one that owns a project manifest, resolves library dependencies and manages multi-environment builds, so the comparison is not like for like: aily-builder deliberately does not do dependency management, and the libraries-path flag tells you where libraries are rather than fetching them. The practical way to choose is by where the time goes. If your bottleneck is discovery, the staging is the answer. If your bottleneck is fetching and version-pinning a dozen libraries across five boards, this tool is not the answer and the absence of a dependency resolver is not a limitation to work around but the boundary of what it does. If your bottleneck is a single developer waiting on a laptop, both of the above are a distraction and a plain compile is fine.

Editorial conclusion

Use aily-builder if you build the same firmware in CI, or if you flash the same board family often enough that preprocessing dominates your build time, because the save-result and preprocess-result pair is the one thing it does that a single-shot compile cannot. Do not adopt it as a teaching front end for beginners, where a single compile with a default board is all the concept involved and a staging flag adds a concept instead of removing one. Verify four things first: that a local or system Arduino SDK is reachable, since the tool takes an sdk-path and an additional tools-path rather than bundling a compiler; what the archive cloud cache sends to a remote URL and under which licence, since four separate flags control remote fetch, remote generation and local-only operation; whether the default board and default job count suit your hardware, because the documented defaults are arduino:avr:uno and four jobs; and which version you installed, because the package manifest reads 1.2.17 while the repository publishes no releases to pin against. The licence identifier is GPL-3.0-only, which matters if you redistribute a modified copy. The last push was on 2026-08-31.

Frequently asked questions

How do I install aily-builder and compile a sketch?

Install it globally with npm install -g aily-builder, then run a compile subcommand against your .ino file with a board identifier, for example aily-builder compile sketch.ino --board arduino:avr:uno. The default board in the documented options is arduino:avr:uno and the default job count is four.

What does the preprocess subcommand do in aily-builder?

It performs the discovery stage without compiling: validating the sketch, extracting macros, parsing board and platform configuration, preparing the build directory, analysing dependencies, generating the compile configuration, and running prebuild hooks if configured. Results can be printed as JSON or saved to a file and passed back to compile with the preprocess-result option.

What is the archive cloud cache in aily-builder?

It is a two-tier cache of compiled object archives with an opt-in remote path. The compile options include a local cache directory, a remote base URL, flags to disable restore and generation, to stop fetching from the remote, to use the local cache only, and to generate uploadable entries after a successful build. The documentation does not describe the remote protocol or the cache key.

Does aily-builder manage library dependencies?

No. Libraries are pointed at with a libraries-path option that can be given multiple times, and the tool does not resolve or pin them for you. Additional build properties, custom macros and board options are also passed in as flags.

How is aily-builder licensed and how often is it released?

The package manifest declares the licence as GPL-3.0-only. The repository has no published GitHub releases, so the version comes from npm, where the manifest currently reads 1.2.17. The last push to the main branch was on 2026-08-31.

Official sources

  1. ailyProject/aily-builder on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
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/ailyproject-aily-builder.svg)](https://hysenlabs.com/projects/ailyproject-aily-builder)