Blog

Victor Campos

July 07, 2026

Spread the word


Share your thoughts

MatchBox includes a native web runtime for building small, fast BoxLang web applications without requiring a JVM or a traditional servlet container. You can follow the MatchBox open beta at https://github.com/ortus-boxlang/matchbox. There are two related pieces in the beta today: a webroot server for .bxm templates and static assets, and a routed app server built around web.server(). Both are early, but they show the direction clearly: BoxLang should be able to serve HTTP from a compact native runtime when the application does not need the full JVM stack.


πŸ—οΈ Two Ways to Serve

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  MatchBox Native Web Runtime                      β”‚
β”‚                                                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚     Webroot Mode            β”‚  β”‚    App Server Mode       β”‚   β”‚
β”‚  β”‚  matchbox --serve           β”‚  β”‚    web.server()          β”‚   β”‚
β”‚  β”‚                             β”‚  β”‚                          β”‚   β”‚
β”‚  β”‚  - .bxm template files      β”‚  β”‚  - Explicit routing      β”‚   β”‚
β”‚  β”‚  - Static asset serving     β”‚  β”‚  - Middleware pipeline   β”‚   β”‚
β”‚  β”‚  - Familiar request scopes  β”‚  β”‚  - JSON APIs             β”‚   β”‚
β”‚  β”‚  - Quick start, no config   β”‚  β”‚  - WebSockets            β”‚   β”‚
β”‚  β”‚                             β”‚  β”‚  - Webhook helpers       β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                   β”‚
β”‚       Built on: matchbox-server crate (Axum + Tokio)             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“„ Webroot and BXM Templates

The webroot server is the quickest path to get BoxLang serving HTTP. Point MatchBox at a directory and it serves .bxm files plus static assets:

matchbox --serve --port 8080 --webroot ./www

BXM files are HTML-like templates that MatchBox transpiles ahead of time into BoxLang bytecode. A template such as:

<bx:output>Hello #user.name#!</bx:output>

is lowered into normal output calls that the VM executes efficiently. The same .bxm templating language you know from BoxLang JVM works here - interpolation with #, <bx:output>, <bx:if>, <bx:loop>, includes, and all the standard template tags.

The webroot runtime injects familiar request scopes into each request:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               Injected Request Scopes                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ url          β”‚ Query string parameters                      β”‚
β”‚ form         β”‚ POST body fields                             β”‚
β”‚ cookie       β”‚ Request cookies                              β”‚
β”‚ session      β”‚ In-memory session state                      β”‚
β”‚ cgi          β”‚ Server and request metadata                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The repo includes a web server example with the following pages:

  • index.bxm - session persistence and dynamic output
  • about.bxm - CGI scope and loops
  • contact.bxm - URL parameters and conditional logic
  • styles.css - served as a static asset alongside templates

There is also a starter template to scaffold a new project:

https://github.com/ortus-boxlang/matchbox-web-server-template


πŸ›£οΈ Routed Apps with web.server()

For applications that need explicit routing, middleware, APIs, or webhooks, the app server exposes a clean BoxLang API:

import boxlang.web

app = web.server()

app.get( "/api/hello/:name", ( event, rc, prc ) -> {
    event.renderJson( {
        "message": "Hello " & rc.name
    } )
} )

app.listen( 8090 )

The Request Collections

Every route handler receives three arguments:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Handler Arguments                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ event        β”‚ Request and response helpers (render, redirect...) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ rc           β”‚ Public request collection:                         β”‚
β”‚              β”‚   - Route params  (:name, :id, etc.)              β”‚
β”‚              β”‚   - Query string params                            β”‚
β”‚              β”‚   - Form fields                                    β”‚
β”‚              β”‚   - Top-level JSON body keys                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ prc          β”‚ Private request collection:                        β”‚
β”‚              β”‚   - Middleware-set values                          β”‚
β”‚              β”‚   - Internal state not exposed to the client       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Middleware

