Package and release audio plug-ins
Choose platform runners, validate VST3, Audio Unit and CLAP builds, prepare installers and downloads, and understand hardware delivery limits.
A musician needs a plug-in that installs, opens in their DAW, restores their session and survives an update. Reaching that point takes more than compiling the DSP: build the complete native bundle, validate it on its target platform, package its interface and resources, and test the delivered archive or installer.
Use the same Maru CLI locally and in CI. Pin the toolchain version in your project, install the components for your selected targets, and keep the build, validation and packaging reports alongside the resulting downloads.
Build on the platform you intend to support
VST3 and CLAP are cross-platform APIs. Their compiled binaries are specific to an operating system and architecture. Steinberg documents Windows VST3 binaries as DLLs and macOS VST3 binaries as Mach-O bundles. Sharing a TypeScript project does not make the resulting native file interchangeable between them. Steinberg's SDK requirements list the platform compiler families.
Our recommendation is native CI runners:
| Intended output | Build and validate on | Important boundary |
|---|---|---|
| macOS VST3, AU, CLAP and standalone | macOS, with the selected Apple SDK and architecture | ARM64 and Intel are separate outputs unless a universal binary is deliberately produced and verified. |
| Windows VST3 and CLAP | Windows with the supported Windows SDK and compiler | Test the editor, resources and installed bundles in the Windows hosts you support. |
| Linux VST3 and CLAP | The supported Linux distribution/toolchain | Qualify the native host, UI adapter and runtime dependencies; a Linux build is not established by macOS results. |
| AAX | A supported runner with the authorized Avid SDK and signing workflow | Distribution requires Avid signing and validation in Pro Tools. |
| Hardware | A runner with the exact target compiler, followed by tests on the board | A desktop plug-in binary is not firmware. |
Trigger the complete CI matrix from either macOS or Windows. Each runner builds and tests its own platform's outputs. Cross-compilation still requires matching SDKs, dependencies and target-host tests, so use native runners for releases. Audio Unit and Apple's signing/notarization tools use the macOS runner.
Keep the native bundle intact
On macOS, .vst3, .component, .clap and .app outputs are directory bundles.
The compiled executable is under Contents/MacOS/; the embedded interface may
contain HTML, CSS and JavaScript under Contents/Resources/. Both belong in the
product. Shipping only the UI does not ship the plug-in, and removing it breaks
the editor.
Keep the module's parameters, state, presets and resources with its canonical source. Define a version and stable identity deliberately before release. Use that identity for builds and retain it when testing updates and session recall. Avoid changing public parameter meaning without a planned state migration for already-released sessions.
From your project directory, build and verify the selected formats:
maru --version maru doctor maru module doctor maru plugin build src/index.ts --release --format vst3 --out build/vst3 maru plugin build src/index.ts --release --format au --out build/au maru plugin build src/index.ts --release --format clap --out build/clap maru plugin build src/index.ts --release --format standalone --out build/standalone maru module verify src/index.ts --build-root build
--release selects the release identity and build instrumentation. Apply
Developer ID signing, notarization and installer validation in the packaging
steps below.
maru plugin build --format all builds the project's configured native formats
and records unavailable targets. Set build.nativeFormats in .maru/config.json
to choose them. The default set is VST3, CLAP, AU and standalone; add AAX when
your project supplies its SDK and delivery requirements. This command does not also generate every installer,
SDK package or hardware image. Explicitly choose the output set your project
promises and fail its release when any required output is missing.
Validate what the customer will receive
Inspect the generated build-report.json and the combined module verification
report. Compilation, format validation, signing and installation are separate
results. An unavailable or skipped check is not passing evidence for that feature.
Run the format-owned checks, then exercise audio/MIDI, sample-rate and block-size
changes, both parameter endpoints, presets, save/reopen, bypass and two independent
instances. VST3 uses Steinberg's validator. CLAP has an upstream
CLAP validator. AU uses
Apple's auval and an AudioComponent host. Format checks supplement actual DAW
tests; they do not prove every host or editor behaves correctly.
For a first manual session, follow Testing your VST. Retest the extracted archive or installed payload, including its editor and resources. Keep the output hashes, tool versions and reports for that exact file.
Package downloads and installers
Give customers a small, clearly named download. A module project puts its final
outputs directly in build/ by default:
build/
README.md
macos-arm64/
plugins/ complete native bundles
standalone/ application bundle
installers/ actual installer, when built
archives/ per-format ZIPs
install/ guide, manifest and matching uninstaller
web/
app/ standalone website with playback host
module/ reusable browser module for another host
documentation/ manual, image and release notes
SHA256SUMS
Set build.output.directory in .maru/config.json to choose another output
root. Enable build.output.productDirectory, build.output.versionDirectory,
or both to group handoffs, for example build/meteora/1.0.0/. Both are off by
default; the module folder, bundle metadata and descriptive archive names
already identify the product and version. Paths are relative to the project
root. Internal compiler and staging files stay under .maru/cache/.
Rebuilds safely replace the selected outputs after validation. They do not clean the whole directory first. With version grouping, a new version gets a new folder; source edits at the same unpublished version update its existing folder. Keep published releases immutable in your release storage. A failed attempt preserves the last successful output, and the README identifies the failed attempt separately. Remove old outputs through an explicit cleanup step.
Only list platform/architecture folders that were actually built. Keep compiler output, local caches, credentials and debug logs outside customer downloads. Version archive filenames and include the format, OS and architecture. Preserve bundle metadata, executable modes and links when archiving; use a platform-aware archiver, then extract and compare the resulting payload.
Installers should let musicians select the formats their DAW needs. Derive
installer destinations, manual-install instructions and uninstall paths from
one install plan. Include the matching uninstaller and test upgrades and removal
without deleting presets or unrelated products. An installer XML/script is a
plan; call it an installer only after creating and inspecting its .pkg or
Windows installer executable. Build an unsigned local candidate when supported,
then test the signed distribution package separately.
For macOS downloads outside the App Store, use the appropriate Developer ID signatures, notarize the distribution container and staple where supported. Verify the final signatures and acceptance, including plug-ins loaded inside a DAW. An ad-hoc signature can provide a consistent local seal without providing Developer ID trust or notarization. See Apple's Developer ID guidance and notarization workflow. Use the Windows signing process for Windows delivery; an Apple signature does not sign a Windows binary.
Include the product license, third-party notices, minimum requirements, exact formats/architectures, install/uninstall steps, version, support contact and release notes. Check your distributor's current submission requirements before uploading; a ZIP that works locally is not evidence of marketplace acceptance.
Run GitHub Actions as a native matrix
Use one job per supported OS/architecture, with strategy.fail-fast: false so
one failed row does not cancel the other evidence. GitHub's
matrix documentation
explains runner selection and failure handling. Use explicit runner images and
record the actual architecture; do not infer it from a moving latest label.
Each job needs the pinned project dependency lockfile, Node.js, the exact Maru CLI and component versions, its native compiler/SDK, the required build tools, and compatible validators. Browser qualification also needs its supported Chromium runtime. A headless validator does not replace interactive editor, audio-device, clean-install or hardware tests.
Provision these tools explicitly for the selected lane:
- macOS: Xcode/Command Line Tools and the selected macOS SDK, CMake, Maru's
pinned native compiler components, the VST3 SDK/validator, CLAP SDK/validator,
and Chromium for browser qualification.
auval,codesign,pkgbuildandproductbuildsupply the Apple format and packaging tools; distribution also usesnotarytooland the appropriate signing credentials. - Windows: the supported MSVC/Windows SDK environment, CMake, the pinned native compiler components, Chromium and Windows builds of the applicable validators.
- Linux: the chosen C/C++ compiler, CMake, pinned native components, Chromium, applicable validators and the declared UI/runtime dependencies. Record the distribution and ABI used for the actual host checks.
- Hardware: the exact board SDK/cross-compiler, adapter and emulator or device runner selected by its profile. A CPU architecture match is insufficient.
The public CLI supplies headless build and validation commands, runtime harnesses, fixture loaders and structured reports. Install and verify pinned compiler, browser and validator components explicitly. System and proprietary SDKs and signing credentials are runner inputs.
Run the pipeline in this order:
- Install locked project dependencies and check CLI/component readiness.
- Resolve the requested targets and report missing SDKs/runners early.
- Build and qualify the exact module on each supported runner.
- Package and verify archives and installers on that same platform.
- Retain reports even on failure; expose successful local candidates separately.
- In an explicit release job, apply signing/notarization and publish only the complete required output set.
Call the same public commands in CI as in local builds. Keep platform provisioning and signing in explicit job steps so the workflow is reproducible on a clean runner.
Run untrusted pull-request checks without release credentials. Use a separate release job with narrowly scoped permissions and protected signing credentials. Cache compilers/components by exact CLI, component, OS, architecture and relevant input identity. Cached build bytes are not fresh validation results.
Retrieve and test the outputs
Upload already-created ZIPs, installers, checksums and reports as Actions artifacts. Avoid uploading a raw macOS bundle as loose files: GitHub's artifact action documents that executable permissions can be lost. A prebuilt archive preserves its internal bundle layout. See the artifact action's permission guidance.
For example, after your project's build/package steps have succeeded, a GitHub.com workflow can use a step like this. Adjust the paths to the project's real layout and pin the reviewed action commit in a release workflow:
- name: Retain native download candidates
uses: actions/upload-artifact@v7
with:
name: plugins-${{ runner.os }}-${{ runner.arch }}-${{ github.sha }}
path: |
build/**/archives/*.zip
build/**/installers/*
build/**/SHA256SUMS
if-no-files-found: error
Add a separate report upload using if: always() with the actual report paths;
it must not turn a failed build into a successful release. The upload step alone
does not verify that every requested installer or format exists; the preceding
build/qualification/package gates must enforce completeness.
Download a candidate from the workflow run's Artifacts section, verify its checksum, extract it with a suitable archiver and test that exact payload on its intended OS/architecture. Keep failed-run reports for diagnosis. Actions artifacts have retention limits; stable customer downloads should use an explicit GitHub Release or your delivery service, with versioned files and permanent release notes.
Hardware is a separate delivery target
A hardware project references the same module through a board profile and host adapter. It needs that board's compiler, runtime, resources, control mapping, flash image/package and recovery procedure. Build and emulator results should be kept separately from physical-device qualification.
Choose a board profile from Hardware platforms and profiles, then follow From module to hardware for the project workflow. Use CI to build and emulate the selected target; measured latency, xruns, memory fit, codec/MIDI/control behavior and recovery need the actual device. Flashing or installation is an explicit step. Provide the exact device/profile/version, checksums and recovery instructions when handing an image to a tester; do not offer a desktop VST3 or a generic ARM archive as firmware.
Continue with Publishing for the product release journey and Native plugins for command discovery.