Javalin without Jetty

If you want to use Javalin with an application server or a servlet container, such as Tomcat, WebLocic, etc, you can use EmbeddedJavalin.createServlet():

@WebServlet(urlPatterns = ["/rest/*"], name = "MyServlet")
class MyServlet : HttpServlet() {
    val javalin = EmbeddedJavalin()
        .get("/rest") { ctx -> ctx.result("Hello!") }

    override fun service(req: HttpServletRequest, resp: HttpServletResponse) {
        javalin.service(req, resp)

The createServlet() method is the same method that Javalin uses internally when attaching itself to Jetty. Jetty server methods like app.contextPath(), app.start(), etc, will throw exceptions if called on EmbeddedJavalin. You have to manually exclude Jetty from your build files if you want to use this approach.


  • You can now easily add WebSocket loggers by calling app.wsLogger(). The method takes a WsHandler, (the same interface as a normal call), and can be used to log events of all types. The logger runs after the WebSocket handler for the endpoint
  • app.enableDebugLogging() now includes extensive WebSocket logging.
  • Fixed a NPE if calling queryParamMap when there was no query string.

Exception mapping

  • You can now add a custom exception handler to override the built-in handler for HttpResponseException
  • The default “Internal server error” for uncaught exceptions now uses the InternalServerErrorResponse instead of a plaintext String
  • ExceptionMapper now takes defaultContentType into account


  • Extended support for wrapped and nested Jetty handlers
  • The SessionHandler is now validated before starting the Server
  • “Jetty is listening on {…}” message now includes the context path


  • You can now get the matched path of an endpoint in an after filter by using ctx.endpointHandlerPath()
  • You can now use the head verb in the ApiBuilder
  • Added support for double extensions for templates (like .html.ext)
  • Added missing @Nullable/@NotNull annotations
  • The onBinaryMessage WebSocket handler now throws Exception
  • The CORS options method is no longer managed by the AccessManager

Thanks to all contributors

This release was created with the help of ten different contributors (!) If you want to get involved, head on over to