Middleware uses a fourth next argument to build request pipelines:

app.use( ( event, rc, prc, next ) -> {
    prc.requestStarted = true
    next.run()
} )

What the App Server Supports Today

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Native App Server Capabilities (Beta)            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Route groups                           β”‚ βœ…                β”‚
β”‚ Middleware pipeline                    β”‚ βœ…                β”‚
β”‚ Cookies                                β”‚ βœ…                β”‚
β”‚ In-memory sessions                     β”‚ βœ…                β”‚
β”‚ JSON responses (renderJson)            β”‚ βœ…                β”‚
β”‚ HTML responses (renderHtml)            β”‚ βœ…                β”‚
β”‚ Static asset mounts                    β”‚ βœ…                β”‚
β”‚ Explicit template rendering            β”‚ βœ…                β”‚
β”‚ Signed webhook helpers                 β”‚ βœ…                β”‚
β”‚ WebSocket listeners                    β”‚ βœ…                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”Œ WebSockets

The beta also includes a WebSocket listener model built around lifecycle methods. Listener classes define:

class MySocketListener {

    function onConnect( channel ) {
        channel.sendText( "Welcome!" )
    }

    function onMessage( message, channel ) {
        channel.broadcast( "Echo: " & message )
    }

    function onClose( channel ) {
        // cleanup
    }

}

Channels support sending text, JSON, bytes, broadcasting to all connected clients, and explicit close operations. That gives MatchBox a path for small real-time apps, live dashboards, and collaborative experiments - without pulling in a large server stack.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    WebSocket Channel API                          β”‚
β”‚                                                                   β”‚
β”‚  channel.sendText( message )    - Send a text frame              β”‚
β”‚  channel.sendJson( struct )     - Serialize and send JSON        β”‚
β”‚  channel.sendBytes( binary )    - Send raw bytes                 β”‚
β”‚  channel.broadcast( message )   - Send to all connected clients  β”‚
β”‚  channel.close()                - Close the connection           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🧱 Under the Hood

The native web server is powered by the matchbox-server crate, which is built on Axum and Tokio - Rust's most battle-tested async web infrastructure. Your BoxLang application code runs on top of that, with the fiber scheduler handling concurrency at the VM level.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    MatchBox Server Stack                           β”‚
β”‚                                                                   β”‚
β”‚   BoxLang Application Code (.bxs / .bxm)                         β”‚
β”‚              β”‚                                                    β”‚
β”‚              β–Ό                                                    β”‚
β”‚   MatchBox VM (fiber scheduler, bytecode execution)               β”‚
β”‚              β”‚                                                    β”‚
β”‚              β–Ό                                                    β”‚
β”‚   matchbox-server crate                                           β”‚
β”‚              β”‚                                                    β”‚
β”‚              β–Ό                                                    β”‚
β”‚   Axum  (HTTP routing, middleware, WebSockets)                    β”‚
β”‚              β”‚                                                    β”‚
β”‚              β–Ό                                                    β”‚
β”‚   Tokio (async I/O runtime)                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

No JVM. No servlet container. No Undertow or Jetty. The whole stack ships as a single compact binary.


πŸ” Where This Fits

MatchBox web is not trying to replace the BoxLang JVM ecosystem. ColdBox, CommandBox, servlet containers, and the JVM runtime remain the mature path for full-stack production applications that need the complete ecosystem.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Which Runtime for Which Use Case?                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ MatchBox Native Web          β”‚ BoxLang JVM (ColdBox / MiniServer)β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Small APIs                   β”‚ Full-stack MVC applications        β”‚
β”‚ Lightweight microservices    β”‚ Enterprise apps with Java interop  β”‚
β”‚ Webhook receivers            β”‚ ColdFusion CFML compatibility      β”‚
β”‚ Edge-style apps              β”‚ Full module ecosystem (ForgeBox)   β”‚
β”‚ Static + dynamic pages       β”‚ Complex ORM / datasources          β”‚
β”‚ WebSocket experiments        β”‚ Production-hardened deployments    β”‚
β”‚ Native binary deployment     β”‚ Servlet container integrations     β”‚
β”‚ Tiny container images        β”‚                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

