Open-source project
jruby/warbler avatar
jruby/warbler

Warbler: packaging a Ruby application as a .war or a runnable .jar

Warbler chirpily constructs .war files of your Ruby applications.

900 stars206 forksRubyMIT

At a glance

What is it?
Warbler is a gem that assembles a Ruby, Rails or Rack application into a Java archive, either a servlet war file or a self-contained runnable jar. It suits teams deploying Ruby on a Java application server, or anyone who wants one artifact that runs with java -jar.
Who is it for?
Warbler is a good fit for a team that has to run Ruby on a Java application server, that wants a single deployable artifact rather than a directory of loose files, and that values a configuration file over command line fiddling. It is the wrong tool for a plain Ruby deployment to a normal app server, it is the wrong tool for a project that needs a modern native build, and it is the wrong tool for a stack you have already standardised on a different packaging approach.
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 10 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One command in the application root produces the archive

The getting started sequence is three steps and it assumes you are at the top of your project. You install the gem with gem install warbler, then run warble in the top directory of your application, and then you choose what to do with the result. For a web project you deploy the myapp.war file to your Java application server. For a standalone application you just run it with java -jar myapp.jar. The design goal stated in the documentation is a minimal, flexible, Ruby-like way to bundle up all of your application files for deployment to a Java environment, backed by a sane set of out-of-the-box defaults that should allow most Ruby applications to assemble and work without configuration. What makes Warbler a wrapper rather than a new build system is that the warble command is a small wrapper around Rake with internally defined tasks, which is why the task list is printed with the -T flag and why every feature is a Rake task in disguise. A project that already drives its build through Rake can slot Warbler in without changing the shape of the build.

Features are Rake tasks and they must share one invocation

The features are small Rake tasks that run before the war file is created and manipulate the archive structure. The list of tasks is short enough to read in one go:

code
    warble compiled    # Feature: precompile all Ruby files
    warble config      # Generate a configuration file to customize your archive
    warble executable  # Feature: make an executable archive (runnable + an emb...
    warble gemjar      # Feature: package gem repository inside a jar
    warble pluginize   # Install Warbler tasks in your Rails application
    warble runnable    # Feature: make a runnable archive (e.g. java -jar rails...
    warble version     # Display version of Warbler
    warble war         # Create the project war file
    warble war:clean   # Remove the project war file
    warble war:debug   # Dump diagnostic information

There is a sharp edge here that has cost people an afternoon, and the documentation calls it out explicitly. Feature tasks must be included in the same command invocation and inserted before the war task in order to take effect. Running warble compiled and then warble war as two separate invocations does not compile the sources, because the second invocation does not run the compiled feature and produces a basic war with the sources included. The working form is:

code
    warble compiled war

The alternative is to put the feature in the configuration file so it always applies:

code
   config.features = %w(FEATURE)

How Warbler decides between a war file and a jar

The decision is made by looking at your project layout, and it is worth knowing because it happens silently. War-based projects are for Rails, Merb or Rack-based web applications, and they usually contain a config/environment.rb file, a config/init.rb file or a config.ru file. The presence of those files is what tells Warbler the project is a web application, and therefore that a Java EE compatible war file should be built. Jar-based projects are for standalone Ruby applications, which usually have a launcher script in the bin directory and Ruby code in the lib directory, and Warbler packages the application so that java -jar myapp.jar runs that launcher. If your project has a .gemspec file in the top directory, that file is used to configure the dependencies, the launcher script, the require paths and the files to include in the archive. For best results the gemspec should specify the executables, the require paths and the runtime dependencies added with add_dependency. When there is no gemspec, Warbler guesses the launcher from the contents of the bin directory and uses lib as the lone require path, and in that case all files in the project are included in the archive. That fallback is convenient and it is also a packaging hazard, because a stray file in the project root ends up in your artifact.

Bundler works, except for path components

Support for Bundler is detected through the presence of a Gemfile, and when it applies the gems are packaged into the archive along with the Gemfile itself. The Bundler groups named :development, :test and :assets are excluded by default, unless you specify config.bundle_without in config/warble.rb, which is the right place to change that if your deployment needs one of those groups present. The limitation is specific and stated plainly: Warbler supports Bundler for gems and git repositories, but not for plain path components. When a :path component is found in the Gemfile, Warbler warns and refuses to include it in the archive. That behaviour is defensible, since a path dependency points at a directory that will not exist on the target server, but it means a Gemfile with a local path reference, which is common in a monorepo or a development setup, will not package cleanly without editing. There is also a deprecated and experimental JBundler path, detected by the presence of a Jarfile, which packages the jars into the archive, with the JBundler gem not needed at runtime since the jars are already on the classpath. The documentation marks it as deprecated and experimental, which is a good reason to leave it alone.

Precompiling with jrubyc replaces sources with stubs

The compiled feature is the one with the most surprising output, and it is worth understanding what the archive will contain. It uses jrubyc to precompile all .rb files in the application to .class files and includes those in the war instead of the Ruby sources. The important detail is that the war file will still contain .rb files, but they will be short stubs containing the following code:

code
load __FILE__.sub(/\.rb$/, '.class')

