Taking control of WO builds

April 27, 2026

Vermilingua 🦡

For the last few years I've been using the vermilingua maven plugin to build my WO apps and frameworks. It's a plugin I've been working on with the help of our beloved Paul (Hoadley) and it's gotten some attention and lovin' in the last few months, making this the perfect time to start openly mentioning and even recommending it.

Why a new plugin

Initially I really just wanted to fix a couple of things in the wolifecycle plugin, but I soon decided writing a new plugin might be easier — and a little liberating, since it meant more freedom to change things. wolifecycle is a wrapper around the old woproject-ant-tasks which makes it more of an effort to modify, improve and extend, and like a lot of WO and Wonder it carries quite a bit of legacy baggage to accommodate old projects and practices. That's great for those who need that, but since vermilingua is a separate plugin we're free to focus on simplicity and modern, standard projects and be a bit more aggressive with changes. Using plain java also means vermilingua performs builds quite a bit faster.

Notable features and differences from wolifecycle

vermilingua has some changes and improvements compared to wolifecycle. Below are a few I feel worth mentioning, the full list of features and differences can be found in the project's README. There are also always new features and fixes being planned and pondered, these can usually be found in the project's github issues.

Bye bye NEXT_ROOT

Since applications are self-contained bundles that don't need a system-wide WO installation, vermilingua's launch script no longer requires or reads the NEXT_ROOT environment variable. This makes the built apps environment independent and removes a step from WO deployment setup.

Sensible default location for WO bundle resources

By default vermilingua assumes WO projects keep WO bundle resources in src/main/woresources rather than src/main/resources. This creates a clean separation between WO resources and java classpath resources, a separation I can't imagine why wasn't there to begin with.

If you prefer src/main/resources you can configure vermilingua to use that folder, see the project's README for configuration specifics. But I don't think you should.

Simplified and configurable launch script

The woa's config.txt contains configuration for launching the application, currently containing only the familiar parameters jvm, jvmOptions and principalClass. These are the same you'll find in a traditional .woa built by wolifecycle but vermilingua provides more options for setting them:

  1. At project level in build.properties. Example: launch.jvm=/opt/jdk-26/bin/java
  2. At build time using a property. Example: mvn package -Dlaunch.jvm=/opt/jdk-26/bin/java
  3. At app launch time using a property. Example: ./MyApp -launch.jvm=/opt/jdk-26/bin/java

This is very useful when you need to switch between java installations/versions, or if you need to add JVM arguments (which you can do the same way, using the launch.jvmOptions property).

Not just WO

vermilingua is not WO specific. It can build any generic java project and package it as a .woa, making it perfect for building ng-objects projects which are generic java projects by nature.

Simplified bundle structure

Vermilingua generates simpler bundles than wolifecycle. We've removed a lot of redundant, outdated platform-specific files and logic (Rhapsody, Windows, MacOS) making the launch script generic/platform-independent and the built bundle simply:

📁 MyApp.woa
  📄 MyApp
  📄 config.txt
  📄 classpath.txt
  📁 Contents
    📄 Info.plist
    📁 WebServerResources
    📁 Frameworks
      📁 SomeFramework.framework
        📁 WebServerResources
    📁 Resources
      📁 Java
        📄 myapp.jar
        📄 ... [other jars/dependencies]

Should you use it

Sure. If you're maven only and not building .war files for servlet deployment. Try it. If it doesn't work or seems to be missing something you need, let me know, either on the WOCommunity chat (where I always am) or the WOCommunity mailinglist. Or file an issue on the github repo.

Latest commits

🌶 cayenne these look like dead code, no? May 13
🌶 cayenne Update README.md May 12
🌶 cayenne Update README.md May 12
🚀 ng-objects Move actual interface methods above interface default methods May 12
🚀 ng-objects Renamed NGMessageInterface to NGMessage May 12
🚀 ng-objects Accept request content as InputStream instead of a byte array May 12
🚀 ng-objects Deleted NGMessage May 12
🚀 ng-objects Move NGMessage utility logic to NGMessageInterface May 12
🚀 ng-objects Deleted NGMessage's httpVersion field/methods May 12
🚀 ng-objects Deleted NGAdaptorRaw May 12

Latest releases

🤸‍♀️ wonder-slim 8.0.0 Apr 30
🦡 vermilingua 1.1.4 Apr 24
🌿 parsley 1.4.1 Apr 22
🚀 ng-objects 0.1.1 Apr 22
🦡 vermilingua 1.1.3 Apr 15
🦡 vermilingua 1.1.2 Apr 15
🌿 parsley 1.4.0 Apr 8
🚀 ng-objects 0.1.0 Mar 7
🌿 parsley 1.3.0 Nov 15
📜 wonder Wonder 7.4 May 28