⚠️ Beta Boundaries

This is open beta software. Some APIs may change as the app-server surface hardens.

One important distinction from the ESP32 embedded web profile: the native server has significantly more capability than what is available on a microcontroller. On ESP32, MatchBox intentionally supports a smaller route-driven profile and rejects heavier features at compile time. A web app that works on the native server may need to be simplified before it can run on a device.


πŸš€ Where to Start

Option 1: Webroot with BXM templates

# Scaffold from the starter template
git clone https://github.com/ortus-boxlang/matchbox-web-server-template myapp
cd myapp

# Serve it
matchbox --serve --port 8080 --webroot ./www

Option 2: Explicit routes with web.server()

// app.bxs
import boxlang.web

app = web.server()

app.get( "/", ( event, rc, prc ) -> {
    event.renderHtml( "<h1>Hello from MatchBox</h1>" )
} )

app.get( "/api/status", ( event, rc, prc ) -> {
    event.renderJson( { "ok": true, "runtime": "matchbox" } )
} )

app.listen( 8080 )
matchbox app.bxs

Use the webroot mode for dynamic BXM pages and server-rendered content. Use web.server() when you want explicit routes, JSON endpoints, middleware, or WebSockets.

The interesting part is not just that MatchBox can serve HTTP. It is that BoxLang can now target a compact native web runtime, with the same language moving between scripts, CLI tools, servers, browser bundles, and devices.


πŸ”­ The Bigger Picture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    BoxLang Runtime Landscape                       β”‚
β”‚                                                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚   BoxLang JVM Runtime β”‚    β”‚     MatchBox (Rust VM)      β”‚    β”‚
β”‚  β”‚                       β”‚    β”‚                             β”‚    β”‚
β”‚  β”‚  - Web Servers        β”‚    β”‚  - Native Web  ◄── Here    β”‚    β”‚
β”‚  β”‚  - AWS Lambda         β”‚    β”‚  - Browser (WASM/JS)        β”‚    β”‚
β”‚  β”‚  - Google Cloud Fns   β”‚    β”‚  - WASI Containers          β”‚    β”‚
β”‚  β”‚  - Desktop (Electron) β”‚    β”‚  - Edge Runtimes            β”‚    β”‚
β”‚  β”‚  - Full Java interop  β”‚    β”‚  - Native CLI               β”‚    β”‚
β”‚  β”‚  - All BL modules     β”‚    β”‚  - ESP32 / IoT              β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                   β”‚
β”‚           Same BoxLang language. Different runtimes.              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Explore the project and open issues at https://github.com/ortus-boxlang/matchbox.

Read the full MatchBox docs at https://boxlang.ortusbooks.com/boxlang-framework/matchbox.


Join the Ortus Community

Be part of the movement shaping the future of web development. Stay connected and receive the latest updates on product launches, tool updates, promo services and much more.

Subscribe to our newsletter for exclusive content.

Follow Us on Social media and don't miss any news and updates:

Add Your Comment

Recent Entries

Building Native CLI Apps with MatchBox & Native Fusion

Building Native CLI Apps with MatchBox & Native Fusion

MatchBox makes BoxLang practical for a classic deployment target: the single-file command-line application.

The MatchBox open beta is available at https://github.com/ortus-boxlang/matchbox.

With the MatchBox native target, you can compile a .bxs script into a standalone executable for macOS, Linux, or Windows. The generated binary includes the MatchBox VM core and your compiled BoxLang bytecode. It does not require a JVM, a separate MatchBox install, or any runtime on the target machine.

Jacob Beers
Jacob Beers
July 14, 2026