So the archive is not source free, it is source replaced, and a reader who opens the war expecting to find the original Ruby will find stubs. The other two features work on the archive structure rather than the code. The gemjar feature bundles all gems into a single gem file to reduce the number of files in the war, which the documentation says is mostly useful for Google AppEngine where the number of files per application has a limit, and it notes that the feature is not applicable to jar-based applications. The executable feature bundles an embedded web server into the war so that it can either be deployed into a traditional Java web server or run as a standalone application with java -jar myapp.jar, and jar-based applications are executable by default. The runnable feature makes a standard Java runnable war so that you can execute binary bundled gem commands, for example java -jar myrailsapp.war -S rake db:migrate. The documentation also notes that features may form the basis for a third-party plugin system in the future if there is demand, which is an honest way of saying there is not one yet.

The compatibility table is the first thing to read

Warbler publishes a compatibility table that tells you exactly which combinations are supported, and the 2.1 line is the one to look at. The table gives Warbler 2.1 as Maintained, with JRuby 9.4 to 10.1, Java 8 and later, JRuby-Rack 1.2 to 2.0, and Rails 5.0 to 8.0, with a note that Rails 8.1 may be fine with pure Ruby web servers. Below that, 2.0 is marked EOL and covers JRuby 9.2 to 9.3, Java 6 and later, JRuby-Rack 1.1 to 1.2 and Rails up to 6.1, and 1.4 is EOL with much older ranges. The table is the reason to read the release history before pinning a version, since a Warbler that is compatible with your Rails version is a moving target. There is a second compatibility dimension that the documentation flags and that people forget. For running wars with specific Java web servers, it points at the JRuby-Rack compatibility notes, and explains that while Warbler is compatible with multiple JRuby-Rack versions, it does not know your target web server, so you may need to further restrict the JRuby-Rack version yourself. In other words, the container is a variable you still have to pin by hand.

Configuration lives in config/warble.rb and a Rakefile

The repository layout shows a gem rather than a framework, and the pieces are conventional Ruby. There is a warbler.gemspec and a Gemfile, a Rakefile, a bin directory for the executable, a lib directory for the code, an ext directory, a spec directory for the tests and an integration directory, plus a warble.rb file and a web.xml.erb template, which is the standard way to generate the servlet deployment descriptor for a war file. There is also a pom.xml, which is what a Maven-based Java build would consume. The CHANGELOG.md tracks releases, and the licence is MIT, held in a LICENSE.txt file. The documentation says that features may be installed into a Rails application with the pluginize task, which writes Warbler tasks into that application rather than leaving them in a global Rakefile, and that a configuration file can be generated with the config task to customise the archive. The overall shape is a small tool with a small surface, which is exactly what you want from something that sits between your application and a Java deployment target, and it explains why the project is still a modest amount of code after more than a decade of releases.

Editorial conclusion

Warbler is a good fit for a team that has to run Ruby on a Java application server, that wants a single deployable artifact rather than a directory of loose files, and that values a configuration file over command line fiddling. It is the wrong tool for a plain Ruby deployment to a normal app server, it is the wrong tool for a project that needs a modern native build, and it is the wrong tool for a stack you have already standardised on a different packaging approach. Before adopting it, check the compatibility table, because the 2.1 line covers JRuby 9.4 to 10.1, Java 8 and later, JRuby-Rack 1.2 to 2.0 and Rails 5.0 to 8.0, and consult the JRuby-Rack compatibility notes for your specific servlet container since Warbler does not know your target web server. The gem is MIT licensed, the last push was on 2026-10-13, and the most recent release is v2.1.2 from 2026-08-30.

Frequently asked questions

How do I package a Ruby application with Warbler?

Install the gem with gem install warbler, run warble in the top directory of your application, and deploy the resulting myapp.war to a Java application server for a web project, or run java -jar myapp.jar for a standalone application. The warble command is a wrapper around Rake with internally defined tasks.

What is the difference between a war file and a jar file in Warbler?

War-based projects are for Rails, Merb or Rack web applications and are detected by the presence of config/environment.rb, config/init.rb or config.ru. Jar-based projects are for standalone Ruby applications with a launcher script in bin and code in lib, and Warbler packages them so that java -jar myapp.jar runs the launcher script.

Why does warble compiled not precompile my sources?

Feature tasks must be included in the same command invocation and inserted before the war task, so the working form is warble compiled war. Running warble compiled and then warble war as two separate invocations does not compile the sources, and the second invocation creates a basic war with the sources included.

Which versions of JRuby, Rails and Java does Warbler support?

The compatibility table lists Warbler 2.1 as maintained, with JRuby 9.4 to 10.1, Java 8 and later, JRuby-Rack 1.2 to 2.0 and Rails 5.0 to 8.0, with a note that Rails 8.1 may work with pure Ruby web servers. The 2.0 and 1.4 lines are marked end of life.

How does Warbler handle Bundler dependencies?

Applications using Bundler are detected by the presence of a Gemfile, and the gems are packaged along with the Gemfile, with the development, test and assets groups excluded by default unless config.bundle_without is set. Bundler is supported for gems and git repositories but not for path components, which Warbler warns about and refuses to include.

Official sources

  1. Issues
  2. jruby/warbler on GitHub
  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/jruby-warbler.svg)](https://hysenlabs.com/projects/jruby-warbler)

Was this useful?