# Introduction

Welcome to BoxLang: A Modern Dynamic JVM Language built for productivity

<figure><img src="/files/5z2n8nJHwqrTkf9cqtVY" alt=""><figcaption></figcaption></figure>

**BoxLang** is a modern dynamic JVM language that can be deployed on multiple runtimes: operating system (Windows/Mac/\*nix/Embedded), web server, AWS Lambda, Google Cloud Functions, DigitalOcean, iOS, Android, web assembly, and more. BoxLang combines many features from different programming languages, including Java, CFML, Python, Ruby, Go, and PHP, to provide developers with a modern, functional and expressive syntax.

<figure><img src="/files/I3RqLojabSzMU4peT84H" alt=""><figcaption><p>BoxLang Multi-Runtime</p></figcaption></figure>

BoxLang has been designed to be a highly adaptable and dynamic language to take advantage of all the modern features of the JVM and was designed with several goals in mind:

1. Be a rapid application development (RAD) scripting language and middleware.
2. Unstagnate the dynamic language ecosystem in Java.
3. Be dynamic, modular, lightweight, and fast.
4. Be 100% interoperable with Java.
5. Be modern, functional, and fluent (Think mixing CFML, Node, Kotlin, Java, and Clojure)
6. Extend via Modules
7. Be able to support multiple runtime environments:
   1. Native OS Binaries (CLI Tooling, compilers, etc.)
   2. Serverless Computing (AWS Lambda, Google Cloud Functions, Azure Functions, etc)
   3. Servlet Containers - CommandBox/Tomcat/Jetty/JBoss/Undertow
   4. Docker Containers
   5. DigitalOcean App Platform
   6. Android/iOS Devices
   7. Web assembly
   8. Spring Boot Applications
8. Compile down to Java ByteCode
9. Framework Capabilities (Scheduling, applications, events, async computing, tasks, queues, modules)
10. [Professional Open-Source Support](https://boxlang.io/plans)
11. Replacement for Adobe ColdFusion and Lucee CFML

{% hint style="danger" %}
**BoxLang can also be used as a replacement for Adobe ColdFusion or Lucee CFML Engines by leveraging our `bx-compat-cfml`module. NO CODE CHANGES, FASTER, MODERN AND SAVE MONEY.**
{% endhint %}

{% content-ref url="/pages/u42tZE9i82kGTlmi8nRx" %}
[Overview](/getting-started/overview)
{% endcontent-ref %}

## Interactive Learning

{% hint style="success" %}
Learn BoxLang hands-on with **BoxLings**, our interactive CLI learning tool with progressive exercises and test-driven feedback.

Start here: <https://github.com/ortus-boxlang/boxlings>
{% endhint %}

## License

BoxLang is open source and licensed under the [Apache 2 ](https://www.apache.org/licenses/LICENSE-2.0.html)License. Copyright and Registered Trademark by Ortus Solutions, Corp.

## BoxLang Subscriptions

BoxLang can also be enhanced by [purchasing subscriptions](https://www.boxlang.io/plans) to give you:

* Business Support with SLAs
* Enhanced builds
* Custom patches and builds
* Dedicated Engineer
* Premium Modules
* Much More...

{% embed url="<https://www.boxlang.io/plans>" %}

## Support Open Source

To support us, please consider becoming our patron at [patreon.com/ortussolutions](https://patreon.com/ortussolutions) for as little as $10/month.

## Discussions & Help

The Ortus Community is how to get help: <https://community.ortussolutions.com/c/boxlang/42>

{% embed url="<https://community.ortussolutions.com/c/boxlang/42>" %}

You can also join our Slack Box Team at: [https://boxteam.ortussolutions.com](https://boxteam.ortussolutions.com/)

## Reporting a Bug <a href="#reporting-a-bug" id="reporting-a-bug"></a>

We all make mistakes from time to time :) So why not let us know about it and help us out? We also love 😍 pull requests, so please star us and fork us at <https://github.com/ortus-boxlang/boxlang>

### Jira Issue Tracking

* BoxLang: <https://ortussolutions.atlassian.net/browse/BL>
* BoxLang IDE: <https://ortussolutions.atlassian.net/browse/BLIDE>
* BoxLang Modules: <https://ortussolutions.atlassian.net/browse/BLMODULES>

## Resources

* Professional Support: <https://www.ortussolutions.com/services/support>
* GitHub Org: <https://github.com/ortus-boxlang>
* Twitter: <https://x.com/TryBoxLang>
* FaceBook: <https://www.facebook.com/tryboxlang/>
* LinkedIn: <https://www.linkedin.com/company/tryboxlang>

## Ortus Solutions, Corp

![](/files/IcUERqqqsA1pwfVr0fcY)

This book was written and maintained by [Luis Majano](https://www.luismajano.com) and the [Ortus Solutions](https://www.ortussolutions.com) Development Team.

> Ortus Solutions is a company that focuses on building professional open source tools, custom applications and great websites! We're the team behind ColdBox, the de-facto enterprise BoxLang HMVC Platform, TestBox, the BoxLang Testing and Behavior Driven Development (BDD) Framework, ContentBox, a highly modular and scalable Content Management System, CommandBox, the BoxLang \<BoxLang> CLI, package manager, etc, and many more - <https://www.ortussolutions.com/>


# Contributing Guide

The best way to contribute to BoxLang!

Hola amigo! I'm excited that you are interested in contributing to **BoxLang**. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:

{% hint style="info" %}
If you are new to BoxLang, start with [BoxLings](https://github.com/ortus-boxlang/boxlings) to build confidence with the language and testing workflow before contributing to core projects.
{% endhint %}

### Code Of Conduct <a href="#code-of-conduct" id="code-of-conduct"></a>

This project is open source, and as such, the maintainers give their free time to build and maintain the source code held within. They make the code freely available in the hope that it will be useful to other developers and/or businesses. Your contributions are crucial in maintaining the integrity of BoxLang. Be considerate towards maintainers when raising issues or presenting pull requests. **We all follow the Golden Rule: Do to others as you want them to do to you.**

* As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
* Participants will be tolerant of opposing views.
* Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
* Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions not aligned with this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
* When interpreting the words and actions of others, participants should always assume good intentions. Emotions cannot be derived from textual representations.
* Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more project maintainers.

### Bug Reporting

Please link it to the appropriate issue if you submit a pull request.

* <https://ortussolutions.atlassian.net/browse/BL>

If you file a bug report, your issue should contain a title, a clear description of the issue, a way to replicate the issue, and any support files we might need to replicate your issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix for it. Not all issues that do not contain a way to replicate will be addressed.

### Support Questions <a href="#support-questions" id="support-questions"></a>

If you have questions about usage, professional support, or ideas to bounce off the maintainers, please do not create an issue. Leverage our support channels first.

* Ortus Community Discourse: <https://community.ortussolutions.com>
* Box Slack Team: <https://boxteam.ortussolutions.com>
* Professional Support: <https://www.ortussolutions.com/services/support>

### Pull Request Guidelines <a href="#pull-request-guidelines" id="pull-request-guidelines"></a>

* The `main` branch is just a snapshot of the **latest stable** release. All development should be done in dedicated branches. Do not submit PRs against the `main` branch. They will be closed.
* All pull requests should be sent against the `development` branch or the LTS version branch `releases/v{version}`
* It's OK to have multiple small commits as you work on the PR - GitHub will automatically squash it before merging.
* Make sure all local tests pass before submitting the merge.
* Please make sure all your pull requests have companion tests.
* Please link the Jira issue in your PR title when sending the final PR

### Security Vulnerabilities

If you discover a security vulnerability, please email the development team at <security@ortussolutions.com>. All security vulnerabilities will be promptly addressed.

### JRE Compatibility

Please make sure your code runs on JRE 21+

### Financial Contributions <a href="#financial-contributions" id="financial-contributions"></a>

You can support BoxLang and all of our Open Source initiatives at Ortus Solutions by becoming a Patreon. You can also get lots of goodies and services depending on the level of contributions.

* [Become a backer or sponsor on Patreon](https://www.patreon.com/ortussolutions)
* [One-time donations via PayPal](https://www.paypal.com/paypalme/ortussolutions)


# Release History

All the major information about BoxLang Releases

## Versioning Schema <a href="#versioning-schema" id="versioning-schema"></a>

BoxLang is maintained under the [Semantic Versioning](http://semver.org/) guidelines as much as possible. Releases will be numbered in the following format:

```
<major>.<minor>.<patch>
```

And constructed with the following guidelines:

* Breaking backward compatibility bumps the major (and resets the minor and patch)
* New additions without breaking backward compatibility bump the minor (and resets the patch)
* Bug fixes and misc changes bump the patch

## BoxLang Release & Support Lifecycle

Our release cadence follows a predictable yearly major-version schedule, with each release enjoying two years of Long-Term Support (LTS):

* **Active Support**: First 12 months after release – full feature updates, bug fixes & security patches.
* **LTS (Updates & Security)**: 2nd year – maintenance releases (minor improvements & security).
* **LTS (Security-Only)**: 3rd year – critical security fixes only, then archived.

This gives you a clear planning horizon and overlap between versions, so you can upgrade on your own schedule without ever being left unprotected.

### Support Lifecycle Chart

Here is our 5-year outlook.

<figure><img src="/files/4HVyx9ajBBnxufGxYt0A" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="104.49920654296875" align="center">Version</th><th align="center">Active Support</th><th align="center">LTS (updates &#x26; security)</th><th align="center">LTS (security-only)</th></tr></thead><tbody><tr><td align="center"><strong>v1</strong></td><td align="center">2025 – 2026</td><td align="center">2026 – 2027</td><td align="center">2027 – 2028</td></tr><tr><td align="center"><strong>v2</strong></td><td align="center">2026 – 2027</td><td align="center">2027 – 2028</td><td align="center">2028 – 2029</td></tr><tr><td align="center"><strong>v3</strong></td><td align="center">2027 – 2028</td><td align="center">2028 – 2029</td><td align="center">2029 – 2030</td></tr><tr><td align="center"><strong>v4</strong></td><td align="center">2028 – 2029</td><td align="center">2029 – 2030</td><td align="center">2030 – 2031</td></tr><tr><td align="center"><strong>v5</strong></td><td align="center">2029 – 2030</td><td align="center">2030 – 2031</td><td align="center">2031 – 2032</td></tr></tbody></table>

* After the “security-only” phase, the version is **archived**: no further updates, but archives remain available for reference.
* Overlaps ensure there’s always at least one actively maintained release.
* All dates refer to calendar years; exact dates will align with our annual major-version launch each Q1.


# 1.16.0

July 30, 2026

**BoxLang 1.16.0** is a reliability, compatibility, and observability-focused release with major HTTP client lifecycle hardening, better runtime diagnostics, and a broad round of CFML parity fixes. The biggest theme is control: control over HTTP client reuse and timeouts, control over proxy/header behavior in real deployments, control over classpath reload behavior, and stronger alignment for edge-case language and query semantics. This release closes **50 issues** across new features, improvements, and bug fixes.

## 🚀 Major Highlights

### 🌐 HTTP Client Lifecycle, Error Hooks, and Observability

This release significantly upgrades the HTTP stack with better lifecycle management and diagnostics:

* [**BL-2559**](https://ortussolutions.atlassian.net/browse/BL-2559) caches HTTP/SOAP clients through Box caches to avoid uncontrolled client creation and improve timeout behavior.
* [**BL-2558**](https://ortussolutions.atlassian.net/browse/BL-2558) adds a new `onHTTPError` event for client-level error interception and handling.
* [**BL-2562**](https://ortussolutions.atlassian.net/browse/BL-2562) exposes HTTP client configuration and request target metadata in BoxLang statistics.
* [**BL-2565**](https://ortussolutions.atlassian.net/browse/BL-2565) introduces maximum stream-content length controls to prevent unbounded response buffering.
* [**BL-2566**](https://ortussolutions.atlassian.net/browse/BL-2566) tracks observed hosts for operational visibility and traffic analysis.

### 🔁 Compatibility and Transpiler Parity Expansion

1.16.0 continues closing edge-case behavioral gaps for CFML and transpiled code:

* [**BL-2580**](https://ortussolutions.atlassian.net/browse/BL-2580) transpiles `listAppend()` member-method usage in addition to BIF usage.
* [**BL-2591**](https://ortussolutions.atlassian.net/browse/BL-2591) aligns `extract()` argument transpilation from `target` to `destination`.
* [**BL-2609**](https://ortussolutions.atlassian.net/browse/BL-2609) improves `query.findColumn()` compatibility behavior.
* [**BL-2610**](https://ortussolutions.atlassian.net/browse/BL-2610) allows CFC/BX files to be included in compatibility scenarios.

### 🧠 Runtime Safety and Data-Model Improvements

This release also sharpens runtime correctness and developer ergonomics:

* [**BL-2588**](https://ortussolutions.atlassian.net/browse/BL-2588) implements `javasettings.reloadOnChange`.
* [**BL-2589**](https://ortussolutions.atlassian.net/browse/BL-2589) loosens default `output` annotation behavior in classes.
* [**BL-2590**](https://ortussolutions.atlassian.net/browse/BL-2590) adds struct stream APIs: `stream()`, `keyStream()`, and `valueStream()`.
* [**BL-2598**](https://ortussolutions.atlassian.net/browse/BL-2598) introduces `useProxyHeaders` for reverse-proxy aware deployments.

## ✨ New Features

### HTTP and Runtime Telemetry

* [**BL-2558**](https://ortussolutions.atlassian.net/browse/BL-2558): Added `onHTTPError` event for HTTP clients.
* [**BL-2562**](https://ortussolutions.atlassian.net/browse/BL-2562): Exposed HTTP client configuration and request target metadata in runtime statistics.
* [**BL-2598**](https://ortussolutions.atlassian.net/browse/BL-2598): Added `useProxyHeaders` setting for proxy-aware request handling.

### Language and Type-System Surface

* [**BL-2590**](https://ortussolutions.atlassian.net/browse/BL-2590): Added struct streaming capabilities: `stream()`, `keyStream()`, `valueStream()`.
* [**BL-2609**](https://ortussolutions.atlassian.net/browse/BL-2609): Added compatibility behavior for `query.findColumn()`.
* [**BL-2610**](https://ortussolutions.atlassian.net/browse/BL-2610): Added compatibility support allowing CFC/BX files to be included.

```js
users = queryNew(
	"id,name,email",
	"integer,varchar,varchar",
	[
		[ 1, "Ana", "ana@example.com" ],
		[ 2, "Luis", "luis@example.com" ]
	]
)

nameColumnIndex = users.findColumn( "name" )
emailColumnIndex = users.findColumn( "email" )
```

```js
myStruct = { foo : "bar", baz : "bum" }

// Stream values
valueCount = myStruct.valueStream().count()

// Stream keys
keyCount = myStruct.keyStream().count()
```

### Classloading and Output Pipeline

* [**BL-2577**](https://ortussolutions.atlassian.net/browse/BL-2577): Added support for setting `disposition` on write-to-browser interception.
* [**BL-2585**](https://ortussolutions.atlassian.net/browse/BL-2585): `dynamicClassLoader.addPaths()` now accepts a single JAR or class-file path.

```js
getRequestClassLoader().addPaths( "/opt/app/lib/acme-utils.jar" )
```

## 🔧 Improvements

### HTTP Client Management

* [**BL-2559**](https://ortussolutions.atlassian.net/browse/BL-2559): Updated HTTPService to cache HTTP/SOAP clients for better timeout behavior and reduced client churn.
* [**BL-2565**](https://ortussolutions.atlassian.net/browse/BL-2565): Added max stream content length controls to protect against unbounded streaming into buffers.
* [**BL-2566**](https://ortussolutions.atlassian.net/browse/BL-2566): Added observed-host tracking to `BoxHTTPClient` for better observability.

### Language, Transpiler, and Compatibility

* [**BL-2561**](https://ortussolutions.atlassian.net/browse/BL-2561): Extended bitwise BIF support to `long` values.
* [**BL-2580**](https://ortussolutions.atlassian.net/browse/BL-2580): Added transpilation support for `listAppend()` member syntax.
* [**BL-2586**](https://ortussolutions.atlassian.net/browse/BL-2586): Improved compatibility so `e.extendedInfo` can be set in CF scenarios.
* [**BL-2589**](https://ortussolutions.atlassian.net/browse/BL-2589): Loosened default class `output` annotation behavior.
* [**BL-2591**](https://ortussolutions.atlassian.net/browse/BL-2591): Updated transpilation mapping for `extract()` (`target` to `destination`).
* [**BL-2592**](https://ortussolutions.atlassian.net/browse/BL-2592): Added missing archive format support.
  * **`compress()`** now supports: `bzip`, `bzip2`, `tar`, `tar.bz`, `tbz`, `tbz2`, `tgz`, `tar.gz`
  * **`extract()`** now supports: `bzip`, `bzip2`, `tar`, `tbz`, `tbz2`, `tgz`, `tar.gz`

```js
// Compress directory to a tar.gz archive
compress(
	source = "/tmp/project",
	destination = "/tmp/project.tar.gz",
	format = "tar.gz"
)

// Extract a tbz2 archive
extract(
	source = "/tmp/project.tbz2",
	destination = "/tmp/project-out",
	format = "tbz2"
)
```

### Runtime and Execution Behavior

* [**BL-2588**](https://ortussolutions.atlassian.net/browse/BL-2588): Implemented `javasettings.reloadOnChange`.
* [**BL-2601**](https://ortussolutions.atlassian.net/browse/BL-2601): Allowed mixed positional and indexed `procresult` usage.
* [**BL-2613**](https://ortussolutions.atlassian.net/browse/BL-2613): MiniServer now defaults form-field charset encoding to UTF-8.

```js
bx:application
	name = "reloadOnChangeApp"
	javaSettings = {
		loadPaths : [ "/path/to/libs/helloworld.jar" ],
		reloadOnChange : true
	}
```

## 🐛 Bug Fixes

### Closures, Interfaces, and Proxy Semantics

* [**BL-2381**](https://ortussolutions.atlassian.net/browse/BL-2381): Closures proxied to functional interfaces now respect default methods.
* [**BL-2552**](https://ortussolutions.atlassian.net/browse/BL-2552): Fixed closure binding to non-lexical variables in calling UDFs.
* [**BL-2608**](https://ortussolutions.atlassian.net/browse/BL-2608): Fixed overriding default interface methods with generic proxy.

### HTTP, MiniServer, and Web Runtime

* [**BL-2556**](https://ortussolutions.atlassian.net/browse/BL-2556): Fixed missing `fileContent` in HTTP results on low-level connection failures.
* [**BL-2567**](https://ortussolutions.atlassian.net/browse/BL-2567): Fixed Basic Auth charset assignment during security protocol negotiation.
* [**BL-2572**](https://ortussolutions.atlassian.net/browse/BL-2572): Fixed MiniServer rewriting `/ws` requests due to trailing slash handling.
* [**BL-2578**](https://ortussolutions.atlassian.net/browse/BL-2578): Fixed whitespace management behavior that broke JavaScript output.
* [**BL-2581**](https://ortussolutions.atlassian.net/browse/BL-2581): Fixed whitespace management not removing leading spaces.

### Query, QoQ, and Data Handling

* [**BL-2563**](https://ortussolutions.atlassian.net/browse/BL-2563): Fixed `query.filter` handling for null column values.
* [**BL-2575**](https://ortussolutions.atlassian.net/browse/BL-2575): Fixed QoQ errors with empty list parameters.
* [**BL-2603**](https://ortussolutions.atlassian.net/browse/BL-2603): Fixed Oracle null refcursor out params defaulting to empty string in compat mode.
* [**BL-2606**](https://ortussolutions.atlassian.net/browse/BL-2606): Fixed casting errors when setting defaults in non-string query columns.
* [**BL-2611**](https://ortussolutions.atlassian.net/browse/BL-2611): Fixed compound operators on query columns.

### File, Zip, and Loop Semantics

* [**BL-2573**](https://ortussolutions.atlassian.net/browse/BL-2573): Fixed zipping a directory into a file inside itself.
* [**BL-2596**](https://ortussolutions.atlassian.net/browse/BL-2596): Fixed file-loop `index` and `item` handling.
* [**BL-2597**](https://ortussolutions.atlassian.net/browse/BL-2597): Added character support in file-loop operations.
* [**BL-2604**](https://ortussolutions.atlassian.net/browse/BL-2604): Fixed file-loop validation requiring either `item` or `index`.

### Casting, Parsing, and Compatibility Edge Cases

* [**BL-2553**](https://ortussolutions.atlassian.net/browse/BL-2553): Fixed `urlDecode( 0 )` ClassCastException.
* [**BL-2554**](https://ortussolutions.atlassian.net/browse/BL-2554): Fixed missing implementation path for `cfloop` struct attributes.
* [**BL-2570**](https://ortussolutions.atlassian.net/browse/BL-2570): Fixed `structKeySet()` forcing keys to strings.
* [**BL-2571**](https://ortussolutions.atlassian.net/browse/BL-2571): Fixed `formatBaseN()` for `Long` inputs.
* [**BL-2579**](https://ortussolutions.atlassian.net/browse/BL-2579): Fixed list append/prepend `includeEmptyFields` behavior on incoming values.
* [**BL-2582**](https://ortussolutions.atlassian.net/browse/BL-2582): Fixed relative class resolution to include base template path lookup.
* [**BL-2583**](https://ortussolutions.atlassian.net/browse/BL-2583): Added DateTime caster compatibility for `M/d/yyyy hh:mm:ss.SSS`.
* [**BL-2584**](https://ortussolutions.atlassian.net/browse/BL-2584): Fixed parser issue with `rethrow` and nested `switch`.
* [**BL-2587**](https://ortussolutions.atlassian.net/browse/BL-2587): Fixed `createObject()` errors when classloader is wrapped in `DynamicObject`.
* [**BL-2602**](https://ortussolutions.atlassian.net/browse/BL-2602): Fixed cookie `expires="never"` casting failure.
* [**BL-2605**](https://ortussolutions.atlassian.net/browse/BL-2605): Fixed parser issues involving `null` in `assert` statements.

### Runtime Stability and Performance

* [**BL-2560**](https://ortussolutions.atlassian.net/browse/BL-2560): Fixed performance regression in compare operator.
* [**BL-2564**](https://ortussolutions.atlassian.net/browse/BL-2564): Fixed `NullPointerException` in `getClassMetadata`.

## 📊 Release Snapshot

* **Release Date:** July 30, 2026
* **Status:** Released
* **Total Issues:** 50
* **Distribution:** 30 Bugs, 12 Improvements, 8 New Features
* **Primary Focus:** HTTP client lifecycle hardening, observability, CFML/transpiler compatibility, parser/runtime stability

{% hint style="success" %}
BoxLang 1.16.0 is the recommended update for teams that rely heavily on HTTP integrations, MiniServer deployments behind proxies, and CFML compatibility edge-case behavior.
{% endhint %}


# 1.15.0

July 9, 2026

**BoxLang 1.15.0** is a high-impact release with two major headlines and a sweeping round of hardening. The first headline is the new first-class **`BoxStringBuilder`** type — together with compile-time literal folding, smarter `&=` semantics, and an auto-switching runtime concat strategy — making string-heavy code dramatically faster with no code changes required. The second is foundational and architectural: **every class loader in the BoxLang runtime and module system has been fully abstracted** behind a pluggable `IClassLoaderFactory` interface, paving the road to our upcoming **Android runtime** and **AOT (Ahead-of-Time compiled) runtimes** such as GraalVM Native Images and more. Beyond these two pillars, this release delivers two new type-check BIFs (`isBoxSet()` and `isRange()`), an improved `threadCurrent()` BIF, synchronized set support, security hardening for the web runtime, QoQ performance improvements, and an extensive round of CFML compatibility fixes, formatter corrections, and runtime hardening. This release closes **35 issues** spanning new features, improvements, and bug fixes.

## 🚀 Major Highlights

### 🔤 BoxStringBuilder — First-Class Mutable String Type

BoxLang 1.15.0 introduces `BoxStringBuilder` as a brand-new first-class type, wrapping `java.lang.StringBuilder` with full BoxLang integration including member-function dispatch, 1-based positional semantics, and silent coercion to `String` when a string value is required. This pairs with four complementary compiler and runtime optimizations that make string concatenation dramatically faster — often with **zero code changes** required.

**Why this matters:** String objects in Java are immutable. Joining two strings always creates a new object and copies both buffers. In loops and accumulators this can dominate runtime. `BoxStringBuilder` provides a mutable buffer that appends in place, avoiding repeated allocations.

**Three creation forms — all equivalent:**

```js
// BIF: optional initial value and buffer capacity
sbA = stringBuilderNew( "Hello", 128 )

// Long literal form
sbB = stringbuilder{ "Hello" }

// Short literal form (preferred)
sbC = sb{ "Hello" }
sbC.append( " World" )
writeOutput( sbC.toString() )  // "Hello World"
```

The `sb{ ... }` literal accepts **any expression**, not just quoted text:

```js
sb{ "Hello #name#" }
sb{ myVar }
sb{ getGreeting() }
sb{ foo.bar() }
```

**Member method API (1-based positional where applicable):**

| Method                                     | Description                                              |
| ------------------------------------------ | -------------------------------------------------------- |
| `append( value )`                          | Append a value to the end                                |
| `prepend( value )`                         | Prepend a value to the beginning                         |
| `insert( position, value )`                | Insert at a 1-based position                             |
| `delete( start, end )`                     | Delete characters from start to end (inclusive, 1-based) |
| `replace( start, end, value )`             | Replace range with new value                             |
| `reverse()`                                | Reverse the character sequence                           |
| `clear()`                                  | Reset to empty                                           |
| `trim()`                                   | Remove leading/trailing whitespace                       |
| `left( count )`                            | Return leftmost N characters                             |
| `right( count )`                           | Return rightmost N characters                            |
| `mid( start [, count ] )`                  | Substring from 1-based position                          |
| `find( substring [, start [, noCase ] ] )` | Find a substring                                         |
| `contains( substring [, noCase ] )`        | Return boolean membership                                |
| `startsWith( prefix )`                     | True if starts with value                                |
| `endsWith( suffix )`                       | True if ends with value                                  |
| `length()`                                 | Current length of the buffer                             |
| `isEmpty()`                                | True if the buffer is empty                              |
| `toString()`                               | Materialize as a Java String                             |

**Example: Building an HTML fragment efficiently:**

```js
sb = sb{}
sb.append( "<ul>" )
for ( item in items ) {
    sb.append( "<li>" ).append( item ).append( "</li>" )
}
sb.append( "</ul>" )
writeOutput( sb.toString() )
```

**Silent string coercion** — pass a `BoxStringBuilder` anywhere a `String` is required and it is automatically converted:

```js
sb = sb{ "Hello " }
writeOutput( sb & "World" )  // "Hello World"
len( sb )                    // works — sb is coerced to string
```

#### Optimization 1 — `&=` in-place append for builders

Compound concat now uses in-place append semantics for `BoxStringBuilder` values:

```js
sb = sb{ "Hello" }

// &= desugars to sb.append( " World" )
sb &= " World"

// sb is mutated in place — no allocation, no reference change
writeOutput( sb )  // "Hello World"
```

This also applies to raw `java.lang.StringBuilder` instances, not just `BoxStringBuilder`.

#### Optimization 2 — Compiler self-assignment rewrite

The compiler recognizes explicit self-concat patterns and rewrites them to the faster compound form:

```js
// Written as:
data = data & chunk

// Internally rewritten to:
data &= chunk
```

This rewrite applies to identifier, dot-access, and array-access targets (`variables.data`, `arr[1]`, etc.), producing the in-place append path automatically.

#### Optimization 3 — Compile-time literal folding

Contiguous string literals are combined **at compile time**, reducing runtime work:

```js
// Source:
result = "foo" & "bar" & "baz" & "qux"

// Compiled as:
result = "foobarbazqux"
```

Mixed expressions are **partially folded**:

```js
// Source:
result = "foo" & "bar" & name & "baz" & "qux"

// Compiled as:
result = "foobar" & name & "bazqux"
```

#### Optimization 4 — Auto-switching runtime concat strategy

At runtime, concat behavior is tiered based on segment count:

| Segments  | Strategy                                               |
| --------- | ------------------------------------------------------ |
| 0–1       | Trivial return                                         |
| 2–3       | Direct String concat path                              |
| 4 or more | `StringBuilder`-backed path with pre-computed capacity |

This means expression chains like `"foo" & bar & "baz" & bum` and interpolation strings like `"foo#bar#baz#bum#"` are **automatically** lowered to:

```js
sb = new StringBuilder( precomputedCapacity )
sb.append( "foo" ).append( bar ).append( "baz" ).append( bum )
result = sb.toString()
```

**Performance benchmarks** (100,000 iterations, 2–8 string segments):

* String concat is faster for exactly 2 strings
* Break-even occurs around 3 segments
* From 2 to 8 strings, concat growth is **\~4.2× steeper** than builder growth
* BoxLang automatically uses StringBuilder for **4 or more segments**

**Java interop nuance:** `BoxStringBuilder` member methods are NOT injected onto a raw `java.lang.StringBuilder` to avoid mixing 1-based (BoxLang) and 0-based (Java) positional semantics. Wrap first if needed:

```js
javaSB = createObject( "java", "java.lang.StringBuilder" ).init( "Hello" )
boxSB  = stringBuilderNew( javaSB )
boxSB.delete( 1, 1 )  // BoxStringBuilder semantics (1-based)

javaSB.delete( 2, 2 )  // Java semantics (0-based, no-op for equal start/end)
```

{% hint style="info" %}
For a complete guide to `BoxStringBuilder` including practical patterns and benchmarks, see [StringBuilder](/boxlang-language/syntax/string-builder) in the Syntax & Semantics section.
{% endhint %}

For the full breakdown of what shipped, see the community post: [StringBuilder in BoxLang: Fast Concatenation, Better &=, and Compile-Time Folding](https://community.ortussolutions.com/t/stringbuilder-in-boxlang-fast-concatenation-better-and-compile-time-folding/11123).

### 🚀 Runtime Architecture — Pluggable ClassLoader Factory (BL-2526)

BoxLang has always had ambitions beyond the JVM. We want BoxLang to run on **Android**, to compile **ahead-of-time** via GraalVM Native Image, and eventually to support other constrained or specialized execution targets that differ fundamentally from a standard JVM process. What has stood in the way — everywhere — has been class loading.

In a standard JVM, loading a class means calling `URLClassLoader.defineClass()`, which JIT-compiles bytecode on first use. That model is deeply wired into how BoxLang boots, how it compiles your `.bx` source files, how modules get isolated from each other, and how runtime-generated classes are resolved. On Android, `URLClassLoader` does not exist. On GraalVM Native Image in closed-world mode, you cannot call `defineClass()` at runtime at all.

In BoxLang 1.15.0, **every class-loader creation point in the runtime has been extracted behind a single `IClassLoaderFactory` interface**. This single seam governs three distinct construction points:

* The **runtime root class loader** — parent of all module loaders, used for Java interop and dynamic lookups
* Each **module's isolated class loader** — responsible for isolating a module's JARs from the rest of the runtime
* The **generated class loader** — the loader that receives compiled BoxLang bytecode and resolves it for execution

Swapping a single factory before the runtime boots changes all three in one move. No forks. No patches. No runtime surgery.

```java
// For a standard JVM (the default — no changes needed for existing deployments)
BoxRuntime.setClassLoaderFactory( new DynamicClassLoaderFactory() );

// For Android: return the app ClassLoader as the runtime loader,
// use DexClassLoader for modules, and a resolve-only loader for generated classes
BoxRuntime.setClassLoaderFactory( new AndroidClassLoaderFactory() );

// For GraalVM Native Image (closed-world AOT):
// all classes are pre-registered at build time; no defineClass() at runtime
BoxRuntime.setClassLoaderFactory( new NativeImageClassLoaderFactory() );
```

The default `DynamicClassLoaderFactory` is installed automatically and reproduces the exact behavior of all previous BoxLang releases — **zero breaking changes for existing deployments**.

**What this unlocks:**

| Target                | What changes                            | BoxLang runtime                          | Your code |
| --------------------- | --------------------------------------- | ---------------------------------------- | --------- |
| Standard JVM          | Nothing                                 | `DynamicClassLoaderFactory` (default)    | Unchanged |
| Android (ART)         | `AndroidClassLoaderFactory` at boot     | Uses app ClassLoader + DexClassLoader    | Unchanged |
| GraalVM Native Image  | `NativeImageClassLoaderFactory` at boot | Pre-registered classes, no `defineClass` | Unchanged |
| Custom OSGI / sandbox | Custom factory at boot                  | Full control                             | Unchanged |

This investment does not add a single new BIF or language construct. What it does is make BoxLang **portable at the architecture level** — a prerequisite for everything that follows on our roadmap. The BoxLang language you write today will run, unchanged, on whatever runtime target we ship tomorrow.

{% hint style="info" %}
Module developers: if your module currently constructs class loaders directly instead of going through the module service lifecycle, now is the time to align with the factory pattern. Contact the Ortus team for migration guidance.
{% endhint %}

## ✨ New Features

### `isBoxSet()` BIF (BL-2506)

A dedicated BIF to check whether a value is a BoxLang `BoxSet` instance — complements the existing `isArray()`, `isStruct()`, and `isQuery()` family:

```js
s = setOf( 1, 2, 3 )

isBoxSet( s )        // true
isBoxSet( [1,2,3] )  // false — arrays are not sets
isBoxSet( "hello" )  // false

// Useful for defensive type checking before set operations
function processCollection( data ) {
    if ( isBoxSet( data ) ) {
        return data.toArray().sort( "numeric" )
    }
    if ( isArray( data ) ) {
        return data.toSet().toArray().sort( "numeric" )
    }
    throw( "Unsupported collection type" )
}
```

### `isRange()` BIF (BL-2507)

A dedicated BIF to test whether a value is a BoxLang `Range` instance:

```js
r = 1..10

isRange( r )        // true
isRange( [1,2,3] )  // false
isRange( "1..10" )  // false — string representation, not a range

// Guard range-specific operations
function sumRange( val ) {
    if ( !isRange( val ) ) {
        throw( "Expected a Range, got #val.getClass().getSimpleName()#" )
    }
    return val.reduce( ( acc, item ) -> acc + item, 0 )
}
```

### `threadCurrent()` BIF (BL-2513)

Easily get access to the current native Java thread from BoxLang via the `threadCurrent()` BIF.

```js
javaThread = threadCurrent()
writeOutput( javaThread.getName() )          // java.lang.Thread getName()
writeOutput( javaThread.getState() )         // RUNNABLE, WAITING, etc.
writeOutput( javaThread.isVirtual() )        // true for virtual threads (Java 21+)
writeOutput( javaThread.threadId() )         // JVM thread identifier
```

This is useful for telemetry, profiling integrations, or any scenario where direct Thread API access is required.

### Improved `asString()` on Class Instances (BL-2487)

BoxLang class instances now produce a more useful string representation from `asString()`. If the class defines a `toString()` method or property, that value is used; otherwise the representation now includes the class name and a summary of public properties:

```js
class Product {
    property string name
    property numeric price

    function toString() {
        return "Product(#variables.name#, $#variables.price#)"
    }
}

p = new Product( name="Widget", price=9.99 )
writeOutput( p )           // Product(Widget, $9.99)
writeOutput( "#p#" )       // Product(Widget, $9.99)
```

### Compile Validation for Inner Classes Inside Functions (BL-2490)

The compiler now emits a clear validation error when an inner class is declared inside a function body, rather than producing a confusing runtime failure:

```js
function doSomething() {
    // ❌ Now produces a clear compile-time error:
    class Helper { }
    // Compiler: Inner classes cannot be declared inside a function body.
}
```

### Deserialize JSON Args to Struct/Array in Remote Methods (BL-2505)

Remote methods (those marked `access="remote"`) now automatically deserialize JSON string arguments into `Struct` or `Array` values when the argument type is declared as such:

```js
remote function saveUser( required struct userData ) {
    // When called via HTTP with userData={"name":"Alice","email":"alice@example.com"}
    // userData is automatically deserialized to a BoxLang Struct:
    writeOutput( userData.name )   // Alice
    writeOutput( userData.email )  // alice@example.com
}
```

### `application/json` Whitespace Compression (BL-2547)

The web runtime's whitespace compression (previously only active for HTML responses) is now also applied to `application/json` responses, reducing payload size without any application changes.

### Error Basics in HTML Error Page Comment (BL-2204)

BoxLang's default HTML error page now includes an HTML comment at the very top of the response with essential error information, making it possible to programmatically extract error details during testing and debugging even when full error display is suppressed:

```html
<!-- BoxLang Error
   Type    : application.MyException
   Message : Something went wrong
   Template: /path/to/template.bxm
   Line    : 42
-->
```

### Synchronized Set Support — `setNew( isSynchronized )` (BL-2494)

`setNew()` gains an `isSynchronized` boolean argument. When `true`, the set is wrapped in a thread-safe synchronized wrapper for safe concurrent access:

```js
// Thread-safe set for shared state across threads
sharedSet = setNew( type="linked", isSynchronized=true )

thread name="t1" { sharedSet.add( "alpha" ) }
thread name="t2" { sharedSet.add( "beta" )  }
threadJoin( "t1,t2" )

writeOutput( sharedSet.size() )  // 2
```

## 🔧 Improvements

### Language & Runtime

* [**BL-2538**](https://ortussolutions.atlassian.net/browse/BL-2538) — **QoQ Performance Improvements** — Query of Queries now executes significantly faster for large datasets through internal optimizations to the filtering, sorting, and aggregation pipeline.
* [**BL-2539**](https://ortussolutions.atlassian.net/browse/BL-2539) — **Expression Interpreter Safe Get** — The expression interpreter no longer throws when performing a safe navigation expression that fails to resolve a key; it returns `null` instead:

```js
data = { name: "alice" }
val = data?.age?.years    // null — no exception thrown
```

* [**BL-2543**](https://ortussolutions.atlassian.net/browse/BL-2543) — **`null` is falsey but not boolean** — `isBoolean( null )` now correctly returns `false`. `null` is falsey but that does not make it a boolean value:

```js
isBoolean( null )   // false (was: true in some earlier builds)
if ( !null ) { }    // still works — null IS falsey
```

* [**BL-2500**](https://ortussolutions.atlassian.net/browse/BL-2500) — **Struct keys capped in error messages** — `KeyNotFoundException` error messages now show a capped list of available keys to avoid flooding logs on large structs.
* [**BL-2501**](https://ortussolutions.atlassian.net/browse/BL-2501) — **Range empty-set semantics** — Paradoxical ranges (e.g., `5..3` with a positive step) now produce zero elements rather than throwing:

```js
r = (5..3).step( 1 )
r.toArray()  // [] — paradoxical range returns empty set
```

* [**BL-2512**](https://ortussolutions.atlassian.net/browse/BL-2512) — **Formatter `arguments.separator` config** — The formatter now accepts an `arguments.separator` config key (default `" = "`) controlling spacing around named argument separators:

```json
{
  "arguments": {
    "separator": " = "
  }
}
```

* [**BL-2514**](https://ortussolutions.atlassian.net/browse/BL-2514) — **Session cookie only set when session management is enabled** — The web runtime no longer emits a `BXSESSIONID` cookie for applications that have session management disabled.
* [**BL-2508**](https://ortussolutions.atlassian.net/browse/BL-2508) — **No path rewriting for known script extensions** — The web runtime no longer rewrites paths that already resolve to known BoxLang script extensions, avoiding double-resolution in certain URL routing scenarios.
* [**BL-2509**](https://ortussolutions.atlassian.net/browse/BL-2509) — **File upload copies rather than moves** — `fileUpload` now copies the temporary upload file to the destination, preventing failures when temp and destination paths cross filesystem mount boundaries.
* [**BL-2510**](https://ortussolutions.atlassian.net/browse/BL-2510) — **Stored proc `OUT` params respect `nullEqualsEmptyString`** — Stored procedure output parameters now honor the CFML compat flag, returning `""` instead of `null` where appropriate.
* [**BL-2497**](https://ortussolutions.atlassian.net/browse/BL-2497) — **CFML compat: string dates as numbers** — In CFML compatibility mode, string representations of dates can now participate in numeric operations, matching Adobe ColdFusion behavior.
* [**BL-2548**](https://ortussolutions.atlassian.net/browse/BL-2548) — **Adobe CF `returnFormat` drives `Content-Type`** — Remote methods with `returnFormat="json"` now correctly set `Content-Type: application/json` in the response.
* [**BL-2493**](https://ortussolutions.atlassian.net/browse/BL-2493) — **Set dump template handles Java sets** — The HTML dump template for `BoxSet` now also renders native `java.util.Set` instances correctly.

### Security

* [**BL-2515**](https://ortussolutions.atlassian.net/browse/BL-2515) — **Web runtime blocks requests with null bytes** — Any HTTP request whose URL contains a null byte (`%00`) is rejected with `400 Bad Request` before processing, preventing null-byte injection attacks.

## 🐛 Bug Fixes

### Language & Parser

* [**BL-2491**](https://ortussolutions.atlassian.net/browse/BL-2491) — Class constructor syntax using `new ClassName()` on imported or locally-declared classes was not being recognized correctly; fixed.
* [**BL-2537**](https://ortussolutions.atlassian.net/browse/BL-2537) — Closures declared inside BoxLang `interface` bodies failed to compile in the Java bytecode compiler; they now compile and execute correctly.
* [**BL-2549**](https://ortussolutions.atlassian.net/browse/BL-2549) — Invalid bytecode was generated for the string concatenation (`&`) operator under certain expression patterns; the bytecode emitter now produces correct output in all cases.
* [**BL-2550**](https://ortussolutions.atlassian.net/browse/BL-2550) — After splitting a large method at the bytecode level, source line numbers in stack traces were incorrect; line number tables are now recalculated after every split.

### Casters & Types

* [**BL-2492**](https://ortussolutions.atlassian.net/browse/BL-2492) — `int`, `long`, and `short` casters previously silently accepted values outside their representable range. They now validate the input and throw a meaningful cast exception:

```js
castAs( 9999999999999, "int" )
// throws: Value 9999999999999 is too large to be cast to int

castAs( -9999999999999, "short" )
// throws: Value -9999999999999 is too large to be cast to short
```

### Formatter

* [**BL-2496**](https://ortussolutions.atlassian.net/browse/BL-2496) — Formatter threw an error on variable assignment statements with no initializer (e.g., `var x`); these are now formatted correctly.
* [**BL-2528**](https://ortussolutions.atlassian.net/browse/BL-2528) — Formatter was incorrectly inserting two extra spaces before the `extends` keyword in class definitions.
* [**BL-2529**](https://ortussolutions.atlassian.net/browse/BL-2529) — Formatter was converting CFML component invocations (angle bracket style) into BoxLang `bx:component` style inside `.cfc` files. The formatter now detects the file context and preserves CFML syntax in CFML files:

```html
<!-- CFML file — now preserved as-is -->
<cfcomponent extends="BaseComponent">
    ...
</cfcomponent>
```

### CFML Compatibility

* [**BL-2495**](https://ortussolutions.atlassian.net/browse/BL-2495) — Query filter regression: when the filter value was empty, the CFML compat layer was incorrectly filtering out non-empty rows.
* [**BL-2530**](https://ortussolutions.atlassian.net/browse/BL-2530) — `decimalFormat( "" )` was throwing a cast exception; it now returns `"0.00"` matching Adobe CF behavior:

```js
decimalFormat( "" )   // "0.00"   (was: cast exception)
decimalFormat( 0 )    // "0.00"
```

* [**BL-2531**](https://ortussolutions.atlassian.net/browse/BL-2531) — Improved parser error messages when an unescaped `#` character is found inside a `<cfoutput>` block — the error now points to the correct source location.
* [**BL-2532**](https://ortussolutions.atlassian.net/browse/BL-2532) — `<cfapplication action="update" datasource="...">` was silently ignoring the datasource change; the runtime now correctly applies the update.
* [**BL-2535**](https://ortussolutions.atlassian.net/browse/BL-2535) — When `onWebExecutorRequest()` changed the request URL, file extension handling was applied to the original URL rather than the rewritten one.
* [**BL-2544**](https://ortussolutions.atlassian.net/browse/BL-2544) — Default JSON serialization format was inconsistent between calls on the same data; the serialization path is now deterministic.
* [**BL-2545**](https://ortussolutions.atlassian.net/browse/BL-2545) — `dateCompare()` now correctly handles `"hours"` as a date-part argument (previously only `"hour"` singular was recognized):

```js
dateCompare( now(), now(), "hours" )    // 0 — now works
dateCompare( now(), now(), "hour" )     // 0 — still works
```

### String BIFs

* [**BL-2536**](https://ortussolutions.atlassian.net/browse/BL-2536) — `replace()` threw a `NullPointerException` when the input string was `null`; it now treats `null` as an empty string:

```js
replace( null, "foo", "bar" )    // "" — no longer throws
replace( "", "foo", "bar" )      // ""
```

### Runtime & Security

* [**BL-2503**](https://ortussolutions.atlassian.net/browse/BL-2503) — A race condition in the Encryption utility was caused by a shared non-concurrent `HashMap`; replaced with a thread-safe `ConcurrentHashMap`.
* [**BL-2484**](https://ortussolutions.atlassian.net/browse/BL-2484) — Hikari connection pool was producing excessive `INFO`-level log output at startup and during routine operation; log levels have been tuned for quiet defaults.
* [**BL-2283**](https://ortussolutions.atlassian.net/browse/BL-2283) — When passing a `Date` value as a query parameter, a timezone offset was incorrectly applied when the application server timezone differed from the database timezone; dates are now sent without offset adjustment.

## 📊 Release Snapshot

* **Release Date:** July 2026
* **Total Issues:** 35
* **Distribution:** 9 New Features, 13 Improvements, 13 Bugs
* **Primary Focus:** String performance (`BoxStringBuilder`, compile-time folding, runtime concat strategy), type-check BIFs, CFML compat hardening, security


# 1.14.0

June 3, 2026

**BoxLang 1.14.0** is an innovative release that pushes the language forward with first-class **dynamic sets**, **ranges**, **inner classes**, **template classes**, **class references as callable constructors**, deep **query transformation**, **JSONPath** capabilities and much more. This release closes **65 issues** spanning new features, developer experience enhancements, formatter maturity, CFML compatibility parity, and extensive runtime hardening.

This release introduces the **Dynamic Set** type — a new first-class collection with literal syntax, operator overloads for set algebra, functional pipelines, and three backing variants (hash, linked, sorted). We also introduce the **Dynamic Range** type, which revolutionizes interval operations with lazy iteration, multiple element types (integers, decimals, characters, dates, and custom `IRangeable` types), exclusive boundaries, custom stepping, Java Stream integration, and unbounded/half-bounded support. On the language evolution side, **inner classes** and **template classes** bring new structural capabilities, while class references now double as callable constructors via functional callbacks. The **DataNavigator** gains full JSONPath-style query support with `get()`, `has()`, and the new `query()` method. The **MiniServer** health endpoint now includes Undertow and WebSocket metrics. The formatter becomes even more production-ready with ignore-comment support (`@formatter:off` / `bxformat-ignore-start`), multiple-source input, `--excludes` flag, and fine-grained `template.enabled` / `property_spacing` rules. Phew! So much to cover, let's dive in!

## 🚀 Major Highlights

### 🔢 Dynamic Set — First-Class Collection Type

BoxLang 1.14.0 introduces `BoxSet` as a brand-new first-class type, wrapping `java.util.Set` with full BoxLang integration including member-function dispatch, change listeners, metadata, and JSON serialization. Sets provide a powerful collection model for working with **unique values**, making them ideal for deduplication, membership testing, tagging systems, permissions, caching, filtering, mathematics, and data comparison workflows.

Unlike arrays, sets enforce uniqueness by design and offer highly efficient lookup operations. BoxLang elevates sets to a first-class citizen with literal syntax, functional collection operations, and rich operator overloads for set algebra—including unions, intersections, differences, and symmetric differences—making complex data manipulation both expressive and concise.

Whether you're comparing datasets, managing unique identifiers, processing large collections, implementing access-control rules, or building recommendation and analytics engines, `BoxSet` provides a performant and elegant foundation for working with distinct values at scale.

Sets support three backing variants:

* `DEFAULT` — `HashSet`, fastest, no ordering
* `LINKED` — `LinkedHashSet`, preserves insertion order
* `SORTED` — `TreeSet`, natural ordering via `Compare.invoke`

```js
// BIF construction
s = setNew()                                  // empty default (hash)
s = setNew( type="linked", values=[1,2,3] )   // ordered, deduped
s = setOf( 1, 2, 2, 3 )                       // varargs, deduped

// Literal syntax (soft-keyword "set", parser-gated)
s = set{ 1, 2, 3 }                            // default (hash)
s = set{}                                     // empty

// From an Array
s = [1, 2, 3].toSet()
s = [1, 2, 3].toSet( "linked" )
```

**Set algebra via operators:**

```js
union     = a + b      // setUnion
diff      = a - b      // setDifference
intersect = a * b      // setIntersection
symdiff   = a ^ b      // setSymmetricDifference
```

**Rich member-function API** — sets support `.add()`, `.contains()`, `.has()`, `.remove()`, `.delete()`, `.size()`, `.len()`, `.isEmpty()`, `.addAll()`, `.removeAll()`, `.retainAll()`, `.clear()`, `.containsAll()`, `.equals()`, `.isSubsetOf()`, `.isSupersetOf()`, `.isDisjointFrom()`, `.union()`, `.intersection()`, `.difference()`, `.symmetricDifference()`, and functional pipelines: `.each()`, `.map()`, `.filter()`, `.reject()`, `.reduce()`, `.every()`, `.some()`, `.none()`, `.find()`.

```js
s = setOf( 1, 2, 3, 4, 5 )
s.filter( ( item ) => item > 2 )
    .map( ( item ) -> item * 10 )
    .toList( ", " )
// → "30, 40, 50"
```

#### Set Built-In Functions Reference

**Construction & Creation**

| BIF                           | Member Method                                          | Description                                           |
| ----------------------------- | ------------------------------------------------------ | ----------------------------------------------------- |
| `setNew( [type], [values] )`  | —                                                      | Create a new Set, optionally seeded from a collection |
| `setOf( ...values )`          | —                                                      | Build a default (hash) Set from positional arguments  |
| `toSet( collection, [type] )` | `Array.toSet()`, `Query.toSet()`, `String.listToSet()` | Convert a collection into a Set, deduplicating        |
| `structKeySet( struct )`      | `Struct.keySet()`                                      | Build a Set containing the keys of a Struct           |
| `structValueSet( struct )`    | `Struct.valueSet()`                                    | Build a Set containing the values of a Struct         |

**Mutation**

| BIF                                  | Member Method(s)         | Description                                          |
| ------------------------------------ | ------------------------ | ---------------------------------------------------- |
| `boxSetAdd( set, value )`            | `.add()`, `.append()`    | Add an element — duplicates ignored, returns the Set |
| `boxSetAddAll( set, collection )`    | `.addAll()`              | Add every element of a collection to a Set           |
| `boxSetRemove( set, value )`         | `.remove()`, `.delete()` | Remove an element — returns the Set for chaining     |
| `boxSetRemoveAll( set, collection )` | `.removeAll()`           | Remove every element of a collection from a Set      |
| `boxSetRetainAll( set, collection )` | `.retainAll()`           | Retain only elements also present in the collection  |
| `boxSetClear( set )`                 | `.clear()`               | Remove all elements, leaving the Set empty           |

**Query & Membership**

| BIF                                    | Member Method(s)        | Description                                               |
| -------------------------------------- | ----------------------- | --------------------------------------------------------- |
| `boxSetContains( set, value )`         | `.contains()`, `.has()` | Test whether a Set contains a given value                 |
| `boxSetContainsAll( set, collection )` | `.containsAll()`        | Test whether a Set contains every element of a collection |
| `boxSetIsEmpty( set )`                 | `.isEmpty()`            | Test whether a Set has no elements                        |
| `boxSetEquals( setA, setB )`           | `.equals()`             | Test whether two Sets contain the same elements           |
| `boxSetIsSubsetOf( setA, setB )`       | `.isSubsetOf()`         | Test whether every element of A is also in B              |
| `boxSetIsSupersetOf( setA, setB )`     | `.isSupersetOf()`       | Test whether every element of B is also in A              |
| `boxSetIsDisjointFrom( setA, setB )`   | `.isDisjointFrom()`     | Test whether two Sets share no elements                   |
| `boxSetFind( set, predicate )`         | `.find()`               | Return the first element matching the predicate           |
| `boxSetEvery( set, predicate )`        | `.every()`              | True if every element matches the predicate               |
| `boxSetSome( set, predicate )`         | `.some()`, `.any()`     | True if at least one element matches the predicate        |
| `boxSetNone( set, predicate )`         | `.none()`               | True if no element matches the predicate                  |

**Set Algebra**

| BIF                                       | Member Method            | Operator | Description                              |
| ----------------------------------------- | ------------------------ | -------- | ---------------------------------------- |
| `boxSetUnion( setA, setB )`               | `.union()`               | `+`      | Compute the union (A ∪ B)                |
| `boxSetIntersection( setA, setB )`        | `.intersection()`        | `*`      | Compute the intersection (A ∩ B)         |
| `boxSetDifference( setA, setB )`          | `.difference()`          | `-`      | Compute the difference (A − B)           |
| `boxSetSymmetricDifference( setA, setB )` | `.symmetricDifference()` | `^`      | Compute the symmetric difference (A △ B) |

**Functional Pipelines**

| BIF                                           | Member Method | Description                                                |
| --------------------------------------------- | ------------- | ---------------------------------------------------------- |
| `boxSetEach( set, callback )`                 | `.each()`     | Invoke a callback for each element                         |
| `boxSetMap( set, callback )`                  | `.map()`      | Transform each element, deduplicate results into a new Set |
| `boxSetFilter( set, predicate )`              | `.filter()`   | Return a new Set of elements matching the predicate        |
| `boxSetReject( set, predicate )`              | `.reject()`   | Return a new Set of elements NOT matching the predicate    |
| `boxSetReduce( set, callback, initialValue )` | `.reduce()`   | Left-fold with an accumulator function and initial value   |

**Export & Conversion**

| BIF                                | Member Method | Description                                           |
| ---------------------------------- | ------------- | ----------------------------------------------------- |
| `boxSetToArray( set )`             | `.toArray()`  | Convert a Set to an Array, preserving iteration order |
| `boxSetToList( set, [delimiter] )` | `.toList()`   | Join elements into a delimited string                 |

For a deeper guide on BoxLang sets visit our docs: [BoxSet Documentation](https://boxlang.ortusbooks.com/boxlang-language/syntax/sets).

### 📏 Ranges — Lazy, Typed, Iterable Intervals

BoxLang 1.14.0 introduces **Ranges** as a first-class type—a massive evolution from the original `..` operator that simply materialized arrays. Instead of eagerly generating every value up front, ranges are now **lazy, iterable objects** that produce values on demand, making them far more memory-efficient, composable, and expressive for everything from loops and data processing pipelines to scheduling, analytics, and domain modeling. [oai\_citation:0‡Ortus Solutions Community](https://community.ortussolutions.com/t/boxlang-ranges-supercharged/11106?utm_source=chatgpt.com)

What makes BoxLang's implementation particularly unique is that ranges are no longer limited to integers. They natively support **integers, decimals, characters, dates**, and even **custom user-defined types** through the new `IRangeable` interface. Developers can create ascending or descending ranges, define custom step increments, use inclusive or exclusive boundaries, build unbounded or half-bounded ranges, perform membership and boundary checks, and seamlessly integrate with Java Streams for high-performance functional processing. [oai\_citation:1‡Ortus Solutions Community](https://community.ortussolutions.com/t/boxlang-ranges-supercharged/11106?utm_source=chatgpt.com)

Unlike many languages where ranges are little more than syntactic sugar for numeric loops, BoxLang elevates ranges into a rich abstraction for representing intervals and sequences of values. Need every day in a month? Every quarter in a fiscal year? Every character from `a` to `z`? Every version number, semantic identifier, or business object in a custom progression? Ranges make these operations natural, fluent, and type-safe.

Perhaps the most groundbreaking capability is the introduction of the **`IRangeable` interface**, which allows developers to teach BoxLang how to create ranges for their own domain objects. This means you can define ranges over custom types such as software versions, inventory SKUs, workflow states, fiscal periods, geographic coordinates, or any object that has a logical progression. This transforms ranges from a language feature into an extensible framework for modeling real-world sequences and intervals directly in your applications.

By combining lazy evaluation, multiple built-in data types, customizable boundaries and stepping, Java Stream interoperability, and user-extensible range semantics, BoxLang delivers one of the most powerful and flexible range implementations available in any dynamic language today. [oai\_citation:2‡Ortus Solutions Community](https://community.ortussolutions.com/t/boxlang-ranges-supercharged/11106?utm_source=chatgpt.com)

**Basic range syntax:**

```js
// Inclusive range — 1, 2, 3, 4, 5
1..5

// Exclusive boundaries
1>..5      // exclude start: 2, 3, 4, 5
1..<5      // exclude end:   1, 2, 3, 4
1>..<5     // exclude both:  2, 3, 4

// Half-bounded and unbounded
1..        // open-ended from 1 (infinite)
..10       // open-start up to 10 (not iterable)
..         // fully unbounded (contains everything)
```

Ranges are **not arrays** — they're lightweight objects that generate values on demand:

```js
result = arrayToList( 1..5, "," )  // "1,2,3,4,5"
len    = arrayLen( 1..10 )         // 10
```

**Multiple element types:**

```js
// Integers and decimals
1..5                        // 1, 2, 3, 4, 5
3.5..1.5                    // 3.5, 2.5, 1.5 (descending auto-detected)
(0..1).step(0.25)           // 0, 0.25, 0.50, 0.75, 1.00

// Characters
for( c in "a".."e" ) { }    // a, b, c, d, e
for( c in "z".."v" ) { }    // z, y, x, w, v

// DateTime with unit stepping
start = createDate( 2024, 1, 1 )
end   = createDate( 2024, 1, 5 )
(start..end).step( 1, "month" )   // iterate by month
(start..end).step( 1, "week" )    // iterate by week

// Any Comparable type (contains-only, not iterable)
r = "aaa".."zzz"
r.contains( "foo" )    // true — lexicographically between bounds
r.isIterable()         // false — can't enumerate strings
```

**Lazy iteration and streaming:**

Ranges don't allocate memory for their values — huge ranges are cheap:

```js
// This does NOT allocate 100 billion integers
for( i in 1..100_000_000_000 ) {
    result = i
    break  // instant
}

// Full Java Stream API integration
(1..100_000_000_000).stream().limit( 5 ).toList()  // [1, 2, 3, 4, 5]
(1..).stream().limit( 5 ).toList()                 // [1, 2, 3, 4, 5]
```

**Custom stepping:**

```js
arrayToList( (1..10).step(2), "," )   // "1,3,5,7,9"
arrayToList( (10..1).step(-3), "," )  // "10,7,4,1"
```

**Contains semantics:**

Simple ranges use bounds checks, but **stepped ranges** verify step-reachability:

```js
r = 1..10
r.contains( 5 )    // true

// Stepped ranges check reachability
r = (1..10).step(3)  // produces: 1, 4, 7, 10
r.contains( 4 )      // true  (reachable)
r.contains( 5 )      // false (within bounds but NOT reachable by step)
```

**Clamping and position checks:**

```js
(1..10).clamp( 11 )           // 10 — snapped to high boundary
(1..10).clamp( 0 )            // 1  — snapped to low boundary
(1..10).isValueBefore( -3 )   // true
(1..10).isValueAfter( 50 )    // true
```

**Typed unbounded ranges:**

Use `.type()` to constrain an unbounded range to a specific BoxLang type:

```js
(..).contains( "foo" )                    // true (no type constraint)
(..).type("number").contains( "foo" )     // false (wrong type)
(..).type("number").contains( "5" )       // true (coercible to number)
(..).type("integer").contains( 5.5 )      // false (not a whole integer)
```

For exact Java class matching with no coercion, pass a Class reference:

```js
import java:java.lang.Number
(..).type( Number ).contains( 42 )    // true — Integer is a Number
(..).type( Number ).contains( "5" )   // false — strict instanceof
```

**Custom rangeable types via `IRangeable`:**

Any BoxLang or Java class can implement `ortus.boxlang.runtime.types.IRangeable` to participate in ranges:

```js
// Example: Fibonacci sequence as an infinite range
(new Fib()..).stream().limit(10).map( .getCurrent() ).toList()
// [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

(new Fib()..).contains( 13 )   // true — 13 is a Fibonacci number
(new Fib()..).contains( 14 )   // false — 14 is not
```

For a comprehensive guide to BoxLang ranges, including advanced usage patterns and `IRangeable` implementation details, visit our docs: [BoxLang Ranges Documentation](https://boxlang.ortusbooks.com/boxlang-language/syntax/ranges).

### 🧩 Inner Classes and Template Classes

BoxLang now supports **classes defined inline** within scripts (`.bxs`), templates (`.bxm`), or even inside other classes, which enables encapsulation, organization, and scope-local class definitions. These are sometimes called **script classes** or **local classes**.

**Local classes in `.bxs` scripts** define a named class anywhere in a script file and instantiate it with `new`. Classes are hoisted, so you can use `new` before the textual definition:

```js
// Instantiate before the definition — class is hoisted!
result = new Greeter().greet( "World" )

class Greeter {
    function greet( name ) {
        return "Hello, " & name & "!"
    }
}
```

```js
// Multiple local classes with properties and init
class Counter {
    property numeric count default=0

    function increment() {
        variables.count++
    }

    function getCount() {
        return variables.count
    }
}

c = new Counter()
c.increment()
c.increment()
c.increment()
// c.getCount() → 3
```

```js
// Static variables and methods in local classes
class MathUtil {
    static {
        static.MAX_RETRIES = 5
        static.APP_NAME = "MyApp"
    }

    static function add( a, b ) {
        return a + b
    }
}

maxRetries = MathUtil::MAX_RETRIES      // 5
sum        = MathUtil::add( 3, 4 )      // 7
```

**Local classes in `.bxm` templates** — define a class directly inside a `<bx:script>` island within a markup template:

```html
<bx:script>
    class Point {
        function init( x, y ) {
            variables.x = x
            variables.y = y
            return this
        }
        function toString() {
            return "(" & variables.x & "," & variables.y & ")"
        }
    }
    result = new Point( 3, 4 ).toString()
</bx:script>
```

**Classes that extend other classes** — local classes can extend other local classes, abstract classes, and even top-level `.bx` classes, with full polymorphism:

```js
class Animal {
    function speak() {
        return "..."
    }
}

class Dog extends="Animal" {
    function speak() {
        return "Woof!"
    }
}

result = new Dog().speak()  // "Woof!"
```

```js
abstract class Shape {
    abstract function area()
}

class Circle extends="Shape" {
    function init( radius ) {
        variables.radius = radius
        return this
    }
    function area() {
        return 3.14159 * variables.radius ^ 2
    }
}

c = new Circle( 5 )
c.area()  // ~78.54
```

**Local classes with imports** — classes inherit their enclosing script's imports, allowing them to use Java types directly:

```js
import java.util.Date

class Event {
    function init( name ) {
        variables.name       = name
        variables.timestamp  = new Date()
        return this
    }
    function getInfo() {
        return variables.name & " at " & variables.timestamp.toString()
    }
}

result = new Event( "Party" ).getInfo()
// → "Party at Tue Jun 03 12:34:56 UTC 2026"
```

**Inner classes** — classes can also be nested inside other classes:

```js
class Outer {
    class Nested {
        function getValue() {
            return "nested-value"
        }
    }

    function getNested() {
        return new Nested()
    }
}
```

Inner classes are accessed externally via the `$` separator syntax — fully qualified, imported, or with aliases:

```js
// Fully qualified
result = new src.test.java.TestCases.phase3.InnerClassExternal$Widget( "my-widget" )

// Imported with alias
import src.test.java.TestCases.phase3.InnerClassExternal$Widget as MyWidget
result = new MyWidget( "aliased-widget" )

// Static member access
import src.test.java.TestCases.phase3.InnerClassExternal$Widget
typeName = Widget::WIDGET_TYPE
```

You can read more about this feature and see additional examples in our docs: [Inner Classes Documentation](https://boxlang.ortusbooks.com/boxlang-language/classes/inner-classes) and [Template Classes Documentation](https://boxlang.ortusbooks.com/boxlang-language/classes/template-classes).

### 🏗️ Class References as Callable Constructors

BoxLang 1.14.0 introduces a major evolution in object construction by treating **class references as first-class callable objects**. Whether the class originates from BoxLang or Java, imported class references can now participate directly in the language's functional programming model. This removes much of the ceremony traditionally associated with object creation and opens the door to more expressive, composable, and concise code.

Traditionally, object creation required the `new` keyword, which remains fully supported. However, class references can now invoke their constructors directly using `.init()` without requiring `new`, making object construction feel more natural and consistent with the rest of the language. This is particularly useful when working with dynamically resolved classes, dependency injection scenarios, factory patterns, or APIs that return class references at runtime.

Even more powerful is the introduction of **functional constructors**, where the class reference itself becomes callable. Invoking a class reference as a function automatically executes the appropriate constructor and returns a new instance. This provides a clean, Python-inspired syntax that reduces noise while preserving full constructor semantics and compatibility with both Java and BoxLang classes.

Beyond syntactic convenience, this feature unlocks entirely new functional programming patterns. Since class references are now callable objects, they can be passed directly to higher-order functions such as `map()`, `reduce()`, `filter()`, and custom functional pipelines. Transforming collections of raw data into fully instantiated objects becomes remarkably concise, allowing developers to express object creation as a first-class operation rather than wrapping constructors in anonymous functions or lambdas.

This capability also strengthens BoxLang's interoperability story. Java classes and BoxLang classes now share a consistent construction model, reducing cognitive overhead when moving between the two ecosystems. Whether you're instantiating a `StringBuilder`, a custom domain object, or a framework component, the same fluent syntax applies.

Under the hood, class references are wrapped in a specialized `ClassInvokerFunction`, allowing them to participate in the runtime exactly like any other callable object. Constructor invocation is delegated to the same proven instantiation pipeline used by the `new` operator, ensuring consistent behavior, compatibility, and performance while dramatically expanding the expressive power of the language.

```js
// Import a BoxLang Class
import models.User
// Call .init() directly on the class reference — no "new" needed
user = User.init( "Alice", "alice@example.com" )

// Java class — same pattern
import java.lang.StringBuilder
builder = StringBuilder.init( "hello" )

// Works on any expression returning a class
getBuilderClass = () => StringBuilder
builder2 = getBuilderClass().init( "world" )
```

**Class references as functional constructors** — the imported class reference itself can be invoked as a function, which executes the constructor and returns an instance. This provides Python-style constructor ergonomics for both Java and BoxLang classes:

```js
// Import classes
import java.lang.StringBuilder
import models.User

// These three forms are equivalent:
b1 = new StringBuilder( "abc" )
b2 = StringBuilder.init( "abc" )
// b3 is the new functional constructor syntax — call the class reference directly
b3 = StringBuilder( "abc" )

// Same for BoxLang classes:
u1 = new User( "Bob", "bob@example.com" )
u2 = User.init( "Bob", "bob@example.com" )
u3 = User( "Bob", "bob@example.com" )
```

Because class references are callable, they can be passed directly to higher-order functions — a clean functional style for mapping data to objects:

```js
import models.User

names = [ "Alice", "Bob", "Charlie" ]

// Shorthand Functional object creation — all equivalent:
users = names.map( User )
// Long Form approaches
users = names.map( name -> new User( name ) )
users = names.map( name -> User.init( name ) )
users = names.map( name -> User( name ) )
```

Under the hood, class references are wrapped in a `ClassInvokerFunction`, whose `_invoke()` delegates to the same constructor plumbing as the `new` keyword.

### 🔍 DataNavigator JSONPath Support

**What is a DataNavigator?** A `DataNavigator` is BoxLang's fluent helper for safely moving through nested data structures such as Structs, Arrays, parsed JSON, runtime configuration, and metadata. It gives you a consistent API for scoping into data with `from()`, checking whether values exist with `has()`, reading values with `get()`, and applying defaults or strict access rules without scattering null checks throughout your code.

The `DataNavigator` fluent API gains full JSONPath-style expression support in `get()`, `has()`, `from()`, and the new `query()` method for multiple-return scenarios. This makes it much easier to inspect, extract, and reshape deeply nested configuration, JSON, API payloads, module metadata, and mixed Array/Struct data without writing repetitive defensive traversal code.

Developers can now use compact path expressions with dot notation, array indexes, slices, wildcards, recursive descent, and filter expressions directly inside the existing navigator workflow. `get()` remains the best fit when you expect a single value, `has()` can validate deep paths before use, `from()` can scope a navigator to a nested segment, and `query()` returns every match as a BoxLang Array when a path fans out across collections.

This release also adds `getOrDefault()` for explicit fallback values and `getByKey()` / `hasByKey()` for exact-key lookups when real key names contain dots or brackets. Together, these additions make data navigation safer, more expressive, and easier to read, especially in code that consumes external JSON where fields may be optional, irregular, or deeply nested.

**Benefits:**

* Less boilerplate for nested Array/Struct traversal
* Safer handling of optional values with clear fallback behavior
* Multi-result extraction without manual loops
* Better support for real-world JSON payloads and configuration documents
* Exact-key access for data models that use dotted or bracketed key names

**Path expression support:**

```js
nav = dataNavigate( jsonData )

// Dot-notation path expressions in get/has/from
value = nav.get( "boxlang.settings.hello" )
exists = nav.has( "users[?(@.active == true)].email" )
moduleNav = nav.from( "app.modules.auth" )

// Recursive descent — find "key1" anywhere in the tree
found = nav.has( "..key1" )

// Array slicing — 1-based inclusive range
slice = nav.get( "list[1:3]" )

// Wildcard — all values / all elements
all = nav.get( "items[*].name" )
allStructVals = nav.query( "settings.*" )

// Filter expressions with @-current, AND/OR/NOT
active = nav.query( "items[?(@.active == true && @.priority > 2)]" )
named  = nav.query( "items[?(@.active)].name" )
```

**New methods:**

```js
// query() — returns ALL matching values as a BoxLang Array
results = nav.query( "store.products[?(@.price > 100)].name" )

// getOrDefault() — guaranteed non-null return with explicit fallback
port = nav.getOrDefault( "server.port", 8080 )

// getByKey() / hasByKey() — exact key lookup (dots/brackets are literal)
nav.getByKey( "value.sep" )    // treats "value.sep" as a literal key name
```

All path expressions are **whitespace-tolerant** — leading, trailing, and separator-adjacent whitespace is ignored.

For the complete guide, examples, and method reference, visit the [DataNavigator documentation](https://boxlang.ortusbooks.com/boxlang-language/syntax/data-navigators).

### 🧵 Query Transformers & Global Query Options

`queryExecute()` and `bx:query` are locked into three hardcoded return types: `query`, `array`, and `struct`. Users who want tabular arrays, rich column descriptors, JSON, domain objects, or any other format must post-process results in a separate step. Adding new native return types for every use case is unsustainable.

A powerful new **Query Transformer** framework (`BL-2476`) solves this by allowing you to register transformers that process query result sets natively and return exactly what you need — eliminating boilerplate post-processing, since you have access to the full query object and metadata at transformation time.

**Three transformer input types:**

1. **Closure/Lambda** — `(query, metadata) => any` or `(query, metadata) → any`
2. **Class instance** — any class with a `transform(query, metadata)` method
3. **String** — name of a registered transformer from `this.queryTransformers` in `Application.bx`

When `transformer` is provided, it **takes precedence** over `returnType`. The transformer receives two arguments:

* **`query`** — the raw Query object (`.recordCount`, `.toArrayOfStructs()`, `.getData()`, `.getColumnNames()`, etc.)
* **`metadata`** — a struct containing `sql`, `parameters`, `executionTime`, `columnMetadata`, and more

#### Transformer Examples

**1. Inline Closure — Custom Struct with Metadata**

```js
var result = queryExecute( "SELECT * FROM users", [], {
    datasource: "app",
    transformer: ( query, meta ) => {
        return {
            data: query.toArrayOfStructs(),
            total: query.recordCount,
            executedAt: now(),
            sql: meta.sql
        }
    }
} )
// => { data: [...], total: 42, executedAt: ..., sql: "SELECT..." }
```

**2. Inline Closure — Domain Objects**

```js
var users = queryExecute( "SELECT * FROM users", [], {
    datasource: "app",
    transformer: ( query, meta ) => query.toArrayOfStructs().map( row => new User( row ) )
} )
// => [ User{...}, User{...}, ... ]
```

**3. Inline Closure — "Rich" Format with Column Descriptors**

```js
var rich = queryExecute( "SELECT id, name, price, status FROM products", [], {
    datasource: "app",
    transformer: ( query, meta ) => {
        var colMeta = query.getColumnMeta()
        return {
            count: query.recordCount,
            columns: query.getColumnNames().map( name => {
                var info = colMeta[ name ]
                return {
                    name: name,
                    type: info.type,
                    nullable: info.nullable,
                    readOnly: info.readOnly,
                    decimals: info.decimals,
                    maxLength: info.maxLength
                }
            } ),
            data: query.getData().map( row => arrayNew( row ) )
        }
    }
} )
// => { count: 3, columns: [...], data: [[1,"Widget",9.99],...] }
```

**4. Inline Closure — "Tabular" Format (Near Zero-Copy)**

```js
var tabular = queryExecute( "SELECT id, name, price FROM products", [], {
    datasource: "app",
    transformer: ( query, meta ) => {
        return {
            columns: query.getColumnNames(),
            data: query.getData().map( row => arrayNew( row ) )
        }
    }
} )
// => { columns: ["id","name","price"], data: [[1,"Widget",9.99],[2,"Gadget",19.99]] }
```

**5. Class Instance Transformer**

```js
// RichTransformer.bx
class RichTransformer {
    function transform( query, metadata ) {
        var colMeta = query.getColumnMeta()
        return {
            count: query.recordCount,
            columns: query.getColumnNames().map( name => {
                var info = colMeta[ name ]
                return {
                    name: name, type: info.type,
                    nullable: info.nullable, readOnly: info.readOnly,
                    decimals: info.decimals, maxLength: info.maxLength
                }
            } ),
            data: query.getData().map( row => arrayNew( row ) )
        }
    }
}

// Usage
var transformer = new RichTransformer()
var result = queryExecute( sql, params, { transformer: transformer } )
```

**6. Registered Transformers (Application.bx)**

```js
// In Application.bx
this.queryTransformers = {
    "rich": new RichTransformer(),
    "tabular": ( query, meta ) => {
        return {
            columns: query.getColumnNames(),
            data: query.getData().map( row => arrayNew( row ) )
        }
    },
    "json": ( query, meta ) => serializeJson( query.toArrayOfStructs() ),
    "domainUsers": "models.transformers.UserTransformer"
}

// Usage anywhere in the app:
var rich    = queryExecute( sql, params, { transformer: "rich" } )
var tabular = queryExecute( sql, params, { transformer: "tabular" } )
var json    = queryExecute( sql, params, { transformer: "json" } )
var users   = queryExecute( sql, params, { transformer: "domainUsers" } )
```

**7. Transformer Takes Precedence Over returnType**

```js
var result = queryExecute( sql, params, {
    returnType: "array",   // ← ignored when transformer is present
    transformer: ( q, m ) => "custom result"
} )
// => "custom result"
```

**8. bx:query Component**

```html
<bx:query name="result" datasource="app"
    transformer=(( q, m ) => serializeJson( q.toArrayOfStructs() ))>
    SELECT * FROM users
</bx:query>
```

#### Global Query Options (`BL-2477`)

A new **`queries` configuration section** in `boxlang.json` allows global query option defaults, while `this.queryOptions = {}` in `Application.bx` provides application-level default query behaviors.

**boxlang.json:**

```json
// Query Default Options
"queries": {
    // The default timeout for queries in seconds. 0 means no timeout.
    "timeout": 0,
    // The default return type: "query", "array", or "struct"
    "returnType": "query",
    // Number of rows to fetch from database at once (0 = all rows)
    "fetchSize": 0,
    // Maximum number of rows to return (0 = all rows)
    "maxRows": 0,
    // The default named cache to use for query caching
    "cacheProvider": "default"
}
```

**Application.bx:**

```js
// Query Default Options for this application
this.queryOptions = {
    "timeout": 0,
    "returnType": "query",
    "fetchSize": 0,
    "maxRows": 0,
    "cacheProvider": "default"
}
```

All options can be overridden per query via `queryExecute()` options or `bx:query` attributes. Per-query options take highest priority, followed by `this.queryOptions`, with `boxlang.json` as the fallback.

## ✨ New Features

### `schedulerNew()` BIF (BL-2408)

Create and register schedulers directly with a single BIF call — no class file required. Unlike `schedulerStart()` which requires a class path, `schedulerNew()` creates a lightweight, ad-hoc scheduler ready for task registration.

```js
myScheduler = schedulerNew(
    name     = "email-scheduler",
    timezone = "America/Chicago",
    force    = false
)

// Register tasks directly on the scheduler
myScheduler.task( "welcome-email" )
    .call( () => sendWelcomeEmails() )
    .everyHour()
    .startup()
```

Use `schedulerNew()` for lightweight runtime schedulers. Use `schedulerStart()` when you need lifecycle callbacks (`onStartup`, `onShutdown`, `onAnyTaskError`) via a dedicated scheduler class.

### `webMode` Server Identifier (BL-1790)

The `server` scope now exposes a `webMode` boolean indicating whether the runtime is operating in web (servlet/MiniServer) mode.

```js
if ( server.webMode ) {
    // web-specific initialization
}
```

### New String BIFs: `stringStartsWith`, `stringEndsWith` (BL-2439)

Four new Built-In Functions with member-method support for checking string prefix/suffix:

```js
stringStartsWith( "Hello World", "Hello" )     // true
stringEndsWith( "Hello World", "World" )       // true
stringStartsWithNoCase( "HELLO", "hello" )     // true
stringEndsWithNoCase( "WORLD", "world" )       // true

// Member methods
"Hello World".startsWith( "Hello" )
"Hello World".endsWith( "World" )
```

### Left/Right Arrow Key REPL Navigation (BL-2409)

The REPL now supports left and right arrow keys for cursor movement within the current input line — a long-requested quality-of-life improvement for interactive development.

### Formatter: Multiple File Sources & Excludes (BL-2417, BL-2418)

The `boxlang format` command now accepts multiple `--source` files and a new `--excludes` flag for skipping files or directories:

```bash
# Format multiple specific files
boxlang format --source models/User.bx,models/Product.bx

# Format directory but exclude generated and vendor folders
boxlang format --source . --excludes generated,vendor
```

### Formatter: Ignore Comments (BL-2440)

Three styles of formatter-ignore comments are now supported, matching the most popular conventions:

```js
// @formatter:off
uglyCode =    {foo:   "bar"}  // preserved as-is
// @formatter:on

// bxformat-ignore-start
legacyQuery = "SELECT  * FROM    users"
// bxformat-ignore-end

// cfformat-ignore-start
{ unformatted:   true }
// cfformat-ignore-end
```

### Formatter: `template.enabled` Flag (BL-2442)

A new formatter config flag `template.enabled` (defaults to `false`) gates template (`.bxm` / `.cfm`) formatting until it exits experimental mode:

```json
{
  "template": {
    "enabled": false
  }
}
```

### Formatter: `property_spacing` Rule (BL-2443)

The new `class.property_spacing` rule (default: `1`) controls blank lines between property declarations in class bodies — matching Ortus coding standards with a single blank line between properties.

```json
{
  "class": {
    "property_spacing": 1
  }
}
```

### Pretty Print Config Clone (BL-2422)

The `Config` object now supports `.clone()`, enabling safe configuration mutation for multi-pass formatting and tooling scenarios without side effects.

### ResolvedFilePath Dump Template (BL-2428)

`ResolvedFilePath` instances now render with a dedicated HTML dump template showing mapping name, mapping path, relative path, and absolute path — invaluable for debugging module resolution and class loading issues.

### Skills & AGENTS.md Standards (BL-2415)

BoxLang now ships with AI agent skills in `.agents/skills/` and updated `AGENTS.md` standards, providing structured domain knowledge for AI coding assistants working with BoxLang codebases.

### `ON_DATASOURCE_INITIALIZED` Interception Point (BL-2454)

A new interception point fires after a datasource config is loaded but **before** the connection pool is established — giving modules full access to the raw HikariCP configuration for advanced customization:

```js
// In your interceptor
function onDatasourceInitialized( event, interceptData ) {
    var hikariConfig = interceptData.hikariConfig
    hikariConfig.setMaximumPoolSize( 50 )
    hikariConfig.addDataSourceProperty( "cachePrepStmts", true )
}
```

### MiniServer Health Metrics (BL-2455, BL-2456)

The MiniServer `/health` endpoint now includes Undertow worker pool statistics, WebSocket session counts, and additional JVM metrics. The MiniServer also supports static retrieval of the Undertow server instance and XNIO worker for programmatic metrics access.

## 🔧 Improvements

### Language & Runtime

* **`BL-1012`** — `BooleanFormat` and `TrueFalseFormat` consolidated: `TrueFalseFormat` is now a deprecated alias for `BooleanFormat`, scheduled for removal in 2.0.

```js
// Both work; prefer BooleanFormat
booleanFormat( true, "Yes", "No" )   // "Yes"
trueFalseFormat( true, "Ja", "Nein" ) // "Ja" (deprecated alias)
```

* **`BL-2379`** / **`BL-2450`** — Function argument names now blocked from overlapping with import names; validation extended to closure/lambda argument names that shadow imports.
* **`BL-2432`** — Java interop varargs improved: BoxLang arrays passed to Java varargs methods no longer require manual unpacking into `Object[]`.

```js
// Before: manual array packing
javaObj.someMethod( [ arg1, arg2 ].toArray() )

// Now: varargs pass-through
javaObj.someMethod( arg1, arg2 )
```

* **`BL-2436`** — Auto-generate Java method stubs when a BoxLang class extends a Java class, filling in required abstract/interface method implementations.
* **`BL-2437`** — Support import aliases in `extends` and `implements` clauses for Java classes:

```js
import java.util.HashMap as MyMap

class MyCollection extends MyMap {
    // ...
}
```

* **`BL-2459`** — Range type improvements with better element category detection (NUMBER, STRING, CHARACTER, IRANGEABLE, OTHER), enabling faster coercion and broader type support for range operations.
* **`BL-2471`** — Application objects now expose `.getWatchers()`, `.getSchedulers()`, and `.getAppDuration()` for runtime introspection of active watchers, registered schedulers, and application uptime.

### CFML Compatibility & Transpiler

* **`BL-2395`** — CF compat: `form.getPartsArray()` added for compatibility with Adobe CF's form part enumeration.
* **`BL-2397`** / **`BL-2399`** — CF transpiler CLI now supports config loading (by convention or explicit path) and new CLI flags for fine-tuned transpilation control.
* **`BL-2410`** — `FileUpload` now supports `mimeType` as an alias for the `accept` attribute:

```html
<bx:file action="upload" destination="/uploads" mimeType="image/*" />
```

* **`BL-2460`** — Transpile `parameterExists()` to `isDefined()` and quote the parameter name for correct resolution.
* **`BL-2467`** — Transpile `hash( string='test' )` to `hash( input='test' )` — the `string` argument is renamed to `input` to match BoxLang's `hash()` BIF signature.

### Formatter

* **`BL-2397`** — Pretty print config can now be loaded by convention for the CF transpiler CLI tool.
* **`BL-2442`** — New `template.enabled` flag (defaults to `false`) gates experimental template formatting.
* **`BL-2443`** — New `class.property_spacing` rule (defaults to `1`) for consistent property declaration spacing.
* **`BL-2462`** — Semicolons now correctly emitted on required rules when `preserve` is `false`.

### Caching & Data

* **`BL-2472`** — `ICacheStats.toStruct()` now includes cache hit/miss ratios that were previously missing from the stats output.
* **`BL-2473`** — The `remove()` method on cache providers no longer double-JSON-serializes when the result is already a JSON string.
* **`BL-2482`** — UUID values are now JSON-serialized as strings instead of objects, preventing downstream deserialization issues.

### MiniServer & Web

* **`BL-2469`** — Whitespace management now enabled on `text/plain` content types, matching the behavior already present for `text/html`.

### Query & JDBC

* **`BL-2468`** — `fromPendingQuery` and query announcements now include the execution context that was previously missing from the event data.
* **`BL-2485`** — Duplicate logic between `arrayUnique()` and `listRemoveDuplicates()` consolidated into a shared implementation for consistency and maintainability.

### String & Case Utilities

* **`BL-2478`** — PascalCase and KebabCase BIFs updated with additional edge case handling. All case-conversion functions (`snakeCase`, `pascalCase`, `kebabCase`) now robustly handle camelCase, PascalCase, snake\_case, kebab-case, space-separated, and mixed inputs:

```js
snakeCase( "parseXMLHTTPRequest" )    // "parse_xmlhttp_request"
pascalCase( "my-variable" )           // "MyVariable"
kebabCase( "MyClass" )                // "my-class"
```

## 🐛 Bug Fixes (By Area)

### Language & Parser

* **`BL-2424`** — Required function argument with no type no longer parsed as being of type `"required"` under certain conditions.
* **`BL-2425`** — Large `if`/`else` blocks no longer throw `LargeMethodErrors` — the compiler now splits oversized conditional blocks.
* **`BL-2426`** — Current template now correctly reported in an include from inside a function inside a class.
* **`BL-2429`** — Tag-based functions with `output=true` now correctly interpolate variables during parsing.
* **`BL-2430`** — CF transpiler no longer adds `output=true` to functions that don't match CF's default behavior.
* **`BL-2445`** — Interfaces with methods that lack `default` no longer have the `default` modifier incorrectly added, which broke interface contracts.
* **`BL-2452`** — Parser now correctly handles method chaining to expression invocation patterns.
* **`BL-2470`** — Unscoped internal call to a generated accessor setter no longer mis-resolves to a BIF (regression in 1.14.0-snapshot+4460).
* **`BL-2475`** — `try`/`catch` now works correctly within static blocks.

### CFML Compatibility

* **`BL-2331`** — `DateFormat` no longer throws "Can't cast Number to a DateTime" on valid numeric date representations.
* **`BL-2392`** — Cached query metadata no longer mutated by subsequent cache retrievals — a defensive copy is returned.
* **`BL-2405`** — CF's query column passed to array now applies to bracket notation correctly.
* **`BL-2406`** — Template switch cases no longer incorrectly use `break` statements — alignment with CF semantics.
* **`BL-2419`** — `ParseDateTime` now supports `yymmdd` format parsing.
* **`BL-2435`** — CF compat: `arrayMax()`, `arrayMin()`, and `arraySum()` now accept dates in addition to numbers.
* **`BL-2414`** — Adobe CF compatibility: empty form fields removed from form scope list of same-named fields.

### Formatter

* **`BL-2441`** — Formatter no longer adds double assignment expressions when using the `include` keyword.
* **`BL-2444`** — Empty blocks with comments no longer collapse into invalid code.
* **`BL-2447`** — Formatter now adds a line break when an expression is followed by HTML.
* **`BL-2448`** — Include issue fixed where formatter was adding an extra attribute that broke other engines.
* **`BL-2462`** — Semicolons now correctly emitted on required rules when `preserve` is `false`.

### Query & JDBC

* **`BL-2411`** — JDBC trailing semicolon removal now handles multiple semicolons (not just one).
* **`BL-2412`** — QoQ single column in parentheses now takes the column name instead of defaulting to `column_0`.
* **`BL-2413`** — Improved thread safety of large QoQ operations under contention.
* **`BL-2420`** — Data validation now enforced when setting values into query objects.
* **`BL-2421`** — QoQ math operations no longer fail on string data — values are coerced automatically.
* **`BL-2464`** — Query timeout bug fixed — was using the wrong configuration key internally.

### Web & HTTP

* **`BL-2416`** — WebService creation/usage now promotes HTTP/SSL exception messages to the main error message for better debuggability.
* **`BL-2423`** — OData `POST` requests fixed: a `Content-Length: 0` header is now sent to resolve "411 Length Required" errors.
* **`BL-2427`** — `enableOutputOnly` setting now correctly uses output components from the parent context.
* **`BL-2480`** — `writeToBrowser` no longer overrides existing `Content-Disposition` header.
* **`BL-2483`** — Fixed `URISyntaxException` when executing files from paths containing spaces.

### Caching, Serialization & Runtime

* **`BL-2042`** — `LoggingService` concurrent modification exception fixed with thread-safe logger management.
* **`BL-2400`** — Regression fix: `serializeJSON()` no longer stack overflows (1.13 regression).
* **`BL-2402`** — `fileSetLastModified()` now accepts a numeric timestamp in addition to date objects.
* **`BL-2403`** — `Decrypt` BIF now correctly decrypts complex/structured objects — previously corrupted nested data.
* **`BL-2407`** — Scheduler task methods using `(Double period, String timeUnit)` now handle plural time units correctly.
* **`BL-2434`** — `dataNavigate` now honors the default value parameter; a new `getOrDefault()` method provides explicit fallback behavior.
* **`BL-2438`** — Preserve primitive type case (e.g., `int` vs `Int`) in `@overrideJava` fallback stubs.
* **`BL-2458`** — Jackson JR JSON parsing no longer silently ignores trailing content — raises a parse error instead.
* **`BL-2461`** — Return values from interface methods are now properly coerced to the declared return type.
* **`BL-2479`** — `BoxCacheStats.hitRate()` no longer always returns `0` due to integer division — now uses floating-point arithmetic.
* **`BL-2483`** — Fixed `URISyntaxException` when executing files from paths containing spaces.

### Scheduler & Async

* **`BL-2407`** — `ScheduledTask` methods using `(period, timeUnit)` with plural time units (e.g., "hours", "minutes") now work correctly — previously only singular forms were recognized.

### String BIFs

* **`BL-1007`** — `SnakeCase` BIF now correctly converts from camelCase to snake\_case instead of simply replacing spaces. All case-conversion BIFs (`snakeCase`, `pascalCase`, `kebabCase`) handle camelCase, PascalCase, snake\_case, kebab-case, and space-separated inputs.

## 📊 Release Snapshot

* **Release Date:** June 3, 2026
* **Total Issues:** 65
* **Distribution:** 24 New Features, 20 Improvements, 21 Bugs
* **Primary Focus:** Language evolution (sets, inner classes, template classes) and developer experience (formatter, data navigation, REPL)

{% hint style="success" %}
BoxLang 1.14.0 is the recommended update for all teams. The new Dynamic Set type, inner/template class support, JSONPath data navigation, and query transformers are production-ready and bring significant expressiveness and productivity improvements over previous releases.
{% endhint %}


# 1.13.0

April 29, 2026

**BoxLang 1.13.0** is a stability-first release with deep compatibility work and runtime hardening. This build closes **48 issues** (all resolved), with the majority focused on CFML compatibility edge cases, concurrency correctness, formatting parity, and miniserver/runtime reliability under real production loads.

While this release is bug-fix heavy, it still introduces several meaningful features and quality-of-life improvements: character-aware trimming, class metadata lookup by absolute path, process environment control in `SystemExecute()`, SOAP headers, new query column rename capabilities, and safer miniserver routing/security defaults.

Release report: [BoxLang 1.13.0 in Jira](https://ortussolutions.atlassian.net/projects/BL/versions/22840/tab/release-report-all-issues)

## 🚀 Major Highlights

### ✅ Compatibility Parity Sweep (CFML + Formatting)

A large portion of 1.13.0 targets exact behavior parity with Adobe CF/Lucee in places where tiny differences caused real migration friction.

Key parity wins include:

* `numberFormat()` mask compatibility for patterns like `_$,.99`, `,9`, and `$,.00`
* `TimeFormat()` token behavior (`n`/`nn` minutes)
* locale-aware date parsing for `en_AU` and `en_GB`
* query BIF column name trimming behavior
* transpiler fixes around `preserveSingleQuotes()` injection and source type handling
* `cfcatch` `name` attribute support in template syntax

```js
// numberFormat compatibility fixes
numberFormat( 432342, "$,.00" )    // no malformed pattern exception
numberFormat( 1234, ",9" )         // 1,234
numberFormat( 2, "999,999,999" )   // 2 (not 000,000,002)

// TimeFormat minute token fix
timeFormat( now(), "HH:nn" )
```

```js
// Locale-sensitive parse now works correctly for AU/GB day-first dates
setLocale( "en_GB" )
parsed = parseDateTime( "31/01/2026", "dd/MM/yyyy" )
```

### 🧵 Async + Concurrency Hardening

Several race and lifecycle issues have been resolved across async execution, file/class generation, and array iteration.

Notable fixes:

* async API surface normalized (missing methods/signatures corrected)
* `BoxFuture()` context lifecycle fix after HTTP request completion
* race condition fixes for `for/in` array iteration
* atomic class file writes (temp file + atomic rename)

```js
// Spread positional args now supported in function calls
args = [ "Brad", "Wood" ]
fullName = buildName( ...args )
```

The runtime now better protects background work from request teardown timing and avoids transient zero-byte class artifacts on disk.

### 🖥️ Miniserver Reliability + Security

1.13.0 improves miniserver correctness for large transfers and upload edge cases while tightening static-serving protections.

Improvements/fixes include:

* configurable pass predicate (CLI, JSON config, env var)
* stronger static security filter (hidden files, config/source exposure blocked)
* chunked encoding truncation fix for large file responses
* empty text-file upload handling correction

```bash
# CLI pass predicate support
boxlang server start --pass-predicate "/api/*"
```

```json
{
  "web": {
    "passPredicate": "/api/*"
  }
}
```

### 🧰 BoxLang Formatter Tool

One of the biggest practical additions in this release cycle is the maturity jump of the BoxLang formatter (`boxlang format`).

The formatter is now production-usable as both a local developer tool and a CI quality gate:

* wired directly into `boxlang format` CLI action in `BoxRunner`
* supports **check mode** with non-zero exit codes when formatting drift is detected
* auto-discovers config with fallback precedence:
  1. `.bxformat.json`
  2. `.cfformat.json` (auto-converted into formatter config model)
  3. built-in defaults
* supports in-place formatting, stdout mode, and directory recursion
* supports BoxLang + CFML extensions in one pass: `.bx`, `.bxs`, `.bxm`, `.cfm`, `.cfc`, `.cfs`

```bash
# Help and Options
boxlang format --help

# Format project in-place (default behavior)
boxlang format --input ./

# CI gate: fail if any file is not properly formatted
boxlang format --check --input ./

# Print formatted content to stdout without touching files
boxlang format --overwrite false --input ./models/User.cfc
```

Config bootstrap and migration are built in:

```bash
# Generate default formatter config
boxlang format --initConfig

# Convert legacy .cfformat.json to .bxformat.json
boxlang format --convertConfig --input ./
```

Why this matters in 1.13.0:

* **BL-2398** aligns BoxLang-native default formatting with Ortus gold-standard conventions.
* `.cfformat.json` compatibility mode still uses legacy baseline defaults for migration-safe behavior.
* **BL-2396** fixes a source-type regression in the transpiler/pretty-printer pipeline so formatting and source interpretation stay consistent.

This gives teams a safe migration path: keep legacy output behavior where needed, or adopt modern BoxLang-first formatting defaults with `.bxformat.json`.

## ✨ New Features

### `trim()`, `ltrim()`, `rtrim()` gain `chars` argument (BL-2348)

You can now trim custom character sets instead of only whitespace.

```js
"**Urgent**".trim( "*" )        // "Urgent"
"000123".ltrim( "0" )           // "123"
"report....".rtrim( "." )       // "report"
```

### `getClassMetadata( absolutePath )` support (BL-2349)

Class metadata can now be loaded directly from absolute paths, useful for tooling, scanners, and IDE integrations.

```js
meta = getClassMetadata( "/opt/apps/myapp/models/User.bx" )
println( meta.name )
```

### `SystemExecute()` environment controls (BL-2390)

Two new arguments provide deterministic process environment behavior:

* `inheritEnvironment` (default `true`)
* `environment` (struct of env vars)

```js
result = systemExecute(
    name = "env",
    arguments = "",
    inheritEnvironment = false,
    environment = {
        APP_ENV : "production",
        FEATURE_X : "true"
    }
)
```

## 🔧 Improvements

### SOAP header support (BL-2078)

SOAP requests can now include optional `<Header>` blocks for auth/security and cross-cutting metadata.

### `query.setColumnNames()` compatibility API (BL-2333)

Query objects now support column renaming through a dedicated method.

```js
q = queryNew( "fname,lname", "varchar,varchar", [ [ "Ada", "Lovelace" ] ] )
q.setColumnNames( [ "firstName", "lastName" ] )
```

### Miniserver pass predicate configurability (BL-2354)

Routing pass-through is now configurable via:

* `--pass-predicate`
* JSON config
* `BOXLANG_PASS_PREDICATE` environment variable

### Miniserver security handler upgrades (BL-2355)

Static serving now blocks sensitive/unsafe resources more aggressively, including hidden files and framework/source/config artifacts.

### CLI now reads `~/.box.env` (BL-2378)

CLI startup now loads user-level env vars from `~/.box.env`.

```bash
# ~/.box.env
DB_HOST=localhost
DB_PORT=5432
```

## 🐛 Bug Fixes (By Area)

### Async & Threading

* **BL-2269**: Missing async methods/signatures fixed (`all()`, `allApply()`, `thenAsync()`, `delay()`, `shutdownAndAwaitTermination()`), with improved argument conventions.
* **BL-2376**: `BoxFuture()` scope access errors after HTTP request completion resolved via safer context/thread lifecycle handling.
* **BL-2372**: Concurrent modification exception fixed for array `for/in` loops.
* **BL-2373**: Class-file write race fixed with atomic write pattern.

### CF Compatibility / Transpiler

* **BL-2334**: `preserveSingleQuotes()` wrapping narrowed to correct interpolation contexts in query bodies.
* **BL-2335**: `queryNew()` now accepts/ignores `cf_sql_` prefix as expected.
* **BL-2358**: `<cfloop endRow="0">` behavior aligned to "do not loop" semantics.
* **BL-2359**: leading whitespace/line-break trimming behavior matched to CF.
* **BL-2371**: query column names are trimmed consistently in query BIFs.
* **BL-2377** / **BL-2388**: UDF output inheritance behavior corrected inside CFC/include scenarios.
* **BL-2389**: `listQualify()` empty-string list behavior aligned with Adobe.
* **BL-2391**: template `<cfcatch>` now supports `name` variable binding.
* **BL-2396**: transpiler pretty-printer regression fixed for source type handling.

```html
<cfcatch type="any" name="anyError">
    <cfoutput>#anyError.message#</cfoutput>
</cfcatch>
```

### Number & Date Formatting

* **BL-2337**, **BL-2338**, **BL-2339**, **BL-2340**, **BL-2387**: major `numberFormat()` mask compatibility fixes.
* **BL-2362**: `TimeFormat()` minute token handling corrected.
* **BL-2364**: compat parse now accepts formats like `Mar 12 2026 12:00AM`.
* **BL-2375**: day-first locale parsing fixed for AU/GB both via explicit locale arg and `setLocale()`.

### Runtime / Core

* **BL-2336**: abort semantics corrected in web runtime Java `try/catch` boundaries.
* **BL-2343**: deterministic, per-binary AppCDS paths on Windows.
* **BL-2344**: failed superclass init now allows class recreation retries.
* **BL-2350**: graceful `blockfactor=0` validation behavior.
* **BL-2351**: module `onLoad()` request-context setup fixes `dump()` template behavior.
* **BL-2356**: REST CFC service-name mapping corrected.
* **BL-2357**: broad class creation and locator performance optimizations.
* **BL-2360**: positional spread arguments now supported in calls.
* **BL-2361**: JSA package path handling fixed for `BOXLANG_HOME` with spaces.
* **BL-2374**: zero timespan (`createTimeSpan(0,0,0,0)`) correctly interpreted as no-cache.
* **BL-2380**: remote methods now force-write correctly under `enableOutputOnly`.
* **BL-2382**: binary write path fixed for valid downloaded ZIP output.
* **BL-2383**: superclass source changes now detected without requiring child manual recompile.
* **BL-2384**: numeric parsing now handles leading-zero strings safely.
* **BL-2385**: empty text-file upload behavior fixed in miniserver.
* **BL-2386**: QoQ nested-parentheses predicate parsing corrected.
* **BL-2393**: chunked encoding truncation fixed for large-file responses.
* **BL-2394**: custom-tag context no longer leaks incorrect `this` scope.

## 📊 Release Snapshot

* **Release Date:** April 29, 2026
* **Status:** Released
* **Total Issues:** 48
* **Distribution:** 38 Bugs, 8 Improvements, 3 New Features
* **Primary Focus:** CF compatibility parity and runtime stability under concurrency/load

{% hint style="success" %}
BoxLang 1.13.0 is the recommended update for teams migrating CFML applications that depend on edge-case formatting/transpiler parity or running high-concurrency web/miniserver workloads.
{% endhint %}


# 1.12.0

April 8, 2026

**BoxLang 1.12.0** marks a meaningful turning point: after establishing a rock-solid foundation across our runtime, compiler, CFML compatibility layer, and module ecosystem, BoxLang has entered its innovation cycle. The language is mature, battle-tested, and production-deployed by many custmoers now.

Now we're accelerating forward with the kinds of expressive, modern features that make writing BoxLang genuinely enjoyable.

This release packs a lot. On the language side, you get full **struct and array destructuring**, **spread syntax** in both literals and function calls, and a new and clean `..` **range operator** — features you'd expect from any contemporary dynamic language, now native to BoxLang.

The new **directory and file watcher** framework brings real-time filesystem monitoring with a flexible listener API that integrates directly with any `Application.bx`, globally or a-la-carte. **Custom `assert` messages**, a new `getLocalHostIp()` BIF, and **pluggable `getSystemSetting()` namespace providers** round out the feature set. There are also meaningful performance wins: a new method-handle caching strategy, a Java CDS shared archive for faster cold starts, and improved struct iteration.

Under the hood, 1.12.0 continues to sharpen the parser, broaden JDBC coverage, improve compat fidelity, and squash a long list of bugs across locales, date formatting, Oracle stored procedures, symlinks, and more.

If you haven't yet adopted BoxLang for production work, 1.12.0 is an excellent release to do so. The platform is stable, the community is growing, and the language is only getting better from here.

## 🚀 Major Highlights

### 🧩 Struct and Array Destructuring

BoxLang now supports destructuring for both structs and arrays.

If you're new to the term, destructuring is a concise way to pull values out of a struct or array and assign them to variables in a single step, instead of reading each value manually one at a time.

```js
user = { name: "Luis", role: "admin", meta: { team: "core" } }
({ name, meta: { team } } = user)

numbers = [ 1, 2, 3, 4, 5 ]
[ first, ...middle, last ] = numbers
```

In this example, the struct assignment pulls `name` from `user.name` and `team` from the nested `user.meta.team`. The array assignment pulls out the first and last values, while `...middle` captures everything in between as an array. In both cases, destructuring lets you unpack data in one statement instead of writing several separate assignments.

Highlights:

* Struct destructuring with shorthand and explicit renaming
* Array destructuring with positional bindings
* Nested destructuring patterns
* Default values
* Rest capture
* Scoped assignment targets when explicitly named
* Middle-rest support for arrays

### 🌟 Spread Syntax

BoxLang now supports spread syntax in literals and function calls.

If you're new to the term, spread syntax lets you take the contents of an existing array or struct and expand them into a function call or into a new array or struct literal.

```js
args = [ 1, 2, 3 ]
result = add( ...args )

base = { retries: 2 }
config = { host, ...base, debug: true }

merged = [ 0, ...left, ...right ]
```

In this example, `...args` expands the array so its values are passed to `add()` as normal arguments. In the struct literal, `...base` copies the existing keys from `base` into `config` alongside the other values you declare. In the array literal, `...left` and `...right` insert the contents of those arrays into `merged` instead of nesting them. Spread syntax is essentially a way to expand an existing collection into a new call or literal.

Highlights:

* Function-call spread for arrays and structs
* Array literal spread
* Unordered and ordered struct literal spread
* Multi-source merging with declaration-order precedence
* Struct shorthand keys like `{ host, port }`

### 🔢 Inclusive Range Operator

BoxLang now supports the inclusive `..` range operator.

If you're new to the term, a range operator is a compact way to describe a sequence of values between two endpoints. In BoxLang, `..` creates an inclusive integer range, which means it includes both the starting and ending numbers.

```js
1..5   // [1,2,3,4,5]
5..1   // [5,4,3,2,1]
a..b   // endpoints resolved at runtime
```

In this example, `1..5` produces all integers from 1 through 5, while `5..1` produces the same kind of range in descending order. `a..b` means the start and end values can come from variables or expressions, so the final range is determined at runtime based on whatever `a` and `b` contain.

This gives BoxLang a compact way to generate ascending or descending integer ranges.

### 👀 Directory and File Watchers

BoxLang now ships with a built-in `WatcherService` for monitoring directories and reacting to filesystem events in real time. Watchers support multiple listener patterns and integrate cleanly with the application framework.

```js
// Closure listener — quick and simple
watcher = watcherNew(
    name = "sourceWatcher",
    paths = [ "./src" ],
    listener = ( event ) => println( "[#event.kind#] #event.relativePath#" ),
    recursive = true,
    debounce = 250
).start()

// Class instance listener — full control
watcher = watcherNew(
    name = "hotReload",
    paths = [ "./src" ],
    listener = new app.listeners.HotReloadListener(),
    debounce = 300,
    atomicWrites = true
).start()
```

Four listener patterns are supported:

* **Closure** — single function receives all events
* **Struct of closures** — per-kind handlers (`onCreate`, `onModify`, `onDelete`, `onOverflow`) plus optional `onEvent` catch-all
* **Class name string** — runtime instantiates and calls the class
* **Class instance** — a pre-created BoxLang class instance is reused across all events

Application-scoped watchers can also be declared directly in `Application.bx` via `this.watchers` and are auto-started-stopped with the application life-cycle.

```js
// Application.bx
this.watchers = {
    sourceWatcher : {
        paths : [ expandPath( "./src" ) ],
        listener : new app.listeners.HotReloadListener(),
        recursive : true,
        debounce : 250
    }
}
```

Watchers can also be configured globally in `boxlang.json` under the `watchers` key, allowing you to establish file system monitoring at runtime startup without requiring an `Application.bx`.

**New Watcher BIFs:**

| BIF                    | Purpose                                                                      |
| ---------------------- | ---------------------------------------------------------------------------- |
| `watcherNew()`         | Create and register a new filesystem watcher without starting it             |
| `watcherStart()`       | Start a registered filesystem watcher by name                                |
| `watcherStop()`        | Stop a running filesystem watcher by name                                    |
| `watcherRestart()`     | Restart a filesystem watcher by name (stop then start)                       |
| `watcherShutdown()`    | Stop and unregister a filesystem watcher by name                             |
| `watcherStopAll()`     | Stop all running filesystem watchers without removing them from the registry |
| `watcherShutdownAll()` | Stop all filesystem watchers and remove them from the registry               |
| `watcherList()`        | Return an array of all registered filesystem watcher names                   |
| `watcherExists()`      | Check whether a filesystem watcher with the given name is registered         |
| `watcherGet()`         | Get a registered filesystem watcher by name                                  |
| `watcherGetAll()`      | Return all registered filesystem watchers as a struct keyed by name          |

See [Directory + File Watchers](/boxlang-framework/asynchronous-programming/directory-file-watchers) for the full API, BIF reference, listener contracts, and global `boxlang.json` configuration examples.

### ✅ Custom `assert` Messages

The `assert` statement now accepts a custom message after a colon, so you can provide more context when an assertion fails. This message is included in the thrown `AssertException` if the assertion condition evaluates to falsy.

```js
assert user != null : "User must be provided before processing"
assert user.isActive() : "Cannot process an inactive user: #user.name#"
```

### 🌍 `getLocalHostIp()` BIF

A new `getLocalHostIp()` BIF returns the resolved IP address(es) of the local machine:

```js
ip = getLocalHostIp()
println( "Running on: #ip#" )  // e.g. 192.168.1.100
```

### ⚙️ `getSystemSetting()` Pluggable Namespace Providers

`getSystemSetting()` now supports pluggable namespace providers, enabling modules to register custom namespaces for system-setting resolution. Provider lookup is chained so the first match wins.

```js
// Built-in env and Java system-property namespaces still work
dbUrl = getSystemSetting( "DB_URL" )

// Module-registered providers add new namespaces
secret = getSystemSetting( "vault:myapp/db_password" )
```

### 🛑 Custom Error Pages (Web Runtime)

Web applications can now configure custom error pages through `Application.bx` or the runtime configuration, replacing the default BoxLang error output with branded or user-friendly HTML.

### 🔄 CFC Script Wrappers

CFML compatibility now includes script wrapper support for CFC tags, ensuring that ColdFusion CFC patterns compile and execute correctly inside BoxLang.

### 📝 Arbitrary Java Logging Category Redirection

Any Java logging category (e.g., third-party library loggers) can now be redirected to a specific BoxLang logger via `boxlang.json` configuration, giving you full control over noisy library output. This is invaluable when integrating third-party dependencies that produce verbose or unwanted log noise.

```json
{
  "logging": {
    "loggers": {
      "thirdparty": {
        "level": "WARN",
        "appender": "file",
        "additive": false,
        "categories": [
          "org.hibernate",
          "com.zaxxer.hikari",
          "org.springframework"
        ]
      }
    }
  }
}
```

You can also silence a category completely by routing it to a logger configured with `"level": "OFF"`.

## ✨ New Features

### Destructuring declarations and assignments

Struct destructuring supports:

* shorthand bindings
* explicit renaming
* nested patterns
* missing-key defaults
* rest capture for remaining keys
* scoped targets in direct assignments

Array destructuring supports:

* positional bindings
* nested patterns
* rest bindings
* middle-rest extraction
* predictable short-array behavior
* defaults for missing or `null` values

### Spread in function arguments

Function-call spread is supported in both BoxLang and CFML grammars.

Arrays expand as positional arguments.\
Structs expand as named arguments.

This works with:

* built-in functions
* member methods
* closures
* lambdas
* returned function expressions

### Literal spread and shorthand keys

Spread syntax is now supported in these literal forms:

* Array literals like `[ 1, ...values, 4 ]`
* Unordered struct literals like `{ ...defaults, debug: true }`
* Ordered struct literals like `[ ...defaults, retries: 5 ]`

Struct literals also support shorthand keys.

```js
fooBar = "value"
result = { fooBar }
```

### Ambiguous spread-only bracket literals

Spread-only bracket literals are resolved at runtime:

* array sources resolve to arrays
* struct sources resolve to ordered structs
* mixed source types are rejected

{% hint style="warning" %}
Spread-only bracket literal resolution is an experimental edge case. Use explicit keyed members when you want to force ordered-struct syntax.
{% endhint %}

## 🛠️ Improvements

### Performance Improvements

1.12.0 ships a new strategy for method handle caching (BL-2304, BL-2306) that ties caches to their owning class loader, dramatically reducing cache pollution across application reloads. `PagePoolClear` now also flushes these method handle caches (BL-2303), and `entrySet()` on structs has been made more efficient (BL-2282).

A Java Shared Class Data Archive (CDS/SAR) is now generated during install, allowing the native binary to skip class verification on startup and shave significant time off cold starts (BL-2299).

### JDBC Improvements

* **Nested transactions** are now Lucee-compatible — inner transactions use savepoints instead of silently rolling back (BL-2271)
* **Isolation levels** are validated on inner transactions to prevent unsupported combinations (BL-2289)
* **`JDBCStore`** datasource lookup and `Long`→`Integer` cast issues on MySQL are fixed (BL-2265, BL-2268)
* **Inline datasource structs** are now accepted in all locations that previously required a named string (BL-2311)

### `bx:execute` / `systemExecute()` Improvements

Exit codes are now exposed as a return value and via `exitCodeVariable` on both the component and BIF (BL-2262). A blocking deadlock that occurred when the `err` stream buffer filled up has also been resolved (BL-2263).

### Locale and Date Format Fixes

Several long-standing locale and date-format issues have been resolved:

* `monthAsString()` now correctly honours the `locale` argument (BL-2259)
* `DateFormat` methods no longer apply the wrong locale when only a language string is supplied (BL-2260)
* European `dd.MM.yyyy` dates parse correctly (BL-2264)
* `datetimeFormat()` in compat now accepts both `t` and `T` ISO separators and passes through non-mask characters as literals (BL-2322, BL-2323)
* Compat `TimeFormat` `mm` mask behaviour corrected (BL-2295)

## 📚 Documentation

See the new and updated language pages for full syntax and examples:

* [Destructuring](/boxlang-language/syntax/destructuring)
* [Spread Syntax](/boxlang-language/syntax/spread-syntax)
* [Operators](/boxlang-language/syntax/operators)
* [Arrays](/boxlang-language/syntax/arrays)
* [Structures](/boxlang-language/syntax/structures)
* [Directory + File Watchers](/boxlang-framework/asynchronous-programming/directory-file-watchers)
* [Application.bx](/boxlang-framework/applicationbx)

***

## 🎶 Release Notes

### Bugs

[BL-2219](https://ortussolutions.atlassian.net/browse/BL-2219) Application updates made with \`bx:application\` do not persist to subsequent requests

[BL-2239](https://ortussolutions.atlassian.net/browse/BL-2239) template case statement is checking delimiter instead of delimiters

[BL-2259](https://ortussolutions.atlassian.net/browse/BL-2259) MonthAsString Not honoring locale argument correctly

[BL-2260](https://ortussolutions.atlassian.net/browse/BL-2260) Incorrect Locale Being Applied on DateFormat Methods When only only lang string is supplied.

[BL-2261](https://ortussolutions.atlassian.net/browse/BL-2261) bx:execute not setting the \`errorVariable\` correctly

[BL-2263](https://ortussolutions.atlassian.net/browse/BL-2263) systemExecute() can hang when err out buffer is full

[BL-2264](https://ortussolutions.atlassian.net/browse/BL-2264) European dd.MM.yyyy format date parses incorrectly

[BL-2265](https://ortussolutions.atlassian.net/browse/BL-2265) Datasource not found error creating JDBCStore cache

[BL-2266](https://ortussolutions.atlassian.net/browse/BL-2266) Compat: Improve Parsing Performance with Explicit Mask

[BL-2268](https://ortussolutions.atlassian.net/browse/BL-2268) JDBCStore throws Long cannot be cast to class java.lang.Integer on mysql datasources

[BL-2272](https://ortussolutions.atlassian.net/browse/BL-2272) improve fall back serializer for JSON

[BL-2274](https://ortussolutions.atlassian.net/browse/BL-2274) miniserver doesn't follow symlinks

[BL-2278](https://ortussolutions.atlassian.net/browse/BL-2278) parse error on #foo\[1]# neq bar

[BL-2279](https://ortussolutions.atlassian.net/browse/BL-2279) Error calling Oracle proc with proc result after positional args

[BL-2285](https://ortussolutions.atlassian.net/browse/BL-2285) lexer doesn't match non-breaking spaces as whitespace

[BL-2287](https://ortussolutions.atlassian.net/browse/BL-2287) CF truncates startRow and endRow attributes to cfloop

[BL-2288](https://ortussolutions.atlassian.net/browse/BL-2288) content component doesn't handle spreadsheet object passed as binary variable

[BL-2293](https://ortussolutions.atlassian.net/browse/BL-2293) Declare UDF inside of catch block

[BL-2295](https://ortussolutions.atlassian.net/browse/BL-2295) Compat: TimeFormat mm mask behaviour

[BL-2298](https://ortussolutions.atlassian.net/browse/BL-2298) Calling static method from another static method within a closure throws a not found exception

[BL-2301](https://ortussolutions.atlassian.net/browse/BL-2301) CF compat allow invalid cflock types

[BL-2302](https://ortussolutions.atlassian.net/browse/BL-2302) Put actual path in server.coldfusion.rootdir

[BL-2308](https://ortussolutions.atlassian.net/browse/BL-2308) QoQ allow table to have more than one dot

[BL-2312](https://ortussolutions.atlassian.net/browse/BL-2312) XOR operator precedence

[BL-2314](https://ortussolutions.atlassian.net/browse/BL-2314) mis-identifying tag component with comment at end of line

[BL-2315](https://ortussolutions.atlassian.net/browse/BL-2315) queryNew - Unknown Column Type "long"

[BL-2317](https://ortussolutions.atlassian.net/browse/BL-2317) parse error with text operator before decimal

[BL-2318](https://ortussolutions.atlassian.net/browse/BL-2318) inout refcursor params don't work on Oracle stored procs

[BL-2321](https://ortussolutions.atlassian.net/browse/BL-2321) fileWrite() should accept file object, not just a string

[BL-2322](https://ortussolutions.atlassian.net/browse/BL-2322) datetimeFormat() in compat allows t but not T

[BL-2323](https://ortussolutions.atlassian.net/browse/BL-2323) datetime format should passthru non-mask chars

[BL-2325](https://ortussolutions.atlassian.net/browse/BL-2325) directoryList() errors on invalid symlinks in listing

[BL-2329](https://ortussolutions.atlassian.net/browse/BL-2329) Adobe compat

[BL-2330](https://ortussolutions.atlassian.net/browse/BL-2330) CF compat preserveSingleQuotes() not required for UDF calls

### Improvements

[BL-417](https://ortussolutions.atlassian.net/browse/BL-417) Directory / File Watchers

[BL-2220](https://ortussolutions.atlassian.net/browse/BL-2220) Add a custom message to an assert expression statement: assert expression : message

[BL-2252](https://ortussolutions.atlassian.net/browse/BL-2252) Add cfhtmlbody tag for cfml compatibility

[BL-2262](https://ortussolutions.atlassian.net/browse/BL-2262) Allow retrieving exit code in execute component and systemExecute() BIF

[BL-2271](https://ortussolutions.atlassian.net/browse/BL-2271) \[JDBC] Nested transactions are not Lucee-compatible

[BL-2289](https://ortussolutions.atlassian.net/browse/BL-2289) JDBC - Validate isolation levels on inner transactions

[BL-2296](https://ortussolutions.atlassian.net/browse/BL-2296) Return early from isDate for blank strings

[BL-2299](https://ortussolutions.atlassian.net/browse/BL-2299) Introduce the usage and creation of a Java shared archive to improve native binary startups

[BL-2303](https://ortussolutions.atlassian.net/browse/BL-2303) PagePoolClear now clears the method handle caches as well.

[BL-2304](https://ortussolutions.atlassian.net/browse/BL-2304) New approach to caching method handles by leveraging class loader location and unique cachekey resolution class

[BL-2309](https://ortussolutions.atlassian.net/browse/BL-2309) Add missing arrayNew() features needed for compat

[BL-2310](https://ortussolutions.atlassian.net/browse/BL-2310) Allow arbitrary Java logging categories to be redirected to the pre-defined BoxLang loggers

[BL-2311](https://ortussolutions.atlassian.net/browse/BL-2311) Allow datasource as struct in all places

[BL-2313](https://ortussolutions.atlassian.net/browse/BL-2313) repeatString() truncate decimal count

[BL-2319](https://ortussolutions.atlassian.net/browse/BL-2319) Allow compat's onServerStart to run inside of request context

[BL-2320](https://ortussolutions.atlassian.net/browse/BL-2320) getter on runtime to see config path used to load runtime

[BL-2326](https://ortussolutions.atlassian.net/browse/BL-2326) Refactor Config Load to only Merge Environment Overrides Once

[BL-2332](https://ortussolutions.atlassian.net/browse/BL-2332) create dump template for BoxFile

### New Features

[BL-310](https://ortussolutions.atlassian.net/browse/BL-310) Spread operator

[BL-311](https://ortussolutions.atlassian.net/browse/BL-311) Implement Array Destructuring assignment

[BL-312](https://ortussolutions.atlassian.net/browse/BL-312) Implement Struct Destructuring assignment

[BL-2275](https://ortussolutions.atlassian.net/browse/BL-2275) getSystemSetting() pluggable namespace provider support

[BL-2276](https://ortussolutions.atlassian.net/browse/BL-2276) range operator

[BL-2280](https://ortussolutions.atlassian.net/browse/BL-2280) Allow custom error pages used in web runtime

[BL-2282](https://ortussolutions.atlassian.net/browse/BL-2282) Improve performance of entrySet() on structs

[BL-2300](https://ortussolutions.atlassian.net/browse/BL-2300) getLocalHostIp() bif

[BL-2306](https://ortussolutions.atlassian.net/browse/BL-2306) Move method handle caching into related class loader

[BL-2307](https://ortussolutions.atlassian.net/browse/BL-2307) Add new types to systemCacheClear()

### Story

[BL-1827](https://ortussolutions.atlassian.net/browse/BL-1827) CFC script wrappers


# 1.11.0

March 4, 2026

**BoxLang 1.11.0** is a highly focused performance and stability release. The team invested heavily in runtime optimizations across bytecode generation, class loading, lock management, and type casting — delivering measurable speed improvements for nearly every BoxLang application. This release also introduces new developer tooling, enhanced configuration capabilities, and resolves critical concurrency bugs in the locking system and DateTime casting pipeline.

## 🚀 Major Highlights

### ⚡ Performance Wave — Across-the-Board Runtime Speedups

BoxLang 1.11.0 includes over **15 targeted performance improvements** that collectively make every BoxLang application faster with zero code changes required:

**Bytecode & Compilation:**

* **Optimized bytecode generation** to avoid unnecessary casts during value operations
* **Cached `isFinal` and `isAbstract` flags** at compile time instead of computing them at runtime
* **Reworked FQN (Fully Qualified Name) parsing** to avoid expensive regex operations
* **Improved ClassInfo lookup** during compilation using better caching strategies
* **Optimized ClassLocator cache key generation** by improving `hashCode()` creation

**Runtime Execution:**

```js
// These operations are ALL faster in 1.11.0
result = myClass.doWork()           // Faster class construction via this.get()
found = myArray.find( "value" )     // arrayFind optimized, avoids stream overhead
flag = isBoolean( "true" )          // Faster boolean string parsing
someBif( arg1, arg2 )               // Function arg/return type casting via keys, not reflection
```

**Memory & Concurrency:**

* **Cached closest `variables` scope** reference in function contexts
* **Cached web request config** instead of re-resolving per request
* **Case-insensitive string matching** now uses an optimized algorithm
* **Reduced `toRealPath()` calls** that were silently adding overhead on every file operation
* **Simplified constructor path** for Box Classes reduces object creation overhead
* **Removed function inner classes**, reducing class loading and GC pressure
* **Avoided `Map.containsValue()`** in UDF invocation (linear scan → constant time)

### 🔒 Concurrency & Lock Safety

Critical fixes to the exclusive lock and `bx:lock (cflock)` race condition ensure that concurrent sections are truly thread-safe:

**Before 1.11.0**, exclusive locks could occasionally allow more than one thread to enter a supposedly exclusive section under high load. Both [BL-2203](https://ortussolutions.atlassian.net/browse/BL-2203) and [BL-2205](https://ortussolutions.atlassian.net/browse/BL-2205) addressed this:

```js
// This critical section is now truly exclusive under concurrent load
lock name="processPayment_#orderId#" type="exclusive" timeout="30" {
    // Only ONE thread will be here at a time — guaranteed in 1.11.0
    if ( !paymentProcessed( orderId ) ) {
        processPayment( orderId )
    }
}
```

Additionally, lock **storage has been improved** (BL-2201) for better performance and memory efficiency.

### 🗓️ DateTime Casting Reliability

A comprehensive sweep of DateTime casting fixes ensures robust date handling across all common formats:

```js
// All of these now work reliably in 1.11.0
date1 = createDateTime( "01-31-2026 23:59:59" )  // BL-2189
date2 = createDateTime( "9-30-2010" )             // BL-2222
date3 = parseDateTime( "2026-01-31 00:00:00.000" ) // ODBC Timestamp (BL-2143)

// Query of Queries with ODBC Timestamp columns now compiles correctly
qoq = queryExecute(
    "SELECT * FROM myQuery WHERE dateCol > :dt",
    { dt: now() },
    { dbtype: "query" }
)  // BL-2144 - no more compile error

// DateTimeCaster now handles ODBC Date/Time formats
cast1 = dateTimeFormat( odbcDate, "yyyy-mm-dd" )     // BL-2188
```

### 🆕 `enforceUDFTypeChecks` Configuration Setting

A new runtime setting allows you to skip UDF argument and return type validation for maximum compatibility or performance tuning in trusted codebases:

```json
// boxlang.json
{
    "enforceUDFTypeChecks": false
}
```

When set to `false`, BoxLang will skip argument type validation and return type casting on function calls. This acts much how the Java compiler does generic type erasure — it removes the layer of runtime type safety checks, which can improve performance but also means that type mismatches won't throw errors. Thus we always recommend you type your UDFs and keep this setting enabled for the best balance of safety and performance.

### ⏱️ `getTickCount()` — Nanosecond & Second Precision

`getTickCount()` now supports `nano` and `second` units in addition to the existing `millisecond` support:

```js
// Measure with nanosecond precision for micro-benchmarks
start = getTickCount( "nano" )
// ... do work ...
elapsed = getTickCount( "nano" ) - start
println( "Elapsed: #elapsed# ns" )

// Or measure in seconds for coarse timing
start = getTickCount( "second" )
sleep( 2000 )
elapsed = getTickCount( "second" ) - start
println( "Elapsed: #elapsed# seconds" )  // 2
```

### 🗑️ New BIF: `ExecutorDelete()`

The missing `ExecutorDelete()` BIF has been added, completing the executor management API:

```js
// Create an executor
myExecutor = executorNew( "myPool", "fixed", 10 )

// ... use it ...
future = executorSubmit( myExecutor, () => doWork() )

// Clean up when done — now properly removes the executor from the registry
executorDelete( "myPool" )
```

Previously, shutting down an executor did not remove it from the executor registry (BL-2168), which could cause issues when recreating executors with the same name. `ExecutorDelete()` now handles full cleanup.

## 🤖 Core Runtime Updates

### 🏗️ Class System Improvements

* **Super class loading** improved to handle complex inheritance hierarchies more reliably (BL-2211)
* **Abstract class enforcement** relaxed — abstract classes are no longer required to implement all interface methods (BL-2251), matching Java/CFML semantics
* **Typed array returns** no longer throw NPE when a class is instantiated via a different invocation path (BL-2237)
* **Implicit accessors** now generate the correct return type in method signatures instead of always using `any` (BL-2195)
* **`isFinal`/`isAbstract` cached at compile time** for major performance gains during runtime class checks (BL-2254)

### 🧵 Thread & Execution Fixes

* **Executor shutdown** now properly removes the executor from the registry (BL-2168)
* **Parser concurrency** issue in LSP fixed when getting cache size (BL-2253)
* **Duplicate bytecode methods** no longer generated in edge cases (BL-2207)
* **Incompatible stack heights** when not assigning `new Foo()` resolved (BL-2213)
* **Illegal exception table range** in class files fixed (BL-1916)

### 📊 Query System

* **`QueryNew()` and `queryAddRow()`** now properly validate column types (BL-2247)
* **`distinct(col)`** no longer confused with a function name in QoQ (BL-2221)
* **QoQ with ODBC Timestamp** format columns now compiles correctly (BL-2144)
* **Query column scope** no longer found in loops for assignment (BL-2208), fixing variable scoping edge cases

### 🔤 String & Type Improvements

* **`quotedValueList()`** now correctly wraps values in single quotes (not double quotes) per CFML spec (BL-2185)
* **`base64_or_object` and `mimetype` keys** no longer have trailing spaces (BL-2180)
* **`compareTo()` date member method** no longer incorrectly attaches to zero-valued `BigDecimal` (BL-2166)
* **`println()`** can now be called with no arguments to output an empty line — no more `println("")` workaround (BL-2200)

### 🌐 XML Handling

* **Deleting a non-existent key** from `XMLAttribute` no longer throws an error (BL-2231)
* **`XMLChildren`** now updates correctly in all mutation cases (BL-2240)
* **WDDX** now properly escapes special characters in attribute values (BL-2216)

### 🔐 Transaction & Stored Procedures

* **Transaction `end` action** no longer throws an error when a stored procedure was executed within the transaction (BL-2157)
* **Transaction `action` attribute** is now case-insensitive (BL-2238)

## 📡 MiniServer Runtime Updates

### 📁 `.boxlang.json` Convention

The MiniServer now automatically detects and loads a `.boxlang.json` file from the current working directory, merging it with the base BoxLang configuration:

```bash
# If .boxlang.json exists in the project root, it's automatically loaded
$ boxlang server start

# .boxlang.json
{
    "enforceUDFTypeChecks": false,
    "defaultDatasource": "mydb"
}
```

This makes project-level BoxLang configuration portable and self-contained — ideal for containerized deployments and team environments.

### ⚙️ Undertow / Socket / WebSocket Options

You can now influence Undertow, socket, and WebSocket low-level options directly from `miniserver.json`:

```json
{
  "undertow": {
    "ioThreads": 8,
    "workerThreads": 64,
    "bufferSize": 16384
  },
  "socket": {
    "tcpNoDelay": true,
    "reuseAddress": true
  },
  "websocket": {
    "maxFrameSize": 65536,
    "maxTextMessageSize": 65536
  }
}
```

### 📂 Logging Directory Output

The MiniServer now logs the logging directory path during startup (BL-1342), making it easier to locate log files:

```
[BoxLang] MiniServer starting...
[BoxLang] Logging directory: /home/app/.boxlang/logs
[BoxLang] Server started on http://localhost:8080
```

### 🔄 Undertow Upgrade

Undertow has been upgraded to **2.3.23.Final**, bringing the latest HTTP server fixes and security patches to the MiniServer runtime.

## 🌐 Web Support Updates

### 🔀 Pre-Request Interception for Request Rerouting

A new interception point fires **before `onRequestStart`**, enabling interceptors to reroute requests before the application lifecycle begins. This enables powerful request gateway patterns — A/B routing, feature flags, maintenance mode, and tenant routing — all handled before the application overhead kicks in.

## 🛠️ Developer Experience

### 🌳 Enhanced `--bx-printast` Tooling

The `--bx-printast` CLI flag now supports **file paths and standard input piping**, making it far more useful for debugging parser output and build tooling integration:

```bash
# Print AST for a file
boxlang --bx-printast /path/to/MyClass.bx

# Pipe source code directly
echo 'result = 1 + 2' | boxlang --bx-printast

# Integrate with editors/build tools
cat MyComponent.bx | boxlang --bx-printast | jq '.body[0]'
```

### 🧩 SOAP Client — Binary and Map Type Support

The SOAP client now supports additional complex types for requests and responses, including binary data and maps/structs. It also allows you to execute methods directly without using the `invoke()` method, we will route the call to the correct method based on the arguments you pass in.

```js
ws = soap( "http://example.com/DataService?wsdl" )

// Send binary data
result = ws.uploadDocument({
    name: "report.pdf",
    data: fileReadBinary( "/reports/annual.pdf" )  // Binary now supported
})

// Send map/struct data
result = ws.updateRecord({
    id: 123,
    metadata: { region: "US", tier: "premium" }   // Map/Struct now supported
})
```

### 🔧 Session Configuration in `boxlang.json`

Two previously missing session configuration settings are now supported in `boxlang.json`:

```json
{
    "sessionManagement": true,
    "sessionCluster": false
}
```

* **`sessionManagement`** — Enable/disable session management globally
* **`sessionCluster`** — Enable session clustering support across nodes

### 📋 Improved CLI Error Messages

CLI error messages have been improved to provide clearer context and actionable information when BoxLang scripts fail (BL-2212).

## 🐛 Notable Bug Fixes

| Ticket                                                         | Summary                                                                                 |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| [BL-2203](https://ortussolutions.atlassian.net/browse/BL-2203) | Exclusive locks sometimes allowed multiple threads into the locked section              |
| [BL-2205](https://ortussolutions.atlassian.net/browse/BL-2205) | `cflock` race condition under high concurrency                                          |
| [BL-2189](https://ortussolutions.atlassian.net/browse/BL-2189) | Can't cast `01-31-2026 23:59:59` to a DateTime                                          |
| [BL-2143](https://ortussolutions.atlassian.net/browse/BL-2143) | DateTime Default ODBC Timestamp format was incorrectly quoted                           |
| [BL-2157](https://ortussolutions.atlassian.net/browse/BL-2157) | Transaction end threw error when a stored procedure was executed within                 |
| [BL-2165](https://ortussolutions.atlassian.net/browse/BL-2165) | `getCurrentTemplatePath()` didn't work inside a catch block                             |
| [BL-2196](https://ortussolutions.atlassian.net/browse/BL-2196) | ENV secrets expand issue on Docker images due to `*_FILE` greediness                    |
| [BL-2206](https://ortussolutions.atlassian.net/browse/BL-2206) | Parser error with extra pound signs                                                     |
| [BL-2209](https://ortussolutions.atlassian.net/browse/BL-2209) | Module service re-activated modules whose `moduleName` was overridden in `box.json`     |
| [BL-2217](https://ortussolutions.atlassian.net/browse/BL-2217) | Module public remote class requests did not fire Application lifecycle events           |
| [BL-2236](https://ortussolutions.atlassian.net/browse/BL-2236) | CFML compat: `form`, `url`, and `CGI` scopes incorrectly scope-hunted during assignment |
| [BL-2242](https://ortussolutions.atlassian.net/browse/BL-2242) | Compat: Null in switch statement threw error                                            |
| [BL-2251](https://ortussolutions.atlassian.net/browse/BL-2251) | Abstract class incorrectly required to implement all interface methods                  |

## 🔧 Configuration Updates

* **`enforceUDFTypeChecks`** — New boolean setting in `runtime` to disable UDF argument/return type validation
* **`sessionManagement`** — Enable/disable session management globally in `boxlang.json`
* **`sessionCluster`** — Enable distributed session clustering in `boxlang.json`
* **`.boxlang.json` convention** — MiniServer now auto-loads this file from the working directory

***

## 🎶 Release Notes

### Bugs

[BL-1916](https://ortussolutions.atlassian.net/browse/BL-1916) Illegal exception table range in class file

[BL-2002](https://ortussolutions.atlassian.net/browse/BL-2002) cffile upload - upload fails if \`accept\` attribute is added

[BL-2143](https://ortussolutions.atlassian.net/browse/BL-2143) DateTime Default ODBC Timestamp format is being incorrectly quoted

[BL-2144](https://ortussolutions.atlassian.net/browse/BL-2144) QoQ Does not Compile when query contains ODBC Timestamp format

[BL-2157](https://ortussolutions.atlassian.net/browse/BL-2157) Transaction End Throws Error When Stored Procedure is Executed Within

[BL-2160](https://ortussolutions.atlassian.net/browse/BL-2160) Compat: RSA Private Key Encryption Not Supported

[BL-2163](https://ortussolutions.atlassian.net/browse/BL-2163) Exception Util License Exception Check swallows error if message is null

[BL-2165](https://ortussolutions.atlassian.net/browse/BL-2165) getCurrentTemplatePath() doesn't work inside a catch block

[BL-2166](https://ortussolutions.atlassian.net/browse/BL-2166) compareTo() date member method attaching to zero-valued BigDecimal

[BL-2168](https://ortussolutions.atlassian.net/browse/BL-2168) Executor Shutdown was not removing the discarded executor

[BL-2180](https://ortussolutions.atlassian.net/browse/BL-2180) base64\_or\_object and mimetype keys have a space at the end

[BL-2185](https://ortussolutions.atlassian.net/browse/BL-2185) quotedvaluelist() is supposed to wrap in single quotes, not double quotes

[BL-2186](https://ortussolutions.atlassian.net/browse/BL-2186) remote cfc invocation doesn't support argumentCollection

[BL-2188](https://ortussolutions.atlassian.net/browse/BL-2188) DateTimeCaster does not support ODBC Date and ODBC Time formats

[BL-2189](https://ortussolutions.atlassian.net/browse/BL-2189) Can't cast \[01-31-2026 23:59:59] to a DateTime

[BL-2192](https://ortussolutions.atlassian.net/browse/BL-2192) Invoke Webservice does not provide Proper SOAP payload Request

[BL-2195](https://ortussolutions.atlassian.net/browse/BL-2195) Implicit accessors always generate "any" as returntype in method signature

[BL-2196](https://ortussolutions.atlassian.net/browse/BL-2196) ENV secrets expand issue on BoxLang Docker base images due to \*\_FILE greedyness

[BL-2197](https://ortussolutions.atlassian.net/browse/BL-2197) Dump Template Error with Empty Byte Array

[BL-2203](https://ortussolutions.atlassian.net/browse/BL-2203) Exclusive locks sometimes allow multiple threads to enter the locked section

[BL-2205](https://ortussolutions.atlassian.net/browse/BL-2205) cflock race condition

[BL-2206](https://ortussolutions.atlassian.net/browse/BL-2206) Parser error with extra pound signs

[BL-2207](https://ortussolutions.atlassian.net/browse/BL-2207) duplicate bytecode method

[BL-2208](https://ortussolutions.atlassian.net/browse/BL-2208) Don't find query columns in loops for assignment

[BL-2209](https://ortussolutions.atlassian.net/browse/BL-2209) module service re-activates modules whose modulename is overridden in the box.json

[BL-2210](https://ortussolutions.atlassian.net/browse/BL-2210) moduleconfig and BX BIFs are not loaded with consistent mapping path and class names

[BL-2213](https://ortussolutions.atlassian.net/browse/BL-2213) incompatible stack heights when not assigning new Foo()

[BL-2216](https://ortussolutions.atlassian.net/browse/BL-2216) WDDX doesn't escape special chars in attribute values

[BL-2217](https://ortussolutions.atlassian.net/browse/BL-2217) Module public remote Class requests do not fire Application Lifecycle events

[BL-2221](https://ortussolutions.atlassian.net/browse/BL-2221) distinct ( col ) confused with function name

[BL-2222](https://ortussolutions.atlassian.net/browse/BL-2222) DateTime Cast error with \`9-30-2010\`

[BL-2231](https://ortussolutions.atlassian.net/browse/BL-2231) deleting non-existent key from XMLAttribute causes XML error

[BL-2236](https://ortussolutions.atlassian.net/browse/BL-2236) CF doesn't scope hunt form, url, and CGI when assigning

[BL-2237](https://ortussolutions.atlassian.net/browse/BL-2237) Typed array return throws NPE when class is instantiated with a different invocation path

[BL-2238](https://ortussolutions.atlassian.net/browse/BL-2238) Transaction action is case-sensitive

[BL-2240](https://ortussolutions.atlassian.net/browse/BL-2240) XMLChildren doesn't update in all cases

[BL-2241](https://ortussolutions.atlassian.net/browse/BL-2241) rewrite directoryList( absolute\_path=foo )

[BL-2242](https://ortussolutions.atlassian.net/browse/BL-2242) Compat: Null in switch statement throws error

[BL-2243](https://ortussolutions.atlassian.net/browse/BL-2243) Compat: Lock component \`name\` attribute is optional

[BL-2244](https://ortussolutions.atlassian.net/browse/BL-2244) Compat: Empty Values In Query new DateTime-typed Column Throw casting errors

[BL-2245](https://ortussolutions.atlassian.net/browse/BL-2245) Compat: FileUpload allows \`filefield\` to be prefixed with \`Form.\`

[BL-2246](https://ortussolutions.atlassian.net/browse/BL-2246) Compat: \`File\` component action also creates a \`file\` variable, instead of just \`cffile\`

[BL-2247](https://ortussolutions.atlassian.net/browse/BL-2247) QueryNew() and queryAddRow() are missing column type validation

[BL-2251](https://ortussolutions.atlassian.net/browse/BL-2251) Abstract class required to implement all interface methods

[BL-2253](https://ortussolutions.atlassian.net/browse/BL-2253) Parser concurrency issue when getting cache size in LSP

### New Features

[BL-1859](https://ortussolutions.atlassian.net/browse/BL-1859) Add missing session config settings: sessionCluster, sessionManagement in the boxlang.json

[BL-2164](https://ortussolutions.atlassian.net/browse/BL-2164) Web Support: Implement Interception prior to onRequestStart to handle Request Rerouting

[BL-2169](https://ortussolutions.atlassian.net/browse/BL-2169) Add missing BIF: ExecutorDelete()

[BL-2187](https://ortussolutions.atlassian.net/browse/BL-2187) Enhanced boxlang --bx-printast to work with files and stadard in for piping in source code

[BL-2202](https://ortussolutions.atlassian.net/browse/BL-2202) enforceUDFTypeChecks setting to skip UDF argument and return type validation

[BL-2214](https://ortussolutions.atlassian.net/browse/BL-2214) Support nano and second for getTickCount()

[BL-2248](https://ortussolutions.atlassian.net/browse/BL-2248) Add ability to influence the undertow, socket and websocket options from the miniserver.json

### Improvements

[BL-1342](https://ortussolutions.atlassian.net/browse/BL-1342) Consider outputting logging directory when miniserver starts

[BL-2151](https://ortussolutions.atlassian.net/browse/BL-2151) Improve performance of security allowed BIF/component checks

[BL-2152](https://ortussolutions.atlassian.net/browse/BL-2152) Avoid concurrent modification exception in config

[BL-2153](https://ortussolutions.atlassian.net/browse/BL-2153) Performance experiment - reduce toRealPath() calls

[BL-2154](https://ortussolutions.atlassian.net/browse/BL-2154) Simplify constructor path for Box Classes

[BL-2162](https://ortussolutions.atlassian.net/browse/BL-2162) Remove use of function inner classes

[BL-2181](https://ortussolutions.atlassian.net/browse/BL-2181) Ignore empty proxy port in http component

[BL-2184](https://ortussolutions.atlassian.net/browse/BL-2184) Add exceptions for when preserveSingleQuotes() is required

[BL-2199](https://ortussolutions.atlassian.net/browse/BL-2199) Interface for objects which can be represented as binary

[BL-2200](https://ortussolutions.atlassian.net/browse/BL-2200) Allow for println() to print a new line for convenience instead of println( "" )

[BL-2201](https://ortussolutions.atlassian.net/browse/BL-2201) Improve storage of locks for lock component

[BL-2211](https://ortussolutions.atlassian.net/browse/BL-2211) Improve class super class loading

[BL-2212](https://ortussolutions.atlassian.net/browse/BL-2212) Improve CLI error messages

[BL-2215](https://ortussolutions.atlassian.net/browse/BL-2215) Add SOAP Client support for additional complex types - Binary and Map

[BL-2218](https://ortussolutions.atlassian.net/browse/BL-2218) Convention: Miniserver should look for \`.boxlang.json\` file and append it to config

[BL-2223](https://ortussolutions.atlassian.net/browse/BL-2223) Improve parsing of FQN by avoiding regex

[BL-2224](https://ortussolutions.atlassian.net/browse/BL-2224) Use optimized case-insensitive string matching logic

[BL-2225](https://ortussolutions.atlassian.net/browse/BL-2225) improve performance of function arg and return type casting by using keys

[BL-2226](https://ortussolutions.atlassian.net/browse/BL-2226) optimize bytecode to avoid casting where not needed

[BL-2227](https://ortussolutions.atlassian.net/browse/BL-2227) faster parsing for boolean caster looking at strings

[BL-2228](https://ortussolutions.atlassian.net/browse/BL-2228) Optimize ClassInfo lookup when compiling

[BL-2229](https://ortussolutions.atlassian.net/browse/BL-2229) Optimize arrayFind by avoiding streams

[BL-2230](https://ortussolutions.atlassian.net/browse/BL-2230) Improve ClassLocator cache key generation time by caching improving hashCode creation

[BL-2232](https://ortussolutions.atlassian.net/browse/BL-2232) cache closest variables scope ref in function context

[BL-2233](https://ortussolutions.atlassian.net/browse/BL-2233) improve Class creation by using this.get() instead of dereference() which has more overhead

[BL-2234](https://ortussolutions.atlassian.net/browse/BL-2234) improve UDF invocation perf by avoiding Map.containsValue()

[BL-2235](https://ortussolutions.atlassian.net/browse/BL-2235) Cache config in web request context

[BL-2249](https://ortussolutions.atlassian.net/browse/BL-2249) Upgrade undertow to 2.3.23.Final on MiniServer

[BL-2254](https://ortussolutions.atlassian.net/browse/BL-2254) For performance cache isFinal and isAbstract field on classes at compile time

[BL-2255](https://ortussolutions.atlassian.net/browse/BL-2255) Update feature audit to recognize CFC service wrappers

[BL-2256](https://ortussolutions.atlassian.net/browse/BL-2256) Updated Gradle wrapper to 9.3.1

[BL-2257](https://ortussolutions.atlassian.net/browse/BL-2257) Bump Jackson Jr to 2.21.1

[BL-2258](https://ortussolutions.atlassian.net/browse/BL-2258) Bump logback classic to 1.5.32


# 1.10.0

February 3, 2026

**BoxLang 1.10.0** delivers substantial improvements to array manipulation, loop syntax, caching infrastructure, and developer tooling. This release introduces powerful functional programming capabilities with 9 new array methods, enhances loop syntax with destructuring support, and extends the caching system with distributed locking via cache providers. Performance optimizations, particularly in fully-qualified name resolution and ASM compilation, make this one of the most significant releases for developer productivity and application performance.

### 🚀 Major Highlights

#### 🎯 Enhanced Array Manipulation

BoxLang 1.10.0 introduces 9 powerful new array methods that bring modern functional programming capabilities to your arrays:

* **`chunk(size)`** - Split arrays into smaller groups
* **`findFirst(predicate, [default])`** - Find the first matching element with optional default
* **`first([default])`** - Get the first element with optional default value
* **`flatMap(mapper)`** - Map and flatten results in one operation
* **`flatten([depth])`** - Flatten nested arrays to specified depth
* **`groupBy(property|function)`** - Group array elements by key or function
* **`reject(predicate)`** - Filter out elements matching a condition (inverse of `filter()`)
* **`transpose()`** - Convert rows to columns in 2D arrays
* **`unique([type])`** - Remove duplicate values with optional type comparison
* **`zip(array2, [array3...])`** - Combine multiple arrays element-wise

```js
// Chunk for pagination
items = [ 1, 2, 3, 4, 5, 6, 7 ]
pages = items.chunk( 3 )  // [ [1,2,3], [4,5,6], [7] ]

// Find first match with default
users = [ {name:"Alice", age:25}, {name:"Bob", age:30} ]
admin = users.findFirst( (u) => u.role == "admin", {name:"Guest"} )

// Group data for reports
transactions.groupBy( "category" )  // Groups by category key
transactions.groupBy( (t) => t.amount > 100 ? "large" : "small" )

// Flatten nested structures
nested = [ [1, [2, 3]], [4, [5]] ]
nested.flatten()      // [1, 2, 3, 4, 5] - full flatten
nested.flatten( 1 )   // [1, [2, 3], 4, [5]] - one level only

// Zip arrays together
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
combined = names.zip( ages )  // [ ["Alice", 25], ["Bob", 30], ["Charlie", 35] ]

// Transpose matrix
matrix = [ [1,2,3], [4,5,6] ]
matrix.transpose()  // [ [1,4], [2,5], [3,6] ]
```

#### 🔄 For Loop Destructuring

The for loop component now supports elegant destructuring syntax for iterating over collections with both keys/values and items/indexes:

```js
// Collection destructuring - (key, value)
data = { name: "Alice", age: 25, city: "NYC" }
for ( key, value in data ) {
    println( "#key#: #value#" )
}

// Array destructuring - (item, index)
colors = ["red", "green", "blue"]
for ( color, index in colors ) {
    println( "#index#: #color#" )
}

// Query destructuring
for ( row, index in myQuery ) {
    println( "Row #index#: #row.name#" )
}
```

This feature eliminates the verbose `structEach()` and `arrayEach()` patterns while providing cleaner, more readable iteration code.

#### 🔒 Distributed Cache Locking

The Lock component now integrates with cache providers that implement the `ILockableCacheProvider` interface, enabling distributed locking across multiple servers:

```js
// Distributed lock using cache provider
lock( name="processPayment", cache="redisCache", timeout=30 ) {
    // Critical section protected across all servers
    processPayment( orderId )
}

// Traditional local lock still works
lock( name="localLock", type="exclusive", timeout=10 ) {
    updateLocalResource()
}
```

This enables safe concurrent operations in clustered environments without requiring external coordination systems. This requires a distributed cache provider like Redis or Couchbase that implements the locking interface.

#### 📊 Module Service Enhancements

New module loading methods make it easier to dynamically manage BoxLang modules at runtime, especially from Java plugins or extensions:

```js
// Load a single module
moduleService().loadModule( expandPath( "/plugins/myModule" ) )

// Load all modules from a directory
moduleService().loadModules( expandPath( "/extensions" ) )

// Check module status
if ( moduleService().hasModule( "myModule" ) ) {
    settings = moduleService().getModuleSettings( "myModule" )
}
```

### 🤖 Core Runtime Updates

#### Performance Improvements

* **FQN Resolution Performance** - Significant optimization in fully-qualified name resolution, improving class loading and component instantiation
* **ASM Compilation** - Reworked method splitting for large methods with try/catch blocks, improving compilation efficiency and reducing bytecode size
* **Content Component Streaming** - Binary responses now use chunked transfer encoding instead of buffering entire response in memory

#### Type System Enhancements

* **Numeric Casting** - General numeric casting now truncates by default for consistent behavior across integer conversions
* **Set Length Support** - The `len()` function now works on `java.util.Set` collections
* **BigDecimal/Long Support** - `formatBaseN()` now properly handles `java.lang.Long` types

#### Cache Hierarchy

The cache retrieval system now properly follows the context cache hierarchy:

```js
// Application cache takes precedence over global cache
cache( "userSessions" )  // Looks for app-specific cache first, then global
```

This ensures application-level cache isolation while maintaining fallback to global caches.

#### Date/Time Improvements

* New date mask support: `"January, 05 2026 17:39:13 -0600"` format
* Fixed date equality issues in compatibility mode with different timezones
* Resolved `false` being incorrectly cast to DateTime objects in compat mode

#### Query Component Enhancements

* **`queryNew()`** now accepts columns as an array: `queryNew( ["id", "name", "email"] )`
* Relaxed `dbtype` validation on query component for better CFML compatibility
* Fixed Oracle SQL trailing semicolon removal

### 📡 MiniServer Runtime Updates

#### Warmup URLs

The MiniServer now supports warmup URLs to pre-initialize your application before serving production traffic:

```json
{
  "warmupURLs": [
    "http://localhost:8080/api/health",
    "http://localhost:8080/admin/cache/prime"
  ],
  "web": {
    "http": {
      "enable": true,
      "port": 8080
    }
  }
}
```

Warmup requests execute sequentially during server startup, ensuring caches are populated, connections established, and critical initialization complete before the server accepts requests.

### 🛠️ Developer Experience

#### Binary Folder for Module Commands

BoxLang now creates a `bin/` folder in the BoxLang home directory, preparing for future CommandBox integration where modules can provide their own CLI commands and binaries.

```bash
{
    "boxlang" : {
        "executable" : "commandbox"
    }
}
```

#### Runtime Introspection

Two new server scope variables aid debugging and runtime identification:

* **`server.java.pid`** - The Java process ID, making it easy to identify the running JVM process
* **`server.boxlang.compiler`** - Identifies which compiler is active (ASM, Java, or Noop)

```js
println( "Running on PID: #server.java.pid#" )
println( "Using compiler: #server.boxlang.compiler#" )
```

#### JSR-223 Configuration

The JSR-223 scripting engine integration now supports environment variables and system properties for configuration, enabling containerized deployments:

```bash
# Environment variable
export BOX_JSR223_TIMEOUT=30000

# System property
java -Dboxlang.jsr223.timeout=30000 -jar app.jar
```

### 🐛 Notable Bug Fixes

#### Compilation & ASM

* **\[BL-1505]** Reworked splitting of large methods in ASM compiler - fixes complex methods that previously failed to compile
* **\[BL-2017]** Fixed ASM compilation failure with closures inside ternary expressions
* **\[BL-2094]** Fixed double transpilation in string replace operations with nocase flag
* **\[BL-2141]** Resolved parser issue with text operator between two interpolated variables

#### Class & Component System

* **\[BL-2059]** Fixed inheritance at three levels losing variables scope when functions assigned as variables
* **\[BL-2110]** Resolved error calling pseudo constructor when using `getClassMetadata()`
* **\[BL-2117]** Fixed missing metadata annotations on abstract UDFs
* **\[BL-2119]** Interface errors when implementing class doesn't set defaults that interface specifies
* **\[BL-2121]** Injected UDFs now have correct "current" template reference
* **\[BL-2122]** UDF called from thread inside class no longer loses class reference

#### Struct & Collection Handling

* **\[BL-2138]** Fixed struct assignment creating string keys instead of integer keys
* **\[BL-2142]** Resolved string hash collisions in structs causing key conflicts

#### File & I/O Operations

* **\[BL-2095]** File member methods no longer incorrectly accessible on `java.io.File` instances
* **\[BL-2096]** `getCanonicalPath()` now preserves trailing slash on directories
* **\[BL-2118]** Fixed `directoryCopy()` mishandling trailing slashes in some cases
* **\[BL-2124]** Compat mode `directoryCopy()` now overwrites by default for CFML compatibility

#### HTTP & Networking

* **\[BL-2081]** Fixed HTTP timeout error with BigDecimal to Integer casting
* **\[BL-2098]** HTTP component no longer fails when empty string passed for proxy server
* **\[BL-2105]** Resolved duplicate cookies being set with different paths

#### Compatibility Mode Fixes

* **\[BL-1917]** Fixed `urlEncodedFormat()` differences from Lucee/ACF
* **\[BL-2079]** Regression fix for date equality with different timezones in compat mode
* **\[BL-2088]** Compat cache BIFs now properly use context cache retrieval hierarchy
* **\[BL-2091]** Timeout attribute is now optional on lock tag in Lucee compat mode
* **\[BL-2129]** Variable attribute is now optional on execute component in compat mode
* **\[BL-2131]** Compat mode now allows duplicate UDF declarations in CF source files

#### Other Fixes

* **\[BL-2085]** Expired BoxLang+ license no longer kills the runtime
* **\[BL-2089]** Dump template no longer represents `byte[]` as array in output
* **\[BL-2090]** Fixed Java proxy calling no-arg constructor incorrectly
* **\[BL-2097]** `val()` no longer fails with trailing hyphen
* **\[BL-2099]** `queryNew()` now supports columns as array
* **\[BL-2102]** Fixed null logger in LocalizationUtil
* **\[BL-2104]** Associate component now strips `cf_` prefix from baseTag properly
* **\[BL-2134]** Application timeout expiry now properly cancels on `application.shutdown()`
* **\[BL-2145]** Fixed `createTimeSpan()` dropping minutes argument

### 🔧 Configuration Updates

#### Config Utility Helper

New configuration utility helper for getting, casting, defaulting, and validating ad-hoc config values. This standardizes configuration handling across the runtime and modules.

#### Environment Variable Improvements

* Better error messages when importing invalid `BOXLANG_setting=value` env vars
* More consistent environment variable processing during server startup

### ⚡ Migration Notes

#### Array Method Name Changes

If you were using any pre-release versions of the new array methods, verify the method names match the final API. All new methods follow consistent naming conventions.

#### Loop Syntax Enhancement

The new destructuring syntax `for (key, value in struct)` is **additive** - existing loop syntax continues to work unchanged. Gradually adopt the new syntax where it improves readability.

#### Cache Locking

The new distributed cache locking requires cache providers that implement `ILockableCacheProvider`. Standard BoxLang caches and the default cache implementation do not support distributed locking - you must use a cache provider like Redis or Hazelcast that implements this interface.

#### Numeric Casting Behavior

General numeric casting now truncates by default. If you rely on rounding behavior, explicitly use `round()` before casting:

```js
// Old behavior (might round)
num = someDecimal

// New behavior (truncates)
num = someDecimal  // Truncates

// If you need rounding
num = round( someDecimal )
```

#### Oracle SQL

The runtime now automatically removes trailing semicolons from Oracle SQL statements. If you have workarounds for this in your code, you can remove them.

***

### 🎶 Release Notes

#### Improvements

[BL-2075](https://ortussolutions.atlassian.net/browse/BL-2075) Remove Compat DateEquality BIF and update \`equals\` method in DateTime class for lenient comparison

[BL-2080](https://ortussolutions.atlassian.net/browse/BL-2080) Better error message when importing invalid BOXLANG\_setting=value env vars

[BL-2083](https://ortussolutions.atlassian.net/browse/BL-2083) Allow general numeric casting types which truncate by default

[BL-2103](https://ortussolutions.atlassian.net/browse/BL-2103) relax dbtype validation on query component

[BL-2114](https://ortussolutions.atlassian.net/browse/BL-2114) content component to chunk binary responses instead of writing in one go

[BL-2115](https://ortussolutions.atlassian.net/browse/BL-2115) Improve performance in FQN

[BL-2116](https://ortussolutions.atlassian.net/browse/BL-2116) Allow Lock Component to Accept a Cache Attribute and ILockableCacheProvider interface

[BL-2123](https://ortussolutions.atlassian.net/browse/BL-2123) ASM cleanup for split methods with try/catch

[BL-2127](https://ortussolutions.atlassian.net/browse/BL-2127) Allow len() to work on a java.util.Set

[BL-2128](https://ortussolutions.atlassian.net/browse/BL-2128) ModuleService methods to load modules

[BL-2130](https://ortussolutions.atlassian.net/browse/BL-2130) set/clear context classloader on scheduled task threads

[BL-2131](https://ortussolutions.atlassian.net/browse/BL-2131) compat - allow dupe UDF declarations in CF source

[BL-2146](https://ortussolutions.atlassian.net/browse/BL-2146) Remove trailing semicolons in Oracle SQL

#### Bugs

[BL-1505](https://ortussolutions.atlassian.net/browse/BL-1505) Rework splitting of large methods in ASM

[BL-1917](https://ortussolutions.atlassian.net/browse/BL-1917) Compat: urlEncodedFormat difference from lucee/acf

[BL-2017](https://ortussolutions.atlassian.net/browse/BL-2017) ASM won't compile closure inside ternary

[BL-2059](https://ortussolutions.atlassian.net/browse/BL-2059) Inheritance at Three Levels Loses Variables Scope when Function is assigned as a variable

[BL-2076](https://ortussolutions.atlassian.net/browse/BL-2076) \`false\` incorrectly being cast to DateTime objects when using \`.equals\` in compat mode

[BL-2079](https://ortussolutions.atlassian.net/browse/BL-2079) Regression: EqualsEquals and Compare in compat for dates is now failing with different timezones.

[BL-2081](https://ortussolutions.atlassian.net/browse/BL-2081) HTTP Timeout Error - BigDecimal cannot be cast to class java.lang.Integer

[BL-2085](https://ortussolutions.atlassian.net/browse/BL-2085) An expired BL+ license seems to kill the runtime

[BL-2086](https://ortussolutions.atlassian.net/browse/BL-2086) formatBaseN does not handle java.lang.long

[BL-2087](https://ortussolutions.atlassian.net/browse/BL-2087) cache() bif not using the context cache retrieval hierarchy

[BL-2088](https://ortussolutions.atlassian.net/browse/BL-2088) compat cache bifs, need to get the cache via the context to do cache hierarchies retrieval

[BL-2089](https://ortussolutions.atlassian.net/browse/BL-2089) Dump Template should not Represent \`byte\[]\` as an array in output

[BL-2090](https://ortussolutions.atlassian.net/browse/BL-2090) Passing java proxy to method calls no-arg constructor

[BL-2091](https://ortussolutions.atlassian.net/browse/BL-2091) timeout attribute is optional to cflock tag in Lucee

[BL-2094](https://ortussolutions.atlassian.net/browse/BL-2094) transpile once to one for replace/nocase

[BL-2095](https://ortussolutions.atlassian.net/browse/BL-2095) file member methods incorrectly accessible on java.io.File instances

[BL-2096](https://ortussolutions.atlassian.net/browse/BL-2096) getCanonicalPath() not preserving trailing slash on directories

[BL-2097](https://ortussolutions.atlassian.net/browse/BL-2097) val() fails with trailing hypen

[BL-2098](https://ortussolutions.atlassian.net/browse/BL-2098) http component fails when empty string passed for proxy server

[BL-2099](https://ortussolutions.atlassian.net/browse/BL-2099) queryNew() doesn't support columns as an array

[BL-2101](https://ortussolutions.atlassian.net/browse/BL-2101) application component should not allow a body

[BL-2102](https://ortussolutions.atlassian.net/browse/BL-2102) logger can be null in localizationutil

[BL-2104](https://ortussolutions.atlassian.net/browse/BL-2104) associate component needs to strip cf\_ prefix from baseTag

[BL-2105](https://ortussolutions.atlassian.net/browse/BL-2105) Duplicate Cookies being set with different paths

[BL-2110](https://ortussolutions.atlassian.net/browse/BL-2110) Error calling pseudo constructor when using getClassMetadata()

[BL-2117](https://ortussolutions.atlassian.net/browse/BL-2117) Metadata annotations missing on abstract UDFs

[BL-2118](https://ortussolutions.atlassian.net/browse/BL-2118) directoryCopy() mishandling trailing slashes in some cases

[BL-2119](https://ortussolutions.atlassian.net/browse/BL-2119) Interface Errors when Implementing Class does not set default when interface does

[BL-2121](https://ortussolutions.atlassian.net/browse/BL-2121) Injected UDFs have incorrect "current" template

[BL-2122](https://ortussolutions.atlassian.net/browse/BL-2122) UDF called from thread inside class loses class reference

[BL-2124](https://ortussolutions.atlassian.net/browse/BL-2124) Compat directoryCopy() overwrites by default

[BL-2129](https://ortussolutions.atlassian.net/browse/BL-2129) Compat variable attr is optional on execute component

[BL-2134](https://ortussolutions.atlassian.net/browse/BL-2134) New application timeout expiry was not cancelling on applicatoin.shutdown

[BL-2138](https://ortussolutions.atlassian.net/browse/BL-2138) struct assignment creating string keys instead of int keys

[BL-2141](https://ortussolutions.atlassian.net/browse/BL-2141) Parser issue with text operator between two interpolated vars

[BL-2142](https://ortussolutions.atlassian.net/browse/BL-2142) string hash collisions in structs

[BL-2145](https://ortussolutions.atlassian.net/browse/BL-2145) CreateTimeSpan Dropping Minutes Argument

#### New Features

[BL-276](https://ortussolutions.atlassian.net/browse/BL-276) Support for loop (key, value) in collection and (item, index) in lists

[BL-2084](https://ortussolutions.atlassian.net/browse/BL-2084) Create config util helper for getting/casting/defaulting/validating ad-hoc config

[BL-2100](https://ortussolutions.atlassian.net/browse/BL-2100) Allow env var/sys prop config options for JSR-223

[BL-2120](https://ortussolutions.atlassian.net/browse/BL-2120) January, 05 2026 17:39:13 -0600 date mask

[BL-2125](https://ortussolutions.atlassian.net/browse/BL-2125) New Array/Member Methods and improvements: chunk(), findFirst(), first( default ), flatMap(), flatten(), groupBy(), reject(), transpose() , unique(), zip()

[BL-2132](https://ortussolutions.atlassian.net/browse/BL-2132) Create a \`bin\` folder in the BoxLang home in preparation of CommandBox next for module binaries

[BL-2133](https://ortussolutions.atlassian.net/browse/BL-2133) Add server.java.pid to easy identify the java process

[BL-2137](https://ortussolutions.atlassian.net/browse/BL-2137) MiniServer support for warmup urls

[BL-2139](https://ortussolutions.atlassian.net/browse/BL-2139) Add server.boxlang.compiler to know which compiler you are on easily


# 1.9.0

January 8, 2026 - Happy New Year! BoxLang 1.9.0 is a significant stability and compatibility release, focusing on production-readiness through enhanced lifecycle management, comprehensive CFML compati

BoxLang 1.9.0 is a significant stability and compatibility release, focusing on production-readiness through enhanced lifecycle management, comprehensive CFML compatibility improvements, and critical bug fixes. This release introduces array-based form field parsing conventions, improved datasource lifecycle management, enhanced metadata capabilities, and resolves over 50 bugs to ensure rock-solid reliability for enterprise applications.

## 🚀 Major Highlights

### 📦 Array-Based Form Field Parsing Convention

BoxLang now supports automatic parsing of query parameters and form fields as arrays using naming conventions, making it easier to work with multiple values without manual parsing:

```js
// HTML form with multiple checkboxes
<form method="POST">
    <input type="checkbox" name="colors[]" value="red" />
    <input type="checkbox" name="colors[]" value="blue" />
    <input type="checkbox" name="colors[]" value="green" />
    <button type="submit">Submit</button>
</form>

// BoxLang automatically parses as array
selectedColors = form.colors
// selectedColors is now an array: ["red", "blue", "green"]

// Works with query parameters too
// URL: /page?tags[]=boxlang&tags[]=java&tags[]=modern
tags = url.tags
// tags is now an array: ["boxlang", "java", "modern"]

// Traditional single values still work
name = form.name  // Single string value
```

**Benefits:**

* No manual `listToArray()` conversions needed
* Consistent with modern web framework conventions
* Backward compatible with existing code
* Works with both form fields and URL parameters

### 🔄 Enhanced Context Lifecycle Management

Significant improvements to context management and shutdown handling ensure proper cleanup and prevent resource leaks:

**Context Thread Tracking**: Contexts now maintain counters for active threads, preventing premature cleanup:

```js
component {
    function onApplicationStart() {
        // Application initialization
        application.dataSource = createDataSource()
        application.cache = createCache()
    }

    function onApplicationEnd() {
        // Proper cleanup with new lifecycle hooks
        application.cache.shutdown()
        application.dataSource.close()
        writeLog( "Application shutdown complete" )
    }

    function onSessionEnd( sessionScope, applicationScope ) {
        // Enhanced session end handling
        // Now properly handles errors without leaving session in broken state
        try {
            sessionScope.cleanup()
        } catch( any e ) {
            writeLog( "Session cleanup error: #e.message#", "error" )
        }
    }
}
```

**Key Improvements:**

* Web request contexts can detach from original exchange during shutdown
* ORM context removal moved to shutdown listeners for proper cleanup
* Session errors no longer leave sessions in permanently expired state
* Proper application startup via `runtime.executeXXX()` methods
* Prevention of session starts during application initialization

### 🧹 SOAP Client Improvements

The SOAP client introduced in 1.8.0 has been enhanced with proper class structure and HTTP method access:

```js
// Create SOAP client with full class capabilities
ws = soap( "http://example.com/service.wsdl" )

// SOAP client now has access to underlying HTTP methods
ws.setTimeout( 60 )
ws.setHeader( "Authorization", "Bearer token123" )

// Invoke SOAP methods with improved reliability
result = ws.invoke( "getUserInfo",  123 )
println( "User: #result.name#" )
```

## 🤖 Core Runtime Updates

### 🗄️ Datasource Lifecycle Management

Critical improvements to datasource lifecycle prevent resource leaks and connection pool issues:

**Proper Shutdown Handling**:

```js
// Application.bx
component {
    this.name = "MyApp"

    this.datasources = {
        "mydb" : {
            driver : "mysql",
            host : "localhost",
            database : "appdb",
            username : "user",
            password : "pass"
        }
    }

    function onApplicationEnd() {
        // Datasources now properly shutdown when application ends
        // No more connection pool leaks across application restarts
        writeLog( "Datasources cleaned up automatically" )
    }
}
```

**Fixed Issues:**

* Application-level datasources now shut down when application ends
* Server-level datasources no longer create duplicate pools per application
* Application caches properly removed on application end
* Connection pool cleanup during application lifecycle

### 📊 Query and JDBC Enhancements

Comprehensive improvements to query handling and database operations:

**Query Metadata Refactoring**: Query metadata responsibility properly separated to `QueryMeta` class for better performance and maintainability.

**Oracle Database Improvements**:

```js
// Named parameters now work correctly
queryExecute(
    "SELECT * FROM users WHERE id = :userId AND status = :status",
    {
        userId : { value: 123, type: "integer" },
        status : { value: "active", type: "varchar" }
    },
    { datasource: "oracle_ds" }
)

// Stored procedures with ref cursors work correctly
storedproc procedure="getUserData" datasource="oracle_ds" {
    procparam type="in" value=123 cfsqltype="cf_sql_integer"
    procparam type="out" variable="result" cfsqltype="cf_sql_refcursor"
}
// Ref cursor params now work regardless of position

// Unused procresult tags are properly ignored
storedproc procedure="processData" datasource="oracle_ds" {
    procresult name="unused"  // No error if not returned
    procparam type="in" value="data"
}
```

**Parameter Handling**:

```js
// Empty lists in queryparam now handled correctly (CFML compat)
query name="filtered" {
    writeOutput( "
        SELECT * FROM products
        WHERE category IN (
            <bx:queryparam value='#categoryList#' list='true' />
        )
    " )
}

// SQL params using integer type now properly validate instead of truncating
queryExecute(
    "INSERT INTO scores (value) VALUES (?)",
    [ { value: 95.5, type: "integer" } ]  // Now throws error instead of truncating to 95
)

// VARCHAR params now match CHAR fields correctly in Oracle
```

**Query of Queries**:

```js
// NULL comparisons with LIKE now work correctly
query1 = queryNew( "name,description", "varchar,varchar", [
    [ "Product 1", null ],
    [ "Product 2", "A great product" ]
] )

result = queryExecute(
    "SELECT * FROM query1 WHERE description LIKE '%product%'",
    {},
    { dbtype: "query" }
)
// Properly handles NULL values without errors
```

### 🔢 Number Handling Improvements

Significant enhancements to numeric type handling and serialization:

**Scientific Notation Prevention**:

```js
// Doubles now serialize without scientific notation
bigNumber = 1234567890.123456
jsonStr = serializeJSON( { value: bigNumber } )
// Output: {"value":1234567890.123456}
// NOT: {"value":1.234567890123456E9}

// BigDecimals also serialize cleanly
amount = preciseValue( "999999999.99" )
jsonStr = serializeJSON( { amount: amount } )
// Output: {"amount":999999999.99}

// Scientific notation literals with leading zeros now parse correctly
value = 0001.5e2  // Now works: 150
```

**Double Caster Improvements**:

```js
// String-to-double conversion now trims whitespace
value = toNumeric( "  42.5  " )  // Now works: 42.5

// Currency BIFs properly validate currency codes
formatted = lsCurrencyFormat( 100, "" )  // Now throws error for empty currency code
formatted = lsCurrencyFormat( 100, "USD" )  // Works correctly
```

### 🎭 Enhanced Class Metadata

Class metadata now includes `static` and `abstract` flags for functions:

```js
// Component with static and abstract methods
abstract class  {
    static function getVersion() {
        return "1.9.0"
    }

    abstract function process()
}

// Inspect metadata
meta = getMetadata( MyClass )
functionMeta = meta.functions[ "getVersion" ]

println( "Is static: #functionMeta.static#" )      // true
println( "Is abstract: #functionMeta.abstract#" )  // false

// Use in reflection scenarios
if( functionMeta.static ) {
    // Call without instance
    version = invoke( MyClass, "getVersion" )
}
```

**Additional Metadata Improvements**:

* Component metadata now returns struct for `implements` (not string)
* Interface metadata properly structured in all scenarios
* Doc comments preserve line breaks for better documentation
* Doc comments immediately inside script blocks now associate properly

### 🔐 Transaction Component Cleanup

Removed unused `nested` boolean attribute from transaction component for cleaner API:

```js
// Simplified transaction syntax
transaction {
    queryExecute( "INSERT INTO users (name) VALUES (?)", [ "John" ] )
    queryExecute( "INSERT INTO logs (action) VALUES (?)", [ "user_created" ] )
}

// Nested transactions work automatically without configuration
transaction {
    queryExecute( "UPDATE accounts SET balance = balance - 100 WHERE id = 1" )

    transaction {
        queryExecute( "UPDATE accounts SET balance = balance + 100 WHERE id = 2" )
    }
}
```

## 📡 MiniServer Runtime Updates

### 📄 JSON Configuration Support

MiniServer now supports loading configuration from JSON files (introduced in 1.8.0, finalized in 1.9.0):

```bash
# Automatically loads miniserver.json from current directory
boxlang-miniserver

# Specify custom config file
boxlang-miniserver /path/to/config.json
```

**Configuration Example**:

```json
{
    "port": 8080,
    "webRoot": "./www",
    "debug": true,
    "rewrites": true,
    "rewriteFileName": "index.bx",
    "healthCheck": true
}
```

## 🛠️ Developer Experience

### 🎯 Improved Error Messages

Better error reporting for interception announcements and general exceptions.

### 📝 Mid() Function Improvement

The `mid()` BIF now has optional count parameter for more flexible string extraction:

```js
// Extract from position 5 to end of string
text = "Hello World"
result = mid( text, 5 )  // "o World"

// Extract with count (existing behavior)
result = mid( text, 5, 3 )  // "o W"

// More intuitive substring extraction
greeting = "Good Morning Everyone"
timeOfDay = mid( greeting, 6, 7 )  // "Morning"
remainder = mid( greeting, 14 )     // "Everyone"
```

### 🔍 Better Class Inspection

Classes and Java class dumps improved with better error handling:

```js
// Dump complex objects without errors
dump( application.wirebox )  // Now works correctly

// Java class dumps handle BoxClass fields properly
javaObj = createObject( "java", "com.example.MyClass" )
dump( javaObj )  // No more template errors
```

## 🐛 Notable Bug Fixes

### CFML Compatibility Improvements

* **ListDeleteAt**: Now retains leading delimiters for proper CFML compatibility
* **ListAppend**: Behavior now matches CFML exactly
* **Boolean Strings**: Characters 'y' and 'n' properly recognized as booleans in compat mode
* **Session IDs**: SessionID in session scope properly prefixed with app identifier when J2EE sessions enabled
* **GetComponentMetaData**: Returns proper struct for `implements` instead of string

### File Operations

* **File Upload**: `result` field now properly populated after upload
* **Content Types**: Upload `contentType` no longer incorrectly includes `contentSubType`
* **File Append**: `action="append"` now correctly appends with proper line breaks

### String and List Operations

* **CreateUUID**: Now returns standard UUID format
* **ReReplace**: Fixed index out of bounds errors
* **DateAdd**: `datepart` parameter no longer case-sensitive
* **DateTime Parsing**: Fixed casting issues with datetime formats like "Dec/13/2025 08:00"

### Session and Cookie Handling

* **Session End Errors**: Errors in `onSessionEnd` no longer leave session in permanently expired state
* **Session Prevention**: Sessions no longer inadvertently start during application initialization
* **Cookie Serialization**: `bx:cookie` now serializes time in GMT as expected

### Core Runtime Fixes

* **Duplicate**: `duplicate()` now properly handles recursive references
* **ExpandPath**: Works correctly outside of request context (e.g., in `onServerStart`)
* **For Loops**: Now work properly with Java primitive arrays
* **Evaluate**: Properly uses CF transpiler when called from CF source
* **Whitespace**: Preserve whitespace no longer consumes excessive line breaks
* **Class Loading**: Fixed race conditions when multiple threads load the same class

### Database and ORM

* **Redis Query Caching**: Fixed serialization issues with cached queries
* **ORM Datasources**: ORM can now properly find datasources without errors
* **Stored Procedure Return Codes**: Now use correct key names

### Memory and Threading

* **Stream Handling**: Fixed "Stream is closed" errors (UT010029)
* **Context Threading**: Proper handling of contexts with multiple active threads
* **Comparison Sorting**: Fixed "Comparison method violates its general contract" errors

## 🔧 Configuration Updates

### HTTP Multipart Simplification

HTTP file uploads no longer require explicit `multipart()` call in many cases:

```js
// Automatic multipart detection
http( "https://api.example.com/upload" )
    .post()
    .file( "document", "/path/to/file.pdf" )
    .send()
// multipart() automatically applied when files present

// Still available for explicit control
http( "https://api.example.com/upload" )
    .post()
    .multipart()
    .file( "document", "/path/to/file.pdf" )
    .formField( "description", "Important file" )
    .send()
```

## ⚡ Migration Notes

### Breaking Changes

This release focuses on bug fixes and compatibility improvements with minimal breaking changes:

1. **SQL Parameter Validation**: Integer SQL type now properly validates instead of silently truncating decimals. Update queries that incorrectly used integer type for decimal values:

```js
// Old code (was silently truncating)
queryExecute( "INSERT INTO scores VALUES (?)", [ { value: 95.5, type: "integer" } ] )

// Update to proper type
queryExecute( "INSERT INTO scores VALUES (?)", [ { value: 95.5, type: "decimal" } ] )
```

2. **Currency BIF Validation**: Empty strings no longer accepted as currency codes:

```js
// Old code (was accepting empty string)
formatted = lsCurrencyFormat( 100, "" )

// Update to proper currency code
formatted = lsCurrencyFormat( 100, "USD" )
```

3. **Transaction Nested Attribute**: The unused `nested` attribute has been removed from the transaction component. Simply remove any references to it as nesting is automatic.

### Upgrade Recommendations

**For Production Applications**:

* Review any custom SQL parameter handling that relied on integer truncation
* Test file upload operations to verify new `result` field population
* Verify datasource connection cleanup in long-running applications
* Test session lifecycle if custom `onSessionEnd` error handling was implemented

**For CFML Migrations**:

* List operations now match CFML behavior more closely - test list manipulation code
* Session handling improved for J2EE compatibility - test session management
* DateTime parsing enhanced - verify any custom date handling code

**Performance Improvements**:

* Datasource connection pools no longer duplicated per application - may see memory improvements
* Query metadata generation optimized - queries may execute slightly faster
* Cache eviction more efficient - better memory utilization in cache-heavy applications

***

## 🎶 Release Notes

### Improvements

[BL-2005](https://ortussolutions.atlassian.net/browse/BL-2005) Query object should not be building it's own metadata, the responsibility lies on the QueryMeta class

[BL-2006](https://ortussolutions.atlassian.net/browse/BL-2006) Ensure Doubles are converted to strings without using scientific notation

[BL-2016](https://ortussolutions.atlassian.net/browse/BL-2016) ignore unused procresult tags in Oracle

[BL-2023](https://ortussolutions.atlassian.net/browse/BL-2023) Consider removing the requirement to add multipart()

[BL-2024](https://ortussolutions.atlassian.net/browse/BL-2024) JDBC - Drop unused 'nested' boolean attribute from Transaction component

[BL-2028](https://ortussolutions.atlassian.net/browse/BL-2028) BoxLang Class Meta now has a static and abstract : boolean key for functions

[BL-2033](https://ortussolutions.atlassian.net/browse/BL-2033) preserve line breaks in doc comments

[BL-2035](https://ortussolutions.atlassian.net/browse/BL-2035) Allow web request context to detach from original exchange on shutdown if still in use

[BL-2036](https://ortussolutions.atlassian.net/browse/BL-2036) Add mechanism for contexts to keep a counter of how many threads are still using them

[BL-2041](https://ortussolutions.atlassian.net/browse/BL-2041) Run boxcache evictChecks during reap

[BL-2045](https://ortussolutions.atlassian.net/browse/BL-2045) Double caster should trim incoming strings

[BL-2051](https://ortussolutions.atlassian.net/browse/BL-2051) Improve error when announcing interceptions

[BL-2052](https://ortussolutions.atlassian.net/browse/BL-2052) Move ORM context removal to shutdown listener

[BL-2061](https://ortussolutions.atlassian.net/browse/BL-2061) Compat: SessionID in Session Scope is not prefixed with app identifier when J2EE sessions are enabled

[BL-2062](https://ortussolutions.atlassian.net/browse/BL-2062) Ensure proper app startup via runtime.executeXXX() methods

[BL-2073](https://ortussolutions.atlassian.net/browse/BL-2073) make count arg to mid() BIF optional

### Bugs

[BL-1756](https://ortussolutions.atlassian.net/browse/BL-1756) Compat behavior - ListDeleteAt should retain leading delimiters

[BL-1979](https://ortussolutions.atlassian.net/browse/BL-1979) CreateUUID should return a standard UUID

[BL-2000](https://ortussolutions.atlassian.net/browse/BL-2000) cffile upload - \`result\` field not written to

[BL-2003](https://ortussolutions.atlassian.net/browse/BL-2003) cffile upload - resulting \`contentType\` should not also contain the \`contentSubType\`

[BL-2007](https://ortussolutions.atlassian.net/browse/BL-2007) Compat: Handle empty lists in cfqueryparam

[BL-2008](https://ortussolutions.atlassian.net/browse/BL-2008) compat: GetComponentMetaData returns string for implements versus object metadata

[BL-2011](https://ortussolutions.atlassian.net/browse/BL-2011) stored proc return code using wrong key name

[BL-2012](https://ortussolutions.atlassian.net/browse/BL-2012) Can't cast \[Dec/13/2025 08:00] to a DateTime.

[BL-2013](https://ortussolutions.atlassian.net/browse/BL-2013) java class dump template error when it contains BoxClass field

[BL-2014](https://ortussolutions.atlassian.net/browse/BL-2014) Custom error type name hierarchy

[BL-2015](https://ortussolutions.atlassian.net/browse/BL-2015) Allow empty statement after constructs which require statement or body

[BL-2018](https://ortussolutions.atlassian.net/browse/BL-2018) compat-cfml - 'y' and 'n' are considered booleans

[BL-2019](https://ortussolutions.atlassian.net/browse/BL-2019) \`datepart\` in \`dateAdd\` is case sensitive

[BL-2020](https://ortussolutions.atlassian.net/browse/BL-2020) Oracle named params not working correctly

[BL-2021](https://ortussolutions.atlassian.net/browse/BL-2021) Oracle procs don't handle ref cursor out params which are not at the end of the list

[BL-2022](https://ortussolutions.atlassian.net/browse/BL-2022) SQL params using integer truncate decimal values instead of erroring

[BL-2025](https://ortussolutions.atlassian.net/browse/BL-2025) error when comparing null with LIKE operator in QoQ

[BL-2027](https://ortussolutions.atlassian.net/browse/BL-2027) ObjectMarshaller loses mappings when used directly with the correct context

[BL-2029](https://ortussolutions.atlassian.net/browse/BL-2029) bx-mail mail body missing when sending via secondary mailserver

[BL-2032](https://ortussolutions.atlassian.net/browse/BL-2032) yesClass interfaces meta was left as array in prime, when they should be struct

[BL-2034](https://ortussolutions.atlassian.net/browse/BL-2034) Doc comment immediately inside script isn't doesn't associate properly

[BL-2037](https://ortussolutions.atlassian.net/browse/BL-2037) redis cached query - java.io.NotSerializableException: ortus.boxlang.runtime.jdbc.DataSource

[BL-2038](https://ortussolutions.atlassian.net/browse/BL-2038) cfcookie should serialize time in terms of GMT

[BL-2039](https://ortussolutions.atlassian.net/browse/BL-2039) orm can't find datasources - Errors announcing \[onTransactionBegin] interception

[BL-2040](https://ortussolutions.atlassian.net/browse/BL-2040) Application-level datasources not being shutdown when application ends

[BL-2043](https://ortussolutions.atlassian.net/browse/BL-2043) App caches aren't removed when the application ends

[BL-2044](https://ortussolutions.atlassian.net/browse/BL-2044) server level datasources are creating a pool for every application they are used in

[BL-2047](https://ortussolutions.atlassian.net/browse/BL-2047) BigDecimals serialize using scientific notation in JSON

[BL-2048](https://ortussolutions.atlassian.net/browse/BL-2048) scientific notation literals with leading zeros error

[BL-2049](https://ortussolutions.atlassian.net/browse/BL-2049) Comparison method violates its general contract!

[BL-2050](https://ortussolutions.atlassian.net/browse/BL-2050) UT010029: Stream is closed

[BL-2053](https://ortussolutions.atlassian.net/browse/BL-2053) GetHTTPTimeString should always be in GMT Timezone

[BL-2054](https://ortussolutions.atlassian.net/browse/BL-2054) Regression: Parsing of Common ODBC String Pattern fails to apply correct zone

[BL-2055](https://ortussolutions.atlassian.net/browse/BL-2055) Different listAppend() behavior

[BL-2056](https://ortussolutions.atlassian.net/browse/BL-2056) Error executing dump template on dump(application.wirebox)

[BL-2057](https://ortussolutions.atlassian.net/browse/BL-2057) Error in OnSessionEnd Can Leave the Session in a Permanently Expired and Non-Recoverable State

[BL-2058](https://ortussolutions.atlassian.net/browse/BL-2058) File Component action \`append\` Not Correctly Appending with New Lines

[BL-2060](https://ortussolutions.atlassian.net/browse/BL-2060) SOAP client not a class and does not have access to underlying HTTP methods

[BL-2063](https://ortussolutions.atlassian.net/browse/BL-2063) preserve whitespace eating too many line breaks

[BL-2064](https://ortussolutions.atlassian.net/browse/BL-2064) race conditions when two threads load the same class after source modification

[BL-2066](https://ortussolutions.atlassian.net/browse/BL-2066) duplicate() doesn't work with recursive references

[BL-2067](https://ortussolutions.atlassian.net/browse/BL-2067) prevent session from starting inside of application start method

[BL-2068](https://ortussolutions.atlassian.net/browse/BL-2068) expandPath() fails outside of a request (onServerStart)

[BL-2069](https://ortussolutions.atlassian.net/browse/BL-2069) Error sorting via store indexer Comparison method violates its general contract

[BL-2070](https://ortussolutions.atlassian.net/browse/BL-2070) Compat: Currency BIFs allow empty strings as currency code

[BL-2071](https://ortussolutions.atlassian.net/browse/BL-2071) Index -1 out of bounds for length 2 in reReplace()

[BL-2072](https://ortussolutions.atlassian.net/browse/BL-2072) for loop doesn't work on Java primitive array

[BL-2074](https://ortussolutions.atlassian.net/browse/BL-2074) evaluate() doesn't use CF transpiler when used in CF source

### New Features

[BL-1644](https://ortussolutions.atlassian.net/browse/BL-1644) Support convention for parsing query params and form fields as array

[BL-1999](https://ortussolutions.atlassian.net/browse/BL-1999) Miniserver can now encapsulate settings in a miniserver.json for portability


# 1.8.0

December 5, 2025

BoxLang 1.8.0 is a massive release bringing revolutionary HTTP/SOAP capabilities, comprehensive CFML compatibility improvements, and critical stability enhancements. This release introduces a completely rewritten HTTP component with fluent APIs, streaming support, and persistent connection management, alongside a powerful SOAP/WSDL client for web service integration. With over 100 bug fixes and improvements, this release focuses on production-readiness, CFML migration compatibility, and modern web application development patterns.

## 🚀 Major Highlights

### 🎯 Modular Compiler Architecture & Ultra-Slim Runtime

**BoxLang 1.8.0 introduces a revolutionary modular compiler architecture that delivers unprecedented flexibility, security, and deployment efficiency for enterprise applications.**

#### 🪶 Mega-Slim 7MB Runtime

The BoxLang runtime has been dramatically optimized, dropping from over 9MB to just **7MB** by removing the JavaParser compiler dependencies. This lean footprint provides:

* **22% Smaller** runtime for faster downloads and deployments
* **Reduced memory footprint** for containerized environments
* **Faster startup times** due to smaller classpath
* **Improved security surface** with fewer dependencies

#### 🔐 Two Deployment Flavors for Enterprise Security

BoxLang now ships in **two distinct flavors** to meet different security and deployment requirements:

**1. `boxlang` - Full Development Runtime**

* Includes **NoOp** (No Operation) compiler for pre-compiled class execution
* Includes **ASM** compiler for runtime compilation and hot-reloading
* Perfect for development, testing, and dynamic environments
* Enables live code changes and interactive development
* Default choice for most applications

**2. `boxlang-noop` - Secure Production Runtime**

* **NoOp compiler only** - no runtime compilation capabilities
* **100% pre-compiled code execution** - zero dynamic compilation
* **Maximum security** - eliminates runtime code injection vectors
* **Compliance-ready** for regulated industries (finance, healthcare, government)
* **Reduced attack surface** - no compiler means no compilation exploits
* **Immutable deployments** - code cannot be modified at runtime
* Perfect for production environments requiring security certifications

```bash
# Development/Standard deployment
java -jar boxlang-1.8.0.jar myapp.bx

# Secure production deployment (pre-compiled only)
java -jar boxlang-noop-1.8.0.jar myapp.bx
```

{% hint style="success" %}
**Enterprise Security Win**: Deploy with `boxlang-noop` in production to guarantee no runtime code compilation, meeting strict security policies for PCI-DSS, HIPAA, SOC 2, and government compliance requirements.
{% endhint %}

#### 🔌 Plug-and-Play Compiler Modules

Compilers are now **modular add-ons** that can be loaded dynamically via classpath. BoxLang includes two compiler modules:

**1. `bx-compiler-asm` - ASM Bytecode Compiler (Recommended)**

* Direct bytecode generation using ASM library
* **Superior performance** - skips Java source generation step
* Modern JVM feature support (virtual threads, pattern matching, etc.)
* Optimized bytecode output
* Default compiler for production applications

**2. `bx-compiler-java` - Java Source Compiler**

* Generates Java source code, then compiles to bytecode
* Legacy compatibility for debugging and inspection
* Useful for understanding compilation process
* Primarily for backward compatibility

```json
// boxlang.json - Choose your compiler
{
  "compiler": "asm",  // Use ASM compiler (default)
  // OR
  "compiler": "java"  // Use Java source compiler
}
```

#### 🚀 Revolutionary `IBoxpiler` Interface

The new **`IBoxpiler` interface** enables true **plug-and-play compiler development**:

```java
public interface IBoxpiler {
    // Compile BoxLang source to bytecode
    byte[] compile( SourceCode source );

    // Get compiler metadata
    String getName();
    String getVersion();
}
```

**What This Means:**

* 🔧 **Custom Compilers** - Build specialized compilers for your needs
* 🎯 **Domain-Specific Optimization** - Create industry-specific compilation strategies
* 🔒 **Security Compilers** - Implement compliance-specific compilation rules
* ⚡ **Performance Compilers** - Optimize for specific deployment targets
* 🌐 **Alternative Targets** - Compile BoxLang to JavaScript, WASM, native code, etc.
* 🔬 **Research & Innovation** - Experiment with new compilation techniques

**Example Use Cases:**

```js
// Financial services: Compiler with embedded audit logging
compiler = new AuditCompiler()
    .enableTracing()
    .logToCompliance( "audit.log" );

// IoT: Compiler optimized for embedded devices
compiler = new EmbeddedCompiler()
    .optimizeForMemory()
    .targetArch( "ARM64" );

// Blockchain: Compiler with cryptographic verification
compiler = new VerifiableCompiler()
    .signOutput()
    .enableProofOfCompilation();
```

#### 💼 Enterprise Benefits

**Security & Compliance:**

* ✅ Deploy `boxlang-noop` for **zero-runtime-compilation** security posture
* ✅ Meet **PCI-DSS, HIPAA, SOC 2** requirements with immutable runtimes
* ✅ Pass security audits with **no dynamic code execution** capabilities
* ✅ Eliminate entire classes of **code injection vulnerabilities**

**Performance & Efficiency:**

* ⚡ **7MB runtime** for lightning-fast container deployments
* 🚀 **Faster startup times** in serverless and microservices
* 💰 **Lower cloud costs** with smaller images and faster scaling
* 🎯 **Optimized memory usage** for high-density deployments

**Flexibility & Innovation:**

* 🔌 **Plug-and-play compilers** via `IBoxpiler` interface
* 🛠️ **Custom compilation strategies** for specialized requirements
* 🌐 **Future-proof architecture** supporting new compilation targets
* 🔬 **Research-friendly** for academic and innovation projects

**Deployment Scenarios:**

| Scenario                   | Recommended Runtime         | Compiler                 |
| -------------------------- | --------------------------- | ------------------------ |
| Development                | `boxlang`                   | ASM (hot-reload enabled) |
| CI/CD Testing              | `boxlang`                   | ASM                      |
| Staging                    | `boxlang` or `boxlang-noop` | ASM                      |
| Production (Standard)      | `boxlang`                   | ASM                      |
| Production (High Security) | `boxlang-noop`              | None (pre-compiled only) |
| Regulated Industries       | `boxlang-noop`              | None (pre-compiled only) |
| Government/Military        | `boxlang-noop`              | None (pre-compiled only) |
| Containerized Apps         | `boxlang-noop`              | None (smaller images)    |

{% hint style="info" %}
**Migration Path**: Existing applications continue to work seamlessly. Simply choose `boxlang` for standard deployments or upgrade to `boxlang-noop` when security requirements demand pre-compiled-only execution.
{% endhint %}

#### 🎓 Technical Details

The modular compiler architecture leverages:

* **Service Provider Interface (SPI)** for compiler discovery
* **Classpath-based loading** for dynamic compiler registration
* **Graceful fallback** to NoOp if no compilers available
* **Zero-overhead abstraction** - no performance penalty
* **Thread-safe compilation** for concurrent applications

This architectural revolution positions BoxLang as the **most flexible, secure, and enterprise-ready** dynamic JVM language, with unparalleled deployment options for modern cloud-native applications.

***

### 🌐 Revolutionary HTTP Client & Component

The HTTP subsystem has been completely rewritten to provide modern, fluent HTTP capabilities with streaming support, connection management, and advanced features for building robust web applications.

#### New `http()` BIF - Fluent HTTP Client

A new `http()` BIF provides a fluent, chainable interface for building and executing HTTP requests with comprehensive configuration options:

```js
// Simple GET request with fluent API
result = http( "https://api.example.com/data" ).send();
println( "Status: #result.statusCode#" );
println( "Body: #result.fileContent#" );

// Or send async and receive a box future
boxFuture = http( "https://api.example.com/data" )
    .get()
    .sendAsync()

// POST with JSON body
result = http( "https://api.example.com/users" )
    .post()
    .header( "Content-Type", "application/json" )
    .body( { name: "John Doe", email: "john@example.com" } )
    .send();
println( "User created: #result.fileContent#" );

// File upload with multipart
http( "https://api.example.com/upload" )
    .post()
    .multipart()
    .file( "document", "/path/to/file.pdf" )
    .formField( "description", "Important document" )
    .send();

// Stream large response with chunking
http( "https://api.example.com/large-data" )
    .get()
    .onChunk( ( chunk ) => {
        // Process each chunk as it arrives
        println( "Received chunk: #chunk.data.len()# bytes" );
    } )
    .send();

// Consume Server-Sent Events (SSE)
http( "https://api.example.com/events" )
    .get()
    .header( "Accept", "text/event-stream" )
    .onChunk( ( event ) => {
        // Process SSE events in real-time
        println( "Event: #event.event#" );
        println( "Data: #event.data#" );
    } )
    .send();

// Configure connection settings
result = http( "https://api.example.com/data" )
    .connectionTimeout( 30 )
    .httpVersion( "HTTP/2" )
    .redirect( true )
    .proxyServer( "proxy.company.com", 8080 )
    .clientCert( "/path/to/cert.p12", "password" )
    .get()
    .send();

// Transform response with custom function
users = http( "https://api.example.com/users" )
    .get()
    .transform( ( result ) => deserializeJSON( result.fileContent ) )
    .send(); // Returns deserialized array instead of result struct
```

**Key Features:**

* **Fluent API**: Chainable methods for readable request building
* **Simple Execution**: `send()` method executes request and returns result struct directly
* **Response Transformation**: `transform()` method applies custom transformations to results before returning
* **HTTP/2 Support**: Modern HTTP/2 by default with HTTP/1.1 fallback
* **Streaming**: Chunk-based streaming for large responses and SSE
* **Connection Pooling**: Automatic connection reuse and management
* **Client Certificates**: SSL/TLS client certificate authentication
* **Proxy Support**: HTTP/HTTPS proxy with authentication
* **Callbacks**: Rich callback system (onChunk, onError, onComplete, onRequestStart)
* **Error Handling**: `throwOnError` option automatically throws exceptions for HTTP errors (4xx/5xx)

#### Completely Rewritten `bx:http` Component

The `bx:http` component has been completely rewritten to match the fluent BIF capabilities while maintaining CFML compatibility:

```js
// Simple GET request
<bx:http url="https://api.example.com/data" result="apiResult" />
<bx:dump var="#apiResult.statusCode#" />

// POST with JSON
<bx:http
    method="POST"
    url="https://api.example.com/users"
    result="response"
    throwOnError="true">
    <bx:httpparam type="header" name="Content-Type" value="application/json" />
    <bx:httpparam type="body" value='{"name":"John","email":"john@example.com"}' />
</bx:http>

// File upload (multipart)
<bx:http
    method="POST"
    url="https://api.example.com/upload"
    multipart="true">
    <bx:httpparam type="file" name="document" file="/path/to/file.pdf" />
    <bx:httpparam type="formfield" name="description" value="Important document" />
</bx:http>

// Download file
<bx:http
    url="https://example.com/downloads/report.pdf"
    file="report.pdf"
    path="/downloads/"
    getAsBinary="yes" />

// Streaming with callbacks
<bx:http
    url="https://api.example.com/stream"
    onChunk="#( chunk ) => processChunk( chunk )#"
    onError="#( error ) => logError( error )#"
    onComplete="#() => println( 'Stream complete' )#" />

// Server-Sent Events (SSE)
<bx:http
    url="https://api.example.com/events"
    sse="true"
    onMessage="#( event ) => handleSSEEvent( event )#" />

// Client certificate authentication
<bx:http
    url="https://secure-api.com/data"
    clientCert="/path/to/cert.p12"
    clientCertPassword="secret" />

// Proxy configuration
<bx:http
    url="https://external-api.com"
    proxyServer="proxy.company.com"
    proxyPort="8080"
    proxyUser="username"
    proxyPassword="password" />
```

**New Features:**

* **Streaming Callbacks**: `onChunk`, `onMessage`, `onError`, `onComplete`, `onRequestStart`
* **SSE Support**: Native Server-Sent Events handling with `sse` attribute
* **HTTP/2**: Full HTTP/2 support with `httpVersion` attribute
* **Connection Management**: Persistent connections and connection pooling
* **Client Certificates**: SSL/TLS client certificate authentication
* **Better Error Handling**: `throwOnError` attribute for automatic exception throwing

#### HTTP Service - Connection Lifecycle Management

A new `HttpService` manages HTTP client instances, connection pooling, and lifecycle:

```js
// Clients are automatically managed and reused based on configuration
client1 = http( "https://api.example.com" );
client2 = http( "https://api.example.com" ); // Reuses same connection pool

// Access HTTP statistics
stats = getBoxRuntime().getHttpService().getStats();
println( "Total requests: #stats.totalRequests#" );
println( "Active connections: #stats.activeConnections#" );
```

**Features:**

* Automatic connection pooling and reuse
* Connection lifecycle management
* Statistics tracking (requests, failures, bytes transferred)
* Graceful shutdown with connection draining

### 🧼 SOAP/WSDL Client Integration

BoxLang now includes comprehensive SOAP web service support with automatic WSDL parsing and fluent method invocation:

#### New `soap()` BIF

A new `soap()` BIF provides easy SOAP client creation:

```js
// Create SOAP client from WSDL using soap() BIF
ws = soap( "http://example.com/service.wsdl" );

// Configure client settings
ws = soap( "http://example.com/service.wsdl" )
    .timeout( 60 )
    .withBasicAuth( "username", "password" )
    .header( "X-Custom-Header", "value" );

// Invoke methods directly (discovered from WSDL)
result = ws.getUserInfo( userID: 123 );
println( "User: #result.name#" );

// Alternative: createObject() syntax (traditional)
ws = createObject( "webservice", "http://example.com/service.wsdl" );
result = ws.getUserInfo( userID: 123 );

// Use invoke() function for dynamic calls
result = invoke( ws, "getUserInfo", { userID: 123 } );

// Use in components
<bx:invoke
    webservice="http://example.com/service.wsdl"
    method="getUserInfo"
    userID="123"
    returnVariable="userInfo" />

// Inspect available operations
operations = ws.getOperations();
println( "Available operations: #operations.toList()#" );

// Get operation details
opInfo = ws.getOperationInfo( "getUserInfo" );
println( "Parameters: #opInfo.parameters.toList()#" );
```

**Features:**

* **Automatic WSDL Parsing**: Discovers methods, parameters, and types
* **SOAP 1.1 & 1.2 Support**: Auto-detects version from WSDL
* **Fluent Method Calls**: Invoke methods directly on client object
* **Response Unwrapping**: Automatically unwraps single-property response structures
* **Document/Literal Wrapped**: Full support for document/literal wrapped style
* **Parameter Handling**: Automatic parameter type conversion and validation
* **Automatic BoxLang Type Mapping**: Maps SOAP types to BoxLang types automatically

**Implementation Details:**

* Parses WSDL using DOM XML parser
* Extracts operations, bindings, and port types
* Handles XSD schema for parameter discovery
* Builds SOAP envelopes dynamically
* Supports complex types and nested structures
* Compatible with `invoke()` BIF and `bx:invoke` component

### 🎯 Context Shutdown Listeners

New lifecycle hooks for graceful application shutdown:

```js
// In Application.bx
component {
    this.name = "MyApp";

    function onApplicationStart() {
        // Register shutdown listener
        application.resources = setupResources();

        getBoxContext().registerShutdownListener( () => {
            // Clean up resources on shutdown
            application.resources.close();
            println( "Application shutdown complete" );
        } );
    }
}
```

**Use Cases:**

* Database connection cleanup
* Cache flushing
* File handle closing
* External service disconnection
* Logging final state

### 📚 Enhanced Metadata & Reflection

Class metadata now includes `simpleName` for easier reflection:

```js
meta = getMetadata( myObject );
println( "Class: #meta.fullName#" );
println( "Simple name: #meta.simpleName#" ); // New in 1.8.0
```

## 🤖 Core Runtime Updates

### Configuration Improvements

**Compiler Configuration**: The experimental compiler setting has been refactored to a top-level directive in `boxlang.json`:

```json
{
  "compiler": "asm",  // or "java" or "noop"
  "runtime": {
    // other runtime settings
  }
}
```

**JDBC URL Enhancements**:

* More robust placeholder replacements
* Case-insensitive placeholder matching
* Support for complex JDBC URL patterns

### Dynamic Class Loading

The `DynamicClassLoader` has been enhanced with `addPaths()` method for dynamically loading JAR files anywhere in your BoxLang source:

```js
// Load external JARs at runtime
getRequestClassLoader().addPaths( [ "/path/to/library.jar", "/path/to/another.jar" ] );

// Now load classes from those JARs
MyClass = createObject( "java", "com.example.MyClass", getRequestClassLoader() );
```

### Performance Optimizations

* **Metadata Creation**: Micro-optimizations using imperative programming for faster class metadata generation
* **Application Timeout Checks**: Now use background thread to reduce main thread overhead
* **Thread Joining**: Faster `bx:thread` join operations

### Query Improvements

* **Text Type Support**: Query columns now support `text` type (maps to VARCHAR)
* **BLOB/CLOB Handling**: Proper support for binary large objects
* **Column Type Tracking**: Original JDBC column types preserved in query metadata
* **Oracle Improvements**:
  * VARCHAR params now match CHAR fields correctly
  * Support for generated keys (ROWID)
  * Stored procedure ref cursor support

## 📡 MiniServer Runtime Updates

### JSON Configuration Support

The BoxLang MiniServer now supports loading configuration from a JSON file, allowing you to store all server settings in one place instead of passing them as command-line arguments:

**Automatic Loading:**

```bash
# Looks for miniserver.json in current directory
boxlang-miniserver
```

**Explicit Path:**

```bash
boxlang-miniserver /path/to/config.json
```

**Override with CLI:**

```bash
# CLI arguments override JSON configuration
boxlang-miniserver miniserver.json --port 9090 --debug
```

**Example Configuration Files:**

```json
// Basic configuration
{
  "port": 8080,
  "webRoot": "./www"
}

// Development configuration
{
  "port": 8080,
  "host": "127.0.0.1",
  "webRoot": "./src/webapp",
  "debug": true,
  "rewrites": true,
  "rewriteFileName": "index.bxm"
}

// Production configuration
{
  "port": 80,
  "host": "0.0.0.0",
  "webRoot": "/var/www/myapp",
  "debug": false,
  "rewrites": true,
  "rewriteFileName": "index.bxm",
  "healthCheck": true,
  "healthCheckSecure": true,
  "serverHome": "/opt/boxlang",
  "envFile": "/etc/boxlang/.env.production"
}
```

**Supported Configuration Options:**

| Option              | Type    | Default           | Description                                            |
| ------------------- | ------- | ----------------- | ------------------------------------------------------ |
| `port`              | number  | 8080              | The port to listen on                                  |
| `host`              | string  | "0.0.0.0"         | The host to bind to                                    |
| `webRoot`           | string  | current directory | Path to the webroot directory                          |
| `debug`             | boolean | false             | Enable debug mode                                      |
| `configPath`        | string  | null              | Path to BoxLang configuration file                     |
| `serverHome`        | string  | null              | BoxLang server home directory                          |
| `rewrites`          | boolean | false             | Enable URL rewrites                                    |
| `rewriteFileName`   | string  | "index.bxm"       | Rewrite target file                                    |
| `healthCheck`       | boolean | false             | Enable health check endpoints                          |
| `healthCheckSecure` | boolean | false             | Restrict detailed health info to localhost only        |
| `envFile`           | string  | null              | Path to custom environment file (relative or absolute) |

**Configuration Priority:**

Configuration values are loaded in the following order (later sources override earlier ones):

1. **Default values** - Built-in defaults
2. **Environment variables** - `BOXLANG_*` environment variables
3. **JSON configuration** - Values from the JSON file
4. **Command-line arguments** - Explicit CLI flags

For example, if you have:

* Environment variable: `BOXLANG_PORT=3000`
* JSON file: `"port": 8080`
* CLI argument: `--port 9090`

The server will start on port **9090** (CLI overrides all).

**Environment File Loading:**

The `envFile` option allows you to specify a custom environment file to load:

```json
{
  "envFile": ".env.local"
}
```

or

```json
{
  "envFile": "/etc/myapp/.env.production"
}
```

* If `envFile` is not specified, the server looks for `.env` in the webroot directory (default behavior)
* If `envFile` is specified, it loads that file instead
* The path can be relative (resolved from current directory) or absolute
* Environment variables are loaded as system properties and can be used throughout the application

### Other Improvements

* **Fixed rewrite handling**: No longer unnecessarily rewrites file extensions
* **Request body improvements**: Better handling of empty request bodies
* **Error messages**: Enhanced error reporting for malformed requests

## 🤖 Servlet Runtime Updates

* **Real page context**: Servlet runtime now uses proper page context (fixes many edge cases)
* **Relative path resolution**: Fixed mapping path resolution issues
* **`BOXLANG_DEBUG` environment variable**: Now properly supported
* **Session management**: Fixed jsessionid cookie handling (prevents AWS WAF issues)
* **Concurrent request handling**: Better handling of in-progress `onApplicationStart()`

## 🚀 AWS Lambda Runtime Updates

* **AWS Lambda Java Core upgraded** from 1.3.0 to 1.4.0

## 🛠️ Developer Experience

### JavaParser Dependencies

Removed all JavaParser dependencies externally unless explicitly checked. This reduces runtime footprint and startup time for applications that don't use Java source parsing features.

### Feature Audit Tool

* Enhanced to find REST classes and REST API usage
* Better reporting of missing modules for migrations
* Improved analysis of BoxLang feature usage

### Web Support Documentation

All web-related BIFs and components now include proper descriptions via `@BoxBIF` and `@BoxComponent` annotations for better IDE integration and documentation generation.

## 🐛 Notable Bug Fixes

### Date & Time (30+ fixes)

* **Timezone Handling**: `this.timezone` now properly respected in Application.bx
* **Date Parsing**: Fixed parsing issues with various date masks:
  * `"Nov-05-2025 8:43am"`
  * `"Jun-30-2010 04:33"`
  * `"Jun-3-2010 04:33"`
  * `"11/21/2025 1:05"`
  * `"Jul 17, 2017 9:29:40 PM"`
* **`dateAdd()`**: No longer mutates date when adding 0 weeks
* **`isDate()`**: Fixed various edge cases:
  * `isDate(0)` now returns false
  * Handles scientific notation strings
  * Better handling of invalid numeric strings
* **Date Casting**: Fixed issues with JVM locales `de_DE` and `en_DE`
* **`dateConvert()`**: Resolved conversion errors
* **`timeFormat()`**: Fixed non-ASCII whitespace in output
* **Null Dates**: Added handling for null dates in formatting methods
* **DateTime Optimization**: DateTimeFormatter usage optimized for better performance
* **`.format()` Member**: Undocumented but now properly supported on DateTime objects

### Query Operations (15+ fixes)

* **`queryFilter()`**: Fixed returning unexpected rows
* **`querySlice()`**: Fixed offset handling
* **`structFindKey()`**: Now returns proper references (not copies)
* **`structFindValue()`**: Fixed crashes when keys contain arrays
* **Nested Queries**: Now respect JSONSerialize query options
* **Connection Pooling**:
  * Fixed queries with user/pass override not using pooling
  * Properly override credentials with on-the-fly struct syntax
* **SQLite Error Handling**: Database errors now properly handled

### List Operations (5+ fixes)

* **`listDeleteAt()`**: Fixed incorrect behavior in both modes
* **List Find BIFs**: Fixed unexpected matches in search operations
* **Null Appending**: Fixed failures when appending null to list

### Number Formatting (5+ fixes)

* **`numberFormat()`**:
  * Fixed compatibility with `"_.00"` mask
  * No longer omits leading zero with `_.00` mask
  * Empty string with `_.00` mask no longer throws
  * Returns proper value for zero with `_.00` mask
* **`isNumeric()`**: `isNumeric("true")` now returns false (matches ACF/Lucee)
* **`val()`**: Fixed occasional scientific notation in results
* **`lsIsCurrency()`**: Fixed type casting issues

### HTTP & Network (10+ fixes)

* **HTTP Component**:
  * Fixed basic auth regression (no longer sending proper header)
  * Fixed failures with duplicate response headers
  * Now properly handles responses with both `file` and `path` attributes
* **Cookie Component**:
  * Fixed expires attribute crashes with createTimeSpan
  * Better date handling for cookie expiration
* **Header Component**: Now adds headers instead of replacing (correct CFML behavior)
* **Compression**: Fixed gzip decompression issues

### File Operations (5+ fixes)

* **`fileCopy()`**: Now respects overwrite parameter
* **File Upload**:
  * Files smaller than 10KB now properly stored on disk
  * Fixed allowed extension check when periods are present in filename
  * Fixed regression where content wasn't committed to disk
  * Empty `allow` argument now treated correctly
* **`getFileInfo()`**: Returns correct type string for directories
* **`expandPath()`**: Fixed using wrong base path when Application.bx in different directory
* **`getTempDirectory()`**: Now contains trailing slash (CFML compat)

### Parser Improvements (10+ fixes)

* **Semicolons**: After empty statement blocks now properly end statements
* **Whitespace**: Allowed in tag closing (`/ >`)
* **CF Template CFCs**: Fixed parsing of template-style component definitions
* **Ternary Operator**: Assignment inside ternary now parses correctly
* **`continue` in `switch`**: Can now use `continue` inside `switch` inside `for` loop
* **Static Function Invocation**: Fixed parse error on static method calls
* **CF Transpiler**:
  * Now catches variables inside `isDefined()` args
  * Better handling of CF template CFC structures

### CFML Compatibility (15+ fixes)

* **CGI Values**: For compatibility, CGI values are now java.lang.String
* **Boolean Comparison**: Don't compare numbers to booleans
* **`isValid()`**: Fixed null reference errors
* **`isDefined()`**: Fixed regression returning false on struct keys
* **`reMatchNoCase()`**: Result is now proper array (not array with 2 elements)
* **Array Comparison**: Fixed "Can't compare \[String] against \[Array]" error
* **`structSort()`**: Fixed issues with unmodifiable arrays from `keyArray()`
* **Object Component**:
  * Type default now being set correctly
  * `component` attribute handled correctly
* **Custom Tags**: `thisTag` scope now behaves like ACF/Lucee
* **Line Numbers**: Correct line numbers reported in tag context

### Java Interop (5+ fixes)

* **Field Access**: Fixed issues accessing public parent package/private class fields
* **Field Setting**: Values now properly coerced when setting Java fields
* **`putAll()`**: Fixed ClassCastException when using Map argument
* **Unmodifiable Arrays**: Can now map/filter unmodifiable arrays
* **Native Array Printing**: `println()` better handles Java native arrays

### XML Operations (3+ fixes)

* **`xmlSearch()`**: Returns correct value for xpath expressions
* **CFDUMP**: Fixed breaking when column names contain commas

### Async Operations (2+ fixes)

* **`asyncRun()`**: Executor argument now properly detects BoxExecutors
* **Session Scope**: Fixed distributed cache persistence when request ends

### Application Lifecycle (3+ fixes)

* **Application Shutdown**: Can no longer shutdown mid-request
* **Server Start**: Added `onServerStart` support to compat mode
* **Runtime Wait**: Mechanism for runtimes to wait until BoxRuntime instance fully started
* **Datasource Loading**: Datasources load first, then caches (avoids chicken/egg issues)
* **Datasource Errors**: Server now starts even if one datasource has connection issues

### Exception Handling (3+ fixes)

* **Custom Tags in Catch**: Can now call custom tags from catch blocks
* **Captured Variables**: Now available when capture is performed in catch block
* **Variable Declaration**: Can now declare variables using BoxExpressionInvocation

### Stored Procedures (2+ fixes)

* **Null Attribute**: Component now respects "null" attribute
* **Multiple Result Sets**: Fixed CFStoredProc returning multiple result sets

### Miscellaneous Fixes

* **Bytecode Versioning**: Clear BL home classes folder on upgrade
* **Compiler References**: Refactored 3 dangling core references to Java Boxpiler
* **`variableName` Type**: Now allows periods in validation
* **Error Messages**: Preserve whitespace in default web error page
* **Query Column Keys**: Upper case outer struct keys when serializing query (compat)
* **`rereplace()`**: Ignore invalid backreference groups (don't throw)

## 🔧 Configuration Updates

### Compiler Configuration

The experimental compiler setting is now a top-level directive:

```json
{
  "compiler": "asm",
  "runtime": {
    // runtime settings
  }
}
```

Valid values: `"asm"` (default), `"java"`, `"noop"`

### JDBC Configuration

Enhanced placeholder support in datasource URLs:

```json
{
  "datasources": {
    "myDB": {
      "driver": "mysql",
      "url": "jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME}",
      "username": "${DB_USER}",
      "password": "${DB_PASS}"
    }
  }
}
```

## ⚡ Migration Notes

### Breaking Changes

**None** - This release maintains full backward compatibility with 1.7.x

### Compatibility Improvements

This release includes extensive CFML compatibility improvements:

**Date/Time Handling**:

* Better date parsing with various masks
* Proper timezone respect in Application settings
* Null date handling in formatting functions

**Query Operations**:

* Connection pooling with credential overrides
* Better query metadata tracking
* Oracle-specific improvements

**List Operations**:

* Fixed `listDeleteAt()` behavior
* Better null handling

**Number Formatting**:

* `numberFormat()` mask compatibility
* `isNumeric()` behavior matches ACF/Lucee

**HTTP Operations**:

* Basic auth header handling
* Duplicate header support
* Cookie expiration handling

**CGI Scope**:

* Values are now java.lang.String for compatibility

**Comparison Operations**:

* No longer compare numbers to booleans
* Proper array vs string comparison errors

### Recommended Actions

**HTTP Migration**: If you're using the old HTTP component or custom HTTP code, consider migrating to the new fluent APIs:

```js
// Old style (component)
<bx:http url="https://api.example.com" method="GET" result="myResult" />

// New style (fluent BIF)
myResult = http( "https://api.example.com" )
    .get()
    .send(); // Returns the result struct directly

// Or with transformation
data = http( "https://api.example.com/users.json" )
    .get()
    .transform( ( result ) => deserializeJSON( result.fileContent ) )
    .send(); // Returns deserialized data
```

**SOAP Integration**: If you're integrating with SOAP web services, use the new `soap()` BIF or traditional `createObject("webservice")` for automatic WSDL parsing and fluent method invocation:

```js
// New soap() BIF (recommended)
ws = soap( "http://example.com/service.wsdl" )
    .timeout( 60 )
    .withBasicAuth( "user", "pass" );

// Or traditional createObject
ws = createObject( "webservice", "http://example.com/service.wsdl" );

// Invoke methods
result = ws.methodName( arg1, arg2 );
```

**Configuration**: Update your `boxlang.json` to use the new top-level `compiler` directive if you were using the experimental setting.

***

## 🎶 Release Notes

### Bugs

[BL-1850](https://ortussolutions.atlassian.net/browse/BL-1850) this.timezone not respected in Application.bx

[BL-1874](https://ortussolutions.atlassian.net/browse/BL-1874) jsessionid cookie value set to null - breaks AWS WAF

[BL-1884](https://ortussolutions.atlassian.net/browse/BL-1884) Compat: GetTempDirectory Does not Contain Trailing Slash

[BL-1886](https://ortussolutions.atlassian.net/browse/BL-1886) ByteCode Versioning on Upgrade - clear BL home classes folder

[BL-1888](https://ortussolutions.atlassian.net/browse/BL-1888) DateAdd changes date when added 0 'w'

[BL-1889](https://ortussolutions.atlassian.net/browse/BL-1889) parseDateTime - Can't cast \[Nov-05-2025 8:43am] to a DateTime.

[BL-1890](https://ortussolutions.atlassian.net/browse/BL-1890) HTTP request fails with exception when server response with duplicate headers

[BL-1892](https://ortussolutions.atlassian.net/browse/BL-1892) stored proc component not respecting "null" attribute

[BL-1896](https://ortussolutions.atlassian.net/browse/BL-1896) cfdump breaks when column names have comma

[BL-1897](https://ortussolutions.atlassian.net/browse/BL-1897) servlet runtime is not using the real page context

[BL-1899](https://ortussolutions.atlassian.net/browse/BL-1899) QueryFilter returning unexpected rows

[BL-1900](https://ortussolutions.atlassian.net/browse/BL-1900) sorting an array of numerics errors on decimals

[BL-1901](https://ortussolutions.atlassian.net/browse/BL-1901) querysclice mishandles offset

[BL-1906](https://ortussolutions.atlassian.net/browse/BL-1906) calling custom tag from catch block errors

[BL-1908](https://ortussolutions.atlassian.net/browse/BL-1908) Parser: semicolons after empty statement block don't end the statement

[BL-1909](https://ortussolutions.atlassian.net/browse/BL-1909) xmlSearch doesn't return correct value for xpath expression

[BL-1910](https://ortussolutions.atlassian.net/browse/BL-1910) Datasources need to lead first, then caches to avoid chicken and egg issues

[BL-1911](https://ortussolutions.atlassian.net/browse/BL-1911) When using SQLite with BoxLang, database errors (like creating a table that already exists) are not handled properly.

[BL-1912](https://ortussolutions.atlassian.net/browse/BL-1912) StructFindKey doesn't seem to return references

[BL-1913](https://ortussolutions.atlassian.net/browse/BL-1913) Application can shutdown mid request

[BL-1914](https://ortussolutions.atlassian.net/browse/BL-1914) captured variable not available when capture is performed in catch block

[BL-1926](https://ortussolutions.atlassian.net/browse/BL-1926) Boxlang server does not start if one datasource has connection issues

[BL-1927](https://ortussolutions.atlassian.net/browse/BL-1927) reMatchNoCase result is an array with 2 elements

[BL-1928](https://ortussolutions.atlassian.net/browse/BL-1928) Can't compare \[String] against \[Array]

[BL-1929](https://ortussolutions.atlassian.net/browse/BL-1929) Date Casting issues when JVM locale is \`de\_DE\` or \`en\_DE\`

[BL-1930](https://ortussolutions.atlassian.net/browse/BL-1930) Can't cast \[0] to a DateTime

[BL-1931](https://ortussolutions.atlassian.net/browse/BL-1931) FileUpload fails allowed extension check when periods are present

[BL-1932](https://ortussolutions.atlassian.net/browse/BL-1932) list / array find BIFs returning unexpected matches

[BL-1933](https://ortussolutions.atlassian.net/browse/BL-1933) acf/lucee compat -- numberFormat( "", '\_.00' ) throws

[BL-1934](https://ortussolutions.atlassian.net/browse/BL-1934) acf/lucee compat - numberFormat(0, "\_.00") returns ".00"

[BL-1935](https://ortussolutions.atlassian.net/browse/BL-1935) Can't cast \[Jul 17, 2017 9:29:40 PM] to a DateTime.

[BL-1938](https://ortussolutions.atlassian.net/browse/BL-1938) number format omits leading zero with \_.00 mask

[BL-1939](https://ortussolutions.atlassian.net/browse/BL-1939) isDate(0) returns true

[BL-1941](https://ortussolutions.atlassian.net/browse/BL-1941) isValid - Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null

[BL-1942](https://ortussolutions.atlassian.net/browse/BL-1942) isDate - can't cast '0000009' to a BigDecimal

[BL-1943](https://ortussolutions.atlassian.net/browse/BL-1943) SessionScope in distributed cache not persisting when request ends

[BL-1946](https://ortussolutions.atlassian.net/browse/BL-1946) Dynamic Interop getField() issue when trying to access a public class parent package/private class fields

[BL-1947](https://ortussolutions.atlassian.net/browse/BL-1947) bad parse (?) on static function invocation

[BL-1948](https://ortussolutions.atlassian.net/browse/BL-1948) can't use \`continue\` inside \`switch\` inside \`for\`

[BL-1949](https://ortussolutions.atlassian.net/browse/BL-1949) For CFML compatibility CGI values should be java,lang.string

[BL-1950](https://ortussolutions.atlassian.net/browse/BL-1950) Nested queries ignore JSONSerialize query options

[BL-1951](https://ortussolutions.atlassian.net/browse/BL-1951) Don't compare numbers to booleans

[BL-1952](https://ortussolutions.atlassian.net/browse/BL-1952) lsIsCurrency - can't cast java.lang.Integer to java.lang.String

[BL-1956](https://ortussolutions.atlassian.net/browse/BL-1956) \`timeFormat\` can produce strings containing non-ascii whitespace

[BL-1958](https://ortussolutions.atlassian.net/browse/BL-1958) CF compat: allow whitespace in / > tag closing

[BL-1959](https://ortussolutions.atlassian.net/browse/BL-1959) Parsing CF template CFC

[BL-1960](https://ortussolutions.atlassian.net/browse/BL-1960) assingment inside ternary parses wrong

[BL-1962](https://ortussolutions.atlassian.net/browse/BL-1962) val() sometimes returns scientific notation

[BL-1963](https://ortussolutions.atlassian.net/browse/BL-1963) array append throws java.lang.UnsupportedOperationException when array originates from struct.keyArray()

[BL-1965](https://ortussolutions.atlassian.net/browse/BL-1965) values not coerced when setting Java fields

[BL-1966](https://ortussolutions.atlassian.net/browse/BL-1966) {}.putAll(Map) throws ClassCastException

[BL-1967](https://ortussolutions.atlassian.net/browse/BL-1967) Can't cast \[Jun-30-2010 04:33] to a DateTime

[BL-1969](https://ortussolutions.atlassian.net/browse/BL-1969) Optimize DateTimeFormatter Usage

[BL-1971](https://ortussolutions.atlassian.net/browse/BL-1971) Cannot map/filter an unmodifiable array

[BL-1972](https://ortussolutions.atlassian.net/browse/BL-1972) query with user/pass override doesn't use connection pooling

[BL-1973](https://ortussolutions.atlassian.net/browse/BL-1973) query with user/pass override doesn't override on-the-fly struct

[BL-1976](https://ortussolutions.atlassian.net/browse/BL-1976) asyncRun() executor argument was not detecting BoxExecutors directly.

[BL-1977](https://ortussolutions.atlassian.net/browse/BL-1977) Regression: isDefined returning false on struct key

[BL-1978](https://ortussolutions.atlassian.net/browse/BL-1978) CF transpiler doesn't catch variables inside isDefined args

[BL-1980](https://ortussolutions.atlassian.net/browse/BL-1980) CFCookie Expires crashes if using CreateTimeSpan

[BL-1981](https://ortussolutions.atlassian.net/browse/BL-1981) Object Component - Type Default Not Being Set

[BL-1982](https://ortussolutions.atlassian.net/browse/BL-1982) Can't cast \[Jun-3-2010 04:33] to a DateTime.

[BL-1983](https://ortussolutions.atlassian.net/browse/BL-1983) Can't cast \[11/21/2025 1:05] to a DateTime

[BL-1984](https://ortussolutions.atlassian.net/browse/BL-1984) isNumeric("true") is true on boxlang, false on lucee/acf

[BL-1985](https://ortussolutions.atlassian.net/browse/BL-1985) Refactor 3 dangling core references to the Java Boxpiler

[BL-1987](https://ortussolutions.atlassian.net/browse/BL-1987) CFTag support for thisTag scope behaves differently than ACF/Lucee

[BL-1988](https://ortussolutions.atlassian.net/browse/BL-1988) You cannot declare a variable using BoxExpressionInvocation

[BL-1989](https://ortussolutions.atlassian.net/browse/BL-1989) Compat: \`format\` member function undocumented but supported for DateTime objects

[BL-1994](https://ortussolutions.atlassian.net/browse/BL-1994) Compat: \`component\` attribute not handled correctly by Object component

[BL-1995](https://ortussolutions.atlassian.net/browse/BL-1995) Incorrect line number reported in tag context

[BL-1996](https://ortussolutions.atlassian.net/browse/BL-1996) header component should add header, not replace

[BL-1997](https://ortussolutions.atlassian.net/browse/BL-1997) Regression: HTTP Component Basic Auth no longer sending proper header

[BL-1998](https://ortussolutions.atlassian.net/browse/BL-1998) Compat: Add handling for null dates in formatting methods

### New Features

[BL-1835](https://ortussolutions.atlassian.net/browse/BL-1835) context shutdown listeners

[BL-1891](https://ortussolutions.atlassian.net/browse/BL-1891) Add mechanism for runtimes to wait until BoxRuntime instance is started

[BL-1893](https://ortussolutions.atlassian.net/browse/BL-1893) Add onServerStart support to compat module

[BL-1895](https://ortussolutions.atlassian.net/browse/BL-1895) ServerSideEventConsumer(), SSEConsume() bif to allow from the core to connect and consume events. This is imperative for LLM integrations

[BL-1898](https://ortussolutions.atlassian.net/browse/BL-1898) ServerSideEventConsumer to allow for any BoxLang app to consume SSE events in a streaming fashion, especially tuned for LLMs

[BL-1921](https://ortussolutions.atlassian.net/browse/BL-1921) Fluent HTTP Client with http() bif

[BL-1922](https://ortussolutions.atlassian.net/browse/BL-1922) HTTP Service for managing and controlling http client life-cycles

[BL-1923](https://ortussolutions.atlassian.net/browse/BL-1923) Ability for our HTTP calls to persist connection and state across executions

[BL-1924](https://ortussolutions.atlassian.net/browse/BL-1924) HTTP Streaming capabilities for the http components (SSE, Regular Streams)

[BL-1970](https://ortussolutions.atlassian.net/browse/BL-1970) SOAP Client Consumer

[BL-1974](https://ortussolutions.atlassian.net/browse/BL-1974) added simpleName to metadata for classes for ease of use

[BL-1990](https://ortussolutions.atlassian.net/browse/BL-1990) StructFindValue breaks if any key is an array

### Improvements

[BL-1315](https://ortussolutions.atlassian.net/browse/BL-1315) Create a way to load jars dynamically - enhanced DynamicClassLoader with addPaths()

[BL-1518](https://ortussolutions.atlassian.net/browse/BL-1518) Remove all JavaParser dependencies externally unless you check if it exists

[BL-1617](https://ortussolutions.atlassian.net/browse/BL-1617) Refactor the experimental compiler setting to a top-level directive in the boxlang.json: compiler

[BL-1868](https://ortussolutions.atlassian.net/browse/BL-1868) More robust placeholder replacements in JDBC URLs

[BL-1887](https://ortussolutions.atlassian.net/browse/BL-1887) Rename SSE BIF to ServerSideEvent and add Alias to SSE

[BL-1894](https://ortussolutions.atlassian.net/browse/BL-1894) Added descriptions to web support bifs/components

[BL-1902](https://ortussolutions.atlassian.net/browse/BL-1902) Add support for query type of text, map to varchar

[BL-1903](https://ortussolutions.atlassian.net/browse/BL-1903) Enhance feature audit to find REST classes

[BL-1905](https://ortussolutions.atlassian.net/browse/BL-1905) Support rowID/generatedKey for Oracle

[BL-1918](https://ortussolutions.atlassian.net/browse/BL-1918) Make datasource URL placeholder replacements case-insensitive

[BL-1919](https://ortussolutions.atlassian.net/browse/BL-1919) Faster bx:thread joining

[BL-1920](https://ortussolutions.atlassian.net/browse/BL-1920) Allow JDBC Drivers to override query column types

[BL-1925](https://ortussolutions.atlassian.net/browse/BL-1925) variableName type allows periods

[BL-1936](https://ortussolutions.atlassian.net/browse/BL-1936) Preserve whitespace in error messages in default web Error page

[BL-1937](https://ortussolutions.atlassian.net/browse/BL-1937) track original JDBC col type and make available in query meta

[BL-1940](https://ortussolutions.atlassian.net/browse/BL-1940) varchar param doesn't match char field in Oracle driver

[BL-1945](https://ortussolutions.atlassian.net/browse/BL-1945) Support BLOB and CLOB properly

[BL-1957](https://ortussolutions.atlassian.net/browse/BL-1957) Compat-- upper case outer struct keys when serializing query

[BL-1968](https://ortussolutions.atlassian.net/browse/BL-1968) Use background thread to check app timeouts

[BL-1975](https://ortussolutions.atlassian.net/browse/BL-1975) Micro optimizations to promote speed when creating metadata by using imperative programming

[BL-1986](https://ortussolutions.atlassian.net/browse/BL-1986) println() better handling of java native arrays

[BL-1991](https://ortussolutions.atlassian.net/browse/BL-1991) Oracle stored procs support for ref cursors

[BL-1992](https://ortussolutions.atlassian.net/browse/BL-1992) rereplace() ignore invalid backreference groups


# 1.7.0

November 4, 2025

## Introduction

BoxLang 1.7.0 brings significant performance improvements, powerful new features for modern web development, and enhanced database capabilities. This release introduces **Server-Sent Events (SSE)** support for building real-time applications and AI agents, a new **JDBC Cache Store** for distributed caching, and **bytecode compatibility versioning** for improved module management. Performance optimizations across scheduled tasks, class loading, and ASM generation deliver faster execution, while over 40 bug fixes improve stability in file operations, HTTP handling, database queries, and CFML compatibility.

### 🚀 Major Highlights

#### 🎯 Server-Sent Events (SSE)

New `SSE()` BIF and Emitter for web runtimes enables real-time server-to-client event streaming, perfect for building AI agents, live dashboards, progressive loading experiences, and real-time notifications. The implementation includes automatic keep-alive, CORS support, async execution, and graceful timeout handling.

**Basic Usage:**

```js
// Simple synchronous streaming
SSE( ( emitter ) => {
    emitter.send( "Hello from server!" );
    emitter.send( { status: "processing", progress: 25 }, "update" );
    emitter.close();
} );
```

**AI Streaming with Async Execution:**

```js
// Non-blocking AI response streaming
SSE(
    callback: ( emitter ) => {
        var response = callAIService();
        while( !emitter.isClosed() && response.hasMoreTokens() ) {
            emitter.send( response.getNextToken(), "token" );
        }
        emitter.send( { complete: true }, "done" );
    },
    async: true,
    keepAliveInterval: 30000,  // Send keep-alive every 30s
    timeout: 300000            // Close after 5 minutes max
);
```

**Cross-Origin Streaming:**

```js
// Enable CORS for cross-domain requests
SSE(
    callback: ( emitter ) => {
        emitter.send( { message: "Hello from API" }, "greeting", 1 );
    },
    cors: "*"  // or specific origin: "https://app.example.com"
);
```

**Available Parameters:**

* `callback` (required) - Closure/lambda that receives the emitter object
* `async` (default: false) - Run callback in background thread (non-blocking)
* `retry` (default: 0) - Client reconnect interval in milliseconds
* `keepAliveInterval` (default: 0) - Auto-send keep-alive comments interval
* `timeout` (default: 0) - Maximum execution time for async mode
* `cors` (default: "") - CORS origin (\* for all, or specific domain)

**Emitter Methods:**

* `send( data, [event], [id] )` - Send SSE event (complex data auto-serialized to JSON)
* `comment( text )` - Send SSE comment for keep-alive
* `close()` - Gracefully close the stream
* `isClosed()` - Check if client disconnected

**Implementation Features:**

* Automatic first-byte flush to establish connection quickly
* Large data chunking (splits >32KB lines automatically)
* Multi-line data support with proper SSE formatting
* Client disconnect detection with graceful cleanup
* Proxy/nginx buffering disabled for real-time delivery

#### 🗄️ JDBC Cache Store

New distributed cache store backed by JDBC databases, enabling cache sharing across multiple BoxLang instances. Perfect for horizontal scaling scenarios where multiple application servers need to share cached data.

**Basic Configuration:**

```js
// Configure JDBC cache store in boxlang.json
{
  "caches": {
    "distributedCache": {
      "provider": "BoxCache",
      "properties": {
        "objectStore": "JDBCStore",
        "datasource": "myDatasource",
        "table": "boxlang_cache",
        "autoCreate": true
      }
    }
  }
}
```

**Advanced Configuration with Eviction:**

```js
{
  "caches": {
    "sharedCache": {
      "provider": "BoxCache",
      "properties": {
        "objectStore": "JDBCStore",
        "datasource": "prodDB",
        "table": "app_cache",
        "autoCreate": true,
        // Standard BoxCache properties
        "maxObjects": 1000,
        "evictionPolicy": "LRU",
        "evictCount": 100,
        "defaultTimeout": 3600,
        "defaultLastAccessTimeout": 1800,
        "reapFrequency": 300
      }
    }
  }
}
```

**Configuration Options:**

* `datasource` (required) - Name of the datasource to use for storage
* `table` (default: "boxlang\_cache") - Database table name for cache storage
* `autoCreate` (default: true) - Automatically create table and indexes if missing
* Plus all standard BoxCache properties (maxObjects, evictionPolicy, evictCount, etc.)

**Supported Databases:**

* Oracle
* MySQL / MariaDB
* PostgreSQL
* Microsoft SQL Server
* Apache Derby
* HSQLDB
* SQLite

The implementation automatically detects the database vendor and generates optimized SQL for each platform, including proper handling of:

* Database-specific data types (CLOB, TEXT, LONGTEXT, etc.)
* Vendor-specific eviction queries (LIMIT, TOP, FETCH FIRST)
* Index creation strategies
* Transaction handling

**Features:**

* **Distributed**: Mark as distributed store - cache data persists across instances
* **Automatic Schema Management**: Creates table and indexes on first use
* **Serialization**: Uses Base64-encoded object marshalling for complex types
* **Performance**: Pre-compiled SQL statements for all operations
* **Eviction Support**: Full support for LRU, LFU, and other eviction policies
* **Metadata Tracking**: Stores hits, timeouts, and access timestamps

All cache stores now expose `isDistributed()` method for ecosystem tools to detect distribution capabilities.

#### 🌳 BoxAST() - AST Generation

New `BoxAST()` BIF enables programmatic access to BoxLang's Abstract Syntax Tree (AST), perfect for building code analysis tools, linters, formatters, and code generation utilities. It supports parsing BoxLang script/template syntax as well as CFML/ColdFusion syntax for migration and compatibility tools.

```js
// Parse BoxLang source code using BIF
ast = BoxAST( source: "x = 1 + 2; y = x * 3;" );

// Or use the convenient string member method
code = "function hello() { return 'world'; }";
ast = code.toAST();

// Parse from a file
ast = BoxAST( filepath: "myScript.bx" );

// Return as JSON for external tools
astJson = BoxAST(
  source: "function hello() { return 'world'; }",
  returnType: "json"
);

// Or with member method
astJson = "x = 1 + 2;".toAST( returnType: "json" );

// Return as text representation
astText = BoxAST(
  filepath: "complex.bx",
  returnType: "text"
);

// Parse BoxLang template syntax
templateAst = BoxAST(
  source: "<bx:output>#now()#</bx:output>",
  sourceType: "template"
);

// Parse CFML/ColdFusion script (for migration tools)
cfScriptAst = BoxAST(
  source: "cfset x = 1; cfloop from='1' to='10' index='i' { writeOutput(i); }",
  sourceType: "cfscript"
);

// Parse CFML/ColdFusion template (for migration tools)
cfTemplateAst = BoxAST(
  source: "<cfset x = 1><cfoutput>#x#</cfoutput>",
  sourceType: "cftemplate"
);
```

**Parameters:**

* `source` - BoxLang/CFML source code to parse
* `filepath` - Path to file to parse (alternative to source)
* `returnType` - Output format: "struct" (default), "json", or "text"
* `sourceType` - Syntax type: "script" (default), "template", "cfscript", or "cftemplate"

**Use Cases:**

* **Code Analysis**: Build custom linters and static analysis tools
* **Code Generation**: Generate BoxLang code from templates or DSLs
* **Formatters**: Create custom code formatting utilities
* **Documentation Generators**: Extract function signatures and comments
* **Refactoring Tools**: Analyze and transform code structures
* **IDE Tooling**: Power syntax highlighting and code intelligence features
* **Migration Tools**: Parse and analyze CFML code for BoxLang migration

#### 🔧 Bytecode Compatibility Versioning

BoxLang now implements bytecode compatibility versioning, ensuring compiled classes remain compatible across runtime versions and improving module stability.

### 🤖 Core Runtime Updates

#### Performance Improvements

* **Scheduled Tasks**: Significant performance boost by introducing non-concurrent maps for logging and closure suppliers
* **Static Initializers**: Optimized execution of static class initializers
* **ASM Generation**: Streamlined bytecode generation by eliminating disk-based class file operations
* **Cache Stores**: Performance tuning across all cache store implementations

#### Enhanced Dumping

* Renamed all `dump()` member methods to `.bxDump()` to prevent conflicts with user-defined methods
* Improved class dumping with better error handling for restricted Java fields
* Fixed Java time type dumping (`java.sql.Time`)
* Better handling of recursive class references in JSON serialization

#### Module System Enhancements

* Added missing properties to `getModuleInfo()` struct snapshot
* Fixed module `publicMapping` registration
* Improved IService lifecycle by ensuring `onConfigurationLoad()` is called correctly
* Better validation of template URIs

#### HTTP Component Improvements

* Added client certificate functionality support:

```js
http url="https://secure-api.com" {
  httpparam type="certificate" file="client-cert.p12" password="secret";
}
```

* Fixed double encoding of query parameters in HTTPParam
* Better handling of `getAsBinary=no` for CFML compatibility
* Proper Optional unwrapping in HTTP result responses

### 📡 MiniServer Runtime Updates

* Fixed rewrite file extension handling - no longer rewrites requests unnecessarily
* Improved request body handling for empty payloads
* Better error messages for empty request bodies

### 🤖 Servlet Runtime Updates

* Fixed relative path resolution for mappings
* Enabled `BOXLANG_DEBUG` environment variable support
* Improved session management - fixed jsessionid cookie handling to prevent AWS WAF issues
* Better handling of in-progress `onApplicationStart()` for concurrent requests

### 🥊 Developer Experience

#### Dynamic Object Creation

Enhanced `createDynamicProxy()` and `createObject()` to accept custom class loaders:

```js
// Use custom class loader for dynamic object creation
customLoader = createObject( "java", "java.net.URLClassLoader" )
  .init( [ url ] );

proxy = createDynamicProxy(
  listener,
  [ "com.example.Interface" ],
  customLoader
);
```

#### IStruct Convenience Method

New `getAsChar()` method on IStruct for convenient character extraction:

```js
struct = { "code": "A" };
charValue = struct.getAsChar( "code" ); // Returns Character 'A'
```

#### Configuration Improvements

* JSON placeholders now applied immediately upon reading for consistent key replacement
* Better handling of hyphens in pre-annotations to match post-annotation behavior
* Fixed ignore of wildcard `*` in valid template extensions when searching for Application descriptors

### 🐛 Notable Bug Fixes

#### Database & Stored Procedures

* Fixed MSSQL connection issues when specifying `username` and `password` in cfquery
* Resolved multiple result set returns in CFStoredProc
* Fixed stored procedure parameter errors and type casting for timestamps
* Improved dynamic SQL type handling in CF transpiler

#### File Operations

* Fixed `fileCopy()` not respecting overwrite parameter
* Corrected file upload handling:
  * Files smaller than 10KB now properly stored on disk
  * Proper directory creation for absolute destination paths
  * Fixed template-relative destination path handling
  * Empty `allow` argument now treated correctly
* Fixed `getFileInfo()` returning incorrect type string for directories
* Resolved `expandPath()` using wrong base path when Application.bx in different directory

#### List Operations

* Fixed `listDeleteAt()` incorrect behavior in both modes
* Resolved appending null to list failures

#### Component & Class Handling

* Better error messages for import statements in class bodies
* Fixed class dump output showing keys twice instead of values
* Improved loose struct converter error handling
* Fixed duplicate() failures when encountering Optional types

#### Mail & Dates

* Fixed `bx:mail` component string attribute handling for useSSL/useTLS
* Resolved `dateConvert()` errors
* Added handling for string dates with common masks

#### Path & Mapping

* Normalized mapping paths with `../` correctly
* Fixed CGI scope mapping returning null values
* Improved abort exception handling (no longer caught inappropriately)

#### Dump Operations

* Fixed `CFDUMP` and `WRITEDUMP` file output functionality

#### Windows Compatibility

* Resolved Windows BoxLang REPL regression

### 🔧 Configuration Updates

No configuration changes required for this release. New features like SSE and JDBC cache store are opt-in and require explicit configuration.

### ⚡ Migration Notes

#### Breaking Changes

**Dump Method Rename**: All built-in member methods named `dump()` have been renamed to `.bxDump()` to avoid conflicts with user-defined methods. If you were calling `.dump()` on built-in objects, update to `.bxDump()`:

```js
// Old
array.dump();

// New
array.bxDump();
```

#### Compatibility Improvements

* Enhanced CFML compatibility for HTTP component behaviors
* Better handling of empty file upload `allow` parameter
* Improved stored procedure result set handling
* More accurate CGI scope value mapping

***

### 🎶 Release Notes

## Release notes - BoxLang - 1.7.0

### Improvements

[BL-1808](https://ortussolutions.atlassian.net/browse/BL-1808) HTTP Component - Support Client Cert Functionality

[BL-1818](https://ortussolutions.atlassian.net/browse/BL-1818) allow hyphen in pre annotations to match post annotations

[BL-1825](https://ortussolutions.atlassian.net/browse/BL-1825) Performance improvement of all scheduled task calls by introducing non concurrent maps for logging and closure suppliers

[BL-1830](https://ortussolutions.atlassian.net/browse/BL-1830) Don't rewrite miniserver requests with rewrite file extension

[BL-1836](https://ortussolutions.atlassian.net/browse/BL-1836) Apply placeholders to JSON as soon as it's read to ensure all keys are replaced

[BL-1838](https://ortussolutions.atlassian.net/browse/BL-1838) Improve performance of running static initializer on class

[BL-1839](https://ortussolutions.atlassian.net/browse/BL-1839) Added missing properties to getModuleInfo() struct snapshot

[BL-1846](https://ortussolutions.atlassian.net/browse/BL-1846) Validate request URIs

[BL-1848](https://ortussolutions.atlassian.net/browse/BL-1848) Optimize ASM generation by not relying on disk class files

[BL-1849](https://ortussolutions.atlassian.net/browse/BL-1849) dump class improvements

[BL-1853](https://ortussolutions.atlassian.net/browse/BL-1853) Component annotation for ignoring ignore outpout only setting

[BL-1855](https://ortussolutions.atlassian.net/browse/BL-1855) Component annotation for auto-evaluating interpolated expressions

[BL-1863](https://ortussolutions.atlassian.net/browse/BL-1863) Rename all dump() member methods to be .bxDump() to avoid conflicts with actual methods named dump()

[BL-1864](https://ortussolutions.atlassian.net/browse/BL-1864) Catch Java access errors when getting Fields dynamically in class dump

[BL-1865](https://ortussolutions.atlassian.net/browse/BL-1865) Allow createDynamicProxy(), createObject() to accept a class loader

[BL-1866](https://ortussolutions.atlassian.net/browse/BL-1866) Ignore valid template extension setting of \* when searching for Application descriptors

[BL-1867](https://ortussolutions.atlassian.net/browse/BL-1867) can't dump java.sql.Time

[BL-1877](https://ortussolutions.atlassian.net/browse/BL-1877) Performance tuning on cache stores

### New Features

[BL-1791](https://ortussolutions.atlassian.net/browse/BL-1791) Implement bytecode compat version

[BL-1861](https://ortussolutions.atlassian.net/browse/BL-1861) New getAsChar() on IStruct for convenience

[BL-1875](https://ortussolutions.atlassian.net/browse/BL-1875) New JDBCStore for the Box Cache

[BL-1876](https://ortussolutions.atlassian.net/browse/BL-1876) Cache stores now have a isDistributed() interface method which allows cache providers and eco system to tell if the store can distribute content or be local only

[BL-1880](https://ortussolutions.atlassian.net/browse/BL-1880) New SSE() BIF and Emitter for Web Runtimes to allow for server side event streaming. Especially great when building AI Agents

[BL-1883](https://ortussolutions.atlassian.net/browse/BL-1883) New BoxAST() bif to help you return the AST of source or a filepath

### Bugs

[BL-1376](https://ortussolutions.atlassian.net/browse/BL-1376) specifying \`username\` and \`password\` throws 'unable to open connection' in cfquery - mssql

[BL-1685](https://ortussolutions.atlassian.net/browse/BL-1685) CFStoredProc does not return multiple result sets when using a statement like an insert as first query

[BL-1809](https://ortussolutions.atlassian.net/browse/BL-1809) Servlet resolution of relative paths can return incorrect mapping

[BL-1810](https://ortussolutions.atlassian.net/browse/BL-1810) Prevent Double Encoding of Query Params passed by HTTParam

[BL-1811](https://ortussolutions.atlassian.net/browse/BL-1811) loose struct converter can error on getting public fields

[BL-1812](https://ortussolutions.atlassian.net/browse/BL-1812) Don't catch abort exceptions

[BL-1814](https://ortussolutions.atlassian.net/browse/BL-1814) appending null to list fails

[BL-1815](https://ortussolutions.atlassian.net/browse/BL-1815) listDeleteAt() is not working correctly on cfml compat mode or not

[BL-1816](https://ortussolutions.atlassian.net/browse/BL-1816) Stored Procedure errors out on missing parameter

[BL-1817](https://ortussolutions.atlassian.net/browse/BL-1817) FileCopy bif using overwrite is not using it.

[BL-1820](https://ortussolutions.atlassian.net/browse/BL-1820) mapping paths with ../ not always normalized

[BL-1821](https://ortussolutions.atlassian.net/browse/BL-1821) recursive class references cause stack overflow on JSON serialization

[BL-1822](https://ortussolutions.atlassian.net/browse/BL-1822) Compat: HTTP getAsBinary=no not always honored in other engines

[BL-1823](https://ortussolutions.atlassian.net/browse/BL-1823) Duplicate Fails When Encountering Optional

[BL-1824](https://ortussolutions.atlassian.net/browse/BL-1824) HTTP Component Returns Raw Optional for Result response When No Timeout is Specified

[BL-1829](https://ortussolutions.atlassian.net/browse/BL-1829) Module publicMapping is not being registered

[BL-1831](https://ortussolutions.atlassian.net/browse/BL-1831) dateConvert is throwing an error

[BL-1833](https://ortussolutions.atlassian.net/browse/BL-1833) bx:mail not handling string useSSL or useTLS attributes

[BL-1834](https://ortussolutions.atlassian.net/browse/BL-1834) CFDUMP and WRITEDUMP do not dump to a file

[BL-1837](https://ortussolutions.atlassian.net/browse/BL-1837) Instances of IService in BL Modules never call onConfigurationLoad

[BL-1840](https://ortussolutions.atlassian.net/browse/BL-1840) CF transpiler doesn't catch dynamic sql type on proc param

[BL-1841](https://ortussolutions.atlassian.net/browse/BL-1841) BOXLANG\_DEBUG env var not used in servlet

[BL-1842](https://ortussolutions.atlassian.net/browse/BL-1842) Class dump doesn't output this scope values, just keys twice

[BL-1845](https://ortussolutions.atlassian.net/browse/BL-1845) subsequent requests do not respect in-progress onApplicationStart()

[BL-1847](https://ortussolutions.atlassian.net/browse/BL-1847) I am getting an error after server forget and server start

[BL-1851](https://ortussolutions.atlassian.net/browse/BL-1851) Better error for Import Statements in Class bodies

[BL-1854](https://ortussolutions.atlassian.net/browse/BL-1854) Web Compat: Empty \`allow\` argument to FileUpload is treated as "All" by other Engines

[BL-1856](https://ortussolutions.atlassian.net/browse/BL-1856) MiniServer Exchange GetRequestBody Method Throws Error when RequestBody Is Empty

[BL-1857](https://ortussolutions.atlassian.net/browse/BL-1857) GetFileInfo Returns Incorrect \`type\` string for Directory

[BL-1858](https://ortussolutions.atlassian.net/browse/BL-1858) File Uploads smaller than 10KB not being stored on disk

[BL-1860](https://ortussolutions.atlassian.net/browse/BL-1860) expandPath() uses wrong base path when application.xx is in different dir

[BL-1870](https://ortussolutions.atlassian.net/browse/BL-1870) stored proc param not casting timestamp

[BL-1871](https://ortussolutions.atlassian.net/browse/BL-1871) Regression Windows Boxlang REPL

[BL-1872](https://ortussolutions.atlassian.net/browse/BL-1872) FileUpload - When Temp directory is passed in explicitly in absolute destination path, directories should be created

[BL-1873](https://ortussolutions.atlassian.net/browse/BL-1873) FileUpload - Ensure correct handling for template relative destination paths

[BL-1874](https://ortussolutions.atlassian.net/browse/BL-1874) jsessionid cookie value set to null - breaks AWS WAF

[BL-1878](https://ortussolutions.atlassian.net/browse/BL-1878) Mapping CGI scope returns null values

[BL-1879](https://ortussolutions.atlassian.net/browse/BL-1879) Add handling for string dates as a common mask


# 1.6.0

October 3, 2025

<figure><img src="/files/xF25fpHnAslwwPWHKaf0" alt=""><figcaption></figcaption></figure>

BoxLang 1.6.0 brings significant performance improvements, enhanced async capabilities with advanced executor monitoring, improved REPL/MiniConsole framework, and better module mapping support. This release focuses on optimization, developer experience, and compatibility enhancements.

### 🚀 Major Highlights

### 📚 BoxLang Documentation MCP Server

<figure><img src="/files/Hh32Yns5Zfn699NpSL30" alt=""><figcaption></figcaption></figure>

BoxLang documentation is now accessible via the **Model Context Protocol (MCP)**! Connect AI assistants like Claude, GitHub Copilot, and other MCP-compatible tools directly to the comprehensive BoxLang documentation for instant access to language references, framework features, and best practices.

**Connect to the MCP Server:**

* **Direct MCP URL**: `https://boxlang.ortusbooks.com/~gitbook/mcp`
* **One-Click VSCode Installation**: [Install BoxLang MCP Server](vscode:mcp/install?%7B%22name%22%3A%22BoxLang%20%3A%20A%20Modern%20Dynamic%20JVM%20Language%22%2C%22url%22%3A%22https%3A%2F%2Fboxlang.ortusbooks.com%2F~gitbook%2Fmcp%22%7D)

This enables developers to:

* 🔍 Search BoxLang documentation semantically from within AI assistants
* 💡 Get instant answers about BIFs, components, and framework features
* 📖 Access code examples and best practices without leaving your workflow
* 🤖 Enhance AI-assisted BoxLang development with authoritative documentation

### Enhanced BoxExecutor with Health Monitoring & Statistics

The `ExecutorRecord` has been transformed into a full-fledged `BoxExecutor` class with comprehensive health monitoring, activity tracking, and advanced statistics. This provides deep insights into your async operations.

You can now retrieve detailed stats and health information about your executors. The following are the different status strings you can expect:

* `healthy` - Executor is operating normally within defined thresholds.
* `degraded` - Executor is experiencing some issues but is still functional. May indicate high load or minor problems.
* `critical` - Executor is in a critical state and may not be functioning properly. Immediate attention is required.
* `idle` - Executor has no active tasks and is idle.
* `shutdown` - Executor is in the process of shutting down and will not accept new tasks.
* `terminated` - Executor has been terminated and is no longer operational.
* `draining` - Executor is finishing existing tasks but not accepting new ones.

The new Executor Health Report provides a detailed analysis of the executor's health, including detected issues, recommendations for improvement, alerts for critical conditions, and insights into performance trends. The result is a structure containing the following keys:

* `status` - Overall health status of the executor.
* `summary` - A brief summary of the executor's health.
* `issues` - An array of detected issues affecting the executor's health.
* `recommendations` - An array of recommended actions to improve executor health.
* `alerts` - An array of critical alerts that require immediate attention.
* `insights` - An array of insights into executor performance and trends.
* `lastChecked` - Timestamp of the last health check.

```js
// Get executor and check its comprehensive stats including health
executor = asyncService.getExecutor( "myExecutor" )
stats = executor.getStats()

// Returns detailed metrics including:
// - Basic info: name, type, created, uptime, lastActivity
// - Task metrics: taskSubmissionCount, taskCount, completedTaskCount, activeCount
// - Pool metrics: poolSize, corePoolSize, maximumPoolSize, largestPoolSize
// - Queue metrics: queueSize, queueCapacity, queueUtilization
// - Utilization: poolUtilization, threadsUtilization, taskCompletionRate
// - Health status: healthStatus ("healthy", "degraded", "critical", "idle", etc.)
// - Health report: detailed analysis with issues, recommendations, alerts, insights

// Check if executor is healthy (simple boolean check)
isHealthy = executor.isHealthy()  // returns true/false

// Access health information from stats
healthStatus = stats.healthStatus  // "healthy", "degraded", "critical", "idle", "shutdown", "terminated", "draining"
healthReport = stats.healthReport  // Detailed health analysis

// Health report includes:
// - status: overall health status
// - summary: brief description
// - issues: array of detected problems
// - recommendations: array of suggested actions
// - alerts: array of critical alerts
// - insights: array of performance insights
```

This opens the door for our future tooling around executor management and monitoring.

### MiniConsole Framework & REPL Improvements

A new `MiniConsole` framework has been introduced, bringing sophisticated terminal interaction capabilities and dramatically improved REPL experience with:

* **Syntax highlighting** for BoxLang code with color themes (dark/light palettes)
* **Tab completion** for BIFs and components with intelligent providers
* **Cross-platform key handling** (Windows, macOS, Linux)
* **Multi-line editing** with continuation prompts
* **Command history** with shortcuts (`!!`, `!n`)
* **Color printing utilities** for rich terminal output
* **Much More**

```js
// REPL now includes smart syntax highlighting
📦 BoxLang> arrayMap( [1,2,3], (x) => x * 2 )
// BIFs in bright green, functions in purple

// Tab completion for components and BIFs
� BoxLang> array<TAB>
// Shows: arrayMap, arrayFilter, arrayEach, arrayReduce...
```

### Module Public Mapping Support

Modules have now a new mapping by convention called `publicMapping` that allows you to define a public mapping for your module's assets. This is in addition to the existing `mapping` property which is used for internal module paths and not visible outside the module. The `publicMapping` can be defined as a simple string or a struct for advanced configuration.

```js
// In ModuleConfig.bx
component {
    // Simple string - creates /bxModules/{moduleName}/public mapping
    this.publicMapping = "public"

    // Or use a struct for advanced config
    this.publicMapping = {
        name: "assets",
        path: "resources/public",
        usePrefix: true,
        external: true
    }

    // Enhanced this.mapping also supports structs
    this.mapping = {
        name: "myModule",
        path: "models",
        usePrefix: false
    }
}
```

## 🤖 Core Runtime Updates

### Performance Optimizations

We have done a second round of performance optimizations focusing on reducing thread contention, memory usage, and improving throughput. Key improvements include:

* **Deferred interception data creation** based on `hasState()` checks, which have increased throughput by over 50x
* **Removed synchronized modifiers** on singleton `getInstance()` methods, improving concurrency and dramatically reducing thread contention
* **Non-concurrent maps** for context config and other internal data structures (reduced thread contention dramatically)
* **Weak reference disk class caching** for better memory management, 80% reduction in memory usage in some scenarios
* **Cached Application descriptor lookups** when trusted cache is enabled
* **Overloaded internal `expandPath()` method** for known mappings to avoid `context.getConfig()` calls
* **ASM compiler improvements** to avoid method-level synchronization in `getInstance()` patterns

These performance improvements can lead to significant speedups in high-concurrency environments and reduce memory footprint considerably. Compilation and execution times are becoming instant in some scenarios. This is a significant jump in performance for BoxLang. We have updated our TechEmpower benchmarks to include BoxLang and how it compares to Adobe and Lucee using vanilla code and also ColdBox. We will be releasing the results soon and will always be available publicly.

We have seen performance and throughput improvements ranging from 45-65% in various benchmarks and vanilla ColdBox applications, between `1.6` and previous `1.5.x` releases. Using BoxLang and our SocketBox websocket's library and server we have seen capabilities of over 5,000 concurrent websocket connections running smoothly on a modest development machine.

#### Performance Stats

* Plain text and updates tests increased from 23,000 requests per second to over 53,000 requests per second on modest cloud VM
* SQL queries tests jumped from 15k requests per second to over 18k requests per second
* 5,000 concurrent websocket connections on a dev laptop with 256 MB of memory allocated to the JVM (Windows, Linux would be higher)
  * CPU once they were all connected and sending 500 heartbeat req/sec was only 4-5%
  * This test pushed 55,000 requests to the server in \~1 minute with an average processing time of 24ms and 0 errors
  * Total heap used never went past 190 MB during the test

More coming soon.

### DateTime Enhancements

* **Immutability flag** to prevent timezone mutation during formatting
* **Performance optimizations** for DateTime class operations
* **Improved date parsing** with better mask support (`yyyy/M/d`)
* **Two-digit year handling** always assumes current millennium
* **Consistent default formats** between parsed date results
* **DateFormat BIF compatibility** - all `m` letters treated as `M`

### JDBC & Database

* **Disabled connection leak detection by default** for better performance
* **Fixed NPE in bx-mariadb** when checking DDL statement results
* **Improved query param encoding** in HTTP requests

## 📡 MiniServer Runtime Updates

### Enhanced Error Handling

* **Improved exception handling** when invalid arguments are provided
* **STOMP heartbeat responses** now properly returned from miniserver
* **Version flag support** - `boxlang-miniserver --version` displays version information

## 🤖 Servlet Runtime Updates

### Jakarta EE Compliance

* **Updated web.xml to Jakarta specs** with proper namespace declarations
* **Integration tests added** to verify WAR deployment can expand, deploy, and run BoxLang code successfully
* **Fixed file upload handling** for small files in servlet environment

## 🚀 AWS Lambda Runtime Updates

* **Upgraded AWS Lambda Java Core** from 1.3.0 to 1.4.0

## 🛠️ Developer Experience

### BIF & Component Documentation

Built-in functions and components now include runtime descriptions via the `description` attribute in `@BoxBIF` and `@BoxComponent` annotations:

```java
@BoxBIF(
    description = "Returns the length of a string, array, struct, or query"
)
public class Len extends BIF {
    // ...
}

@BoxComponent(
    name = "Http",
    description = "Makes HTTP/HTTPS requests to remote servers"
)
public class Http extends Component {
    // ...
}
```

### CFTranspile Improvements

* **Verbose mode added** to `cftranspile` command for detailed conversion insights
* Better visibility into transpilation issues and potential data concerns

### Feature Audit Tool

* **Updated feature audit** with improved output
* **Lists missing modules** to help identify required BoxLang modules for migrations

## 🐛 Notable Bug Fixes

### Component & Function Fixes

* **`structKeyExists()` now works on closures**
* **`imageRead()`** properly expands paths and handles URIs
* **`bx:cookie` expires attribute** now processes dates before strings
* **HTTP component** now returns results when both `file` and `path` are specified
* **File/Path compatibility** improved between BoxLang, Lucee, and Adobe CF

### XML Handling

* **`XMLElemNew()` usage** - XMLAttribute on produced nodes no longer throws errors
* **Empty `xmlNew()` results** now produce valid XML objects with nodes
* **Multiple BOMs** - parsing no longer fails on files with multiple byte order marks

### Parsing Improvements

* **Extra spaces in tag close** now parse correctly
* **`return` keyword** can now be used as a variable name
* **`component` keyword** can be used as annotation name
* **FQN starting with underscore** now supported
* **Property shortcuts with FQN types** now work properly

### List & Compatibility Fixes

* **`ListDeleteAt()` retains leading delimiters** in compatibility mode
* **CF compat nulls** now equal empty strings
* **`IsValid()` supports `number` type** in compatibility mode
* **Lucee JSON compatibility** - unquoted keys in JSON handled consistently with Lucee when in compatibility mode
* **Duplication util** now uses correct class loader when serializing classes

## 🔧 Configuration Updates

### Datasource Environment Variables

* **Datasource keys** are now searched for environment variable replacements in configuration
* Supports patterns like `${DB_HOST}`, `${DB_PORT}` in datasource definitions

### Mapping Configuration

* **Enhanced mapping registration** detects between simple and complex mappings
* Better handling of module mappings with `usePrefix` and external flags

## ⚡ Migration Notes

### Breaking Changes

None registered for this release.

### Compatibility Improvements

This release includes numerous compatibility fixes for Adobe ColdFusion and Lucee migrations:

* DateFormat mask handling (`m` vs `M`)
* ListDeleteAt delimiter behavior
* Null handling in CF compat mode
* IsValid type validation
* JSON unquoted key handling

### Performance Considerations

* **JDBC connection leak detection** is now disabled by default. Enable via configuration if needed for debugging
* **Trusted cache behavior** - Application descriptor lookups are now cached when trusted cache is enabled
* Consider using the new **BoxExecutor health monitoring** to track async operation performance

## 🎶 Release Notes

### Improvements

[BL-1591](https://ortussolutions.atlassian.net/browse/BL-1591) Update the feature audit tool - Part 2

[BL-1735](https://ortussolutions.atlassian.net/browse/BL-1735) Bad link on dateformat in docs

[BL-1741](https://ortussolutions.atlassian.net/browse/BL-1741) Performance optimizations for DateTime class

[BL-1742](https://ortussolutions.atlassian.net/browse/BL-1742) HTTP Param - Change URL param handling to Encode Always

[BL-1747](https://ortussolutions.atlassian.net/browse/BL-1747) defer intercept data creation based on hasState()

[BL-1748](https://ortussolutions.atlassian.net/browse/BL-1748) avoid synchronized modifier on singleton getInstance() methods

[BL-1749](https://ortussolutions.atlassian.net/browse/BL-1749) Convert context config to non-concurrent maps for performance

[BL-1750](https://ortussolutions.atlassian.net/browse/BL-1750) assorted small performance fixes

[BL-1752](https://ortussolutions.atlassian.net/browse/BL-1752) Disable JDBC connection leak detection by default

[BL-1753](https://ortussolutions.atlassian.net/browse/BL-1753) Add weak reference disk class caching

[BL-1754](https://ortussolutions.atlassian.net/browse/BL-1754) Cache Application descriptor lookups when trusted cache is enabled

[BL-1755](https://ortussolutions.atlassian.net/browse/BL-1755) Provide overloaded internal expandpath method for known mappings to avoid context.getConfig()

[BL-1758](https://ortussolutions.atlassian.net/browse/BL-1758) bx:cookie did not try to process \`expires\` as a date before a string

[BL-1765](https://ortussolutions.atlassian.net/browse/BL-1765) Improve exception handling on miniserver when arguments are invalid

[BL-1767](https://ortussolutions.atlassian.net/browse/BL-1767) Added verbose mode to the cftranspile command to see issues or potential data

[BL-1775](https://ortussolutions.atlassian.net/browse/BL-1775) calling getCachedObjectMetadata registers as a hit

[BL-1785](https://ortussolutions.atlassian.net/browse/BL-1785) Improve type names in error messages

[BL-1786](https://ortussolutions.atlassian.net/browse/BL-1786) modify getInstance pattern in ASM compiler to avoid method-level synchronization

[BL-1793](https://ortussolutions.atlassian.net/browse/BL-1793) Configuration mappings registration needs to be updated to detect between a simple and a complex mapping

[BL-1794](https://ortussolutions.atlassian.net/browse/BL-1794) Add \`context\` to intercept data whenever you can find interception calls that require it

[BL-1795](https://ortussolutions.atlassian.net/browse/BL-1795) The key to the datasource needs to be searched for env replacements in the configuraiton

[BL-1802](https://ortussolutions.atlassian.net/browse/BL-1802) Update feature audit to output list of missing modules

[BL-1805](https://ortussolutions.atlassian.net/browse/BL-1805) return STOMP heartbeat responses from miniserver

### Bugs

[BL-1586](https://ortussolutions.atlassian.net/browse/BL-1586) ImageRead does not expand the path

[BL-1672](https://ortussolutions.atlassian.net/browse/BL-1672) imageRead with URIs

[BL-1690](https://ortussolutions.atlassian.net/browse/BL-1690) When using compatibility mode and set to Lucee, handling of unquoted keys in json is not consistent with Lucee.

[BL-1695](https://ortussolutions.atlassian.net/browse/BL-1695) duplication util doesn't use correct class loader when serializing classes

[BL-1710](https://ortussolutions.atlassian.net/browse/BL-1710) Cannot use structKeyExists on closure

[BL-1727](https://ortussolutions.atlassian.net/browse/BL-1727) small files not uploaded in servlet

[BL-1729](https://ortussolutions.atlassian.net/browse/BL-1729) Compare Operations Should Not Use Collations unless Locale Sensitivity is Specified

[BL-1731](https://ortussolutions.atlassian.net/browse/BL-1731) Change Deprecated Uses of StringUtils compare and contains functions to use new Strings API

[BL-1732](https://ortussolutions.atlassian.net/browse/BL-1732) number caster doesn't trim spaces on incoming strings

[BL-1736](https://ortussolutions.atlassian.net/browse/BL-1736) Native toString output of ZonedDateTime object not being parsed/cast correctly

[BL-1737](https://ortussolutions.atlassian.net/browse/BL-1737) HTTP Component not returning result if \`file\` and \`path\` are specified

[BL-1738](https://ortussolutions.atlassian.net/browse/BL-1738) File/Path compat differences between BL/Lucee/Adobe

[BL-1739](https://ortussolutions.atlassian.net/browse/BL-1739) Add Immutability Flag to DateTime Objects to Prevent Timezone Mutation on Format

[BL-1740](https://ortussolutions.atlassian.net/browse/BL-1740) Inconsistent default formats between parsed date results

[BL-1743](https://ortussolutions.atlassian.net/browse/BL-1743) Can't create application caches on Windows

[BL-1744](https://ortussolutions.atlassian.net/browse/BL-1744) Ensure Two-Digit Year is Always Assumptive of Current Millenium in Date Parsing

[BL-1745](https://ortussolutions.atlassian.net/browse/BL-1745) Dates with Mask \`yyyy/M/d\` are not parsed natively

[BL-1751](https://ortussolutions.atlassian.net/browse/BL-1751) cache component announcing wrong interception point

[BL-1756](https://ortussolutions.atlassian.net/browse/BL-1756) Compat behavior - ListDeleteAt should retain leading delimiters

[BL-1763](https://ortussolutions.atlassian.net/browse/BL-1763) CF compat nulls need to equal empty string

[BL-1766](https://ortussolutions.atlassian.net/browse/BL-1766) Compat: IsValid does not support \`number\` as a type

[BL-1769](https://ortussolutions.atlassian.net/browse/BL-1769) XMLAttribute usage on node produced by XMLElemNew Throws Error

[BL-1771](https://ortussolutions.atlassian.net/browse/BL-1771) Empty xmlNew Result produces an XML object with no node

[BL-1776](https://ortussolutions.atlassian.net/browse/BL-1776) ASM bug on loading a pre-compiled class when doing renaming of identifiers: illegalArgumentException null

[BL-1777](https://ortussolutions.atlassian.net/browse/BL-1777) In function \[logMessage], argument \[logEvent] with a type of \[boxgenerated.boxclass.coldbox.system.logging.Logevent$cfc] does not match the declared type of \[coldbox.system.logging.LogEvent] when using pre-compiled source

[BL-1782](https://ortussolutions.atlassian.net/browse/BL-1782) boxlang run compiled template gets confused when doing shebang detection

[BL-1784](https://ortussolutions.atlassian.net/browse/BL-1784) pre-compiled classes not getting their name metadata set properly

[BL-1789](https://ortussolutions.atlassian.net/browse/BL-1789) bx-mariadb throwing NPE checking for results on DDL statement

[BL-1797](https://ortussolutions.atlassian.net/browse/BL-1797) Extra space in tag close not parsing

[BL-1798](https://ortussolutions.atlassian.net/browse/BL-1798) Use of return keyword as variable

[BL-1799](https://ortussolutions.atlassian.net/browse/BL-1799) Use of component keyword as annotation name

[BL-1800](https://ortussolutions.atlassian.net/browse/BL-1800) FQN starting with \_

[BL-1801](https://ortussolutions.atlassian.net/browse/BL-1801) property shortcut with FQN as type

[BL-1803](https://ortussolutions.atlassian.net/browse/BL-1803) Parsing fails on files with multiple BOMs

[BL-1804](https://ortussolutions.atlassian.net/browse/BL-1804) Compat - For DateFormat BIF treat all \`m\` letters as \`M\`

### New Features

[BL-1498](https://ortussolutions.atlassian.net/browse/BL-1498) Enhance executor stats

[BL-1718](https://ortussolutions.atlassian.net/browse/BL-1718) Update servlet web.xml to new Jakarta specs and added intgration test for the WAR to check it can expand, deploy and run BoxLang code.

[BL-1725](https://ortussolutions.atlassian.net/browse/BL-1725) ExecutorRecord becomes a class BoxExecutor due to instance data required for stats and health metrics

[BL-1726](https://ortussolutions.atlassian.net/browse/BL-1726) Enhance BoxLang BoxExecutor with Health Monitoring, Activity Tracking, and Advanced Statistics

[BL-1746](https://ortussolutions.atlassian.net/browse/BL-1746) Bump com.amazonaws:aws-lambda-java-core from 1.3.0 to 1.4.0

[BL-1760](https://ortussolutions.atlassian.net/browse/BL-1760) this.mapping for modules needs to support simple string and a struct of mapping options

[BL-1762](https://ortussolutions.atlassian.net/browse/BL-1762) Introduce this.publicMapping for modules to allow for public mapping by convention

[BL-1764](https://ortussolutions.atlassian.net/browse/BL-1764) Repl Improvements + MiniConsole Framework

[BL-1779](https://ortussolutions.atlassian.net/browse/BL-1779) Adding a description to the BoxBif and BoxComponent annotations for short inline descriptions

[BL-1780](https://ortussolutions.atlassian.net/browse/BL-1780) Add a boxlang-miniserver --version to spit out the version information

[BL-1783](https://ortussolutions.atlassian.net/browse/BL-1783) BIFS and Components now include a runtime description

### Tasks

[BL-1759](https://ortussolutions.atlassian.net/browse/BL-1759) remove unused variables in the module record that's not implemented


# 1.5.0

August 30, 2025

We're excited to announce BoxLang 1.5.0, bringing significant improvements to performance, reliability, and developer experience. This release focuses on enhanced AWS Lambda support, better Java interoperability, improved query handling, and numerous bug fixes that make BoxLang more robust for production workloads.

## 🚀 Major Highlights

### **AWS Lambda Runtime Enhancements**

BoxLang 1.5.0 introduces powerful optimizations for serverless deployments, including class caching, connection pooling, and performance metrics.

### **Enhanced Query Operations**

Improved support for multiple SQL statements, better parameter handling, and enhanced metadata capture for database operations.

### **Advanced Java Interop**

Better method resolution for overloaded Java methods and improved handling of primitive type expectations.

***

## 🏗️ AWS Lambda Runtime Features

### **Lambda Class Caching**

*Ticket:* [*BL-1712*](https://ortussolutions.atlassian.net/browse/BL-1712)

BoxLang now caches compiled lambda classes to avoid expensive recompilations on subsequent invocations, dramatically improving cold start performance.

```javascript
// Your BoxLang lambda handlers now benefit from automatic class caching
function handler( event, context ) {
    // Compiled classes are cached automatically for faster subsequent invocations
    return {
        "statusCode" : 200,
        "body" : serializeJSON( processEvent( event ) )
    };
}
```

### **Configurable Connection Pooling**

*Ticket:* [*BL-1716*](https://ortussolutions.atlassian.net/browse/BL-1716)

Control AWS runtime connection pool size via the new environment variable:

```bash
# Set connection pool size (defaults to 2)
BOXLANG_LAMBDA_CONNECTION_POOL_SIZE=2
```

### **Performance Metrics Logging**

*Ticket:* [*BL-1713*](https://ortussolutions.atlassian.net/browse/BL-1713)

Enable detailed performance metrics in debug mode to monitor Lambda execution times and resource usage.

## **Convention-Based URI Routing**

*Ticket:* [*BL-1714*](https://ortussolutions.atlassian.net/browse/BL-1714)

Automatic routing using PascalCase conventions. You can now build multi-class Lambda functions with BoxLang easily following our conventions.

```javascript
// URL: /products -> Products.bx
// URL: /home-savings -> HomeSavings.bx  
// URL: /user-profile -> UserProfile.bx

// Products.bx
function handler( event, context ) {
    return {
        "statusCode" : 200,
        "body" : getProductCatalog()
    };
}
```

***

## 🔧 Core Runtime Improvements

### **Enhanced File Upload Support**

*Tickets:* [*BL-1664*](https://ortussolutions.atlassian.net/browse/BL-1664)*,* [*BL-1663*](https://ortussolutions.atlassian.net/browse/BL-1663)

FileUpload now includes `blockedExtensions` argument and correctly populates file name properties:

```javascript
// Enhanced file upload with security
result = fileUpload( 
    destination = "/uploads/", 
    fileField = "attachment",
    blockedExtensions = [ "exe", "bat", "com" ],
    allowedExtensions = [ "jpg", "png", "pdf", "docx" ]
);

// Correctly populated properties
writeOutput( "Client filename: " & result.clientFile );
writeOutput( "Server filename: " & result.serverFile );
writeOutput( "Original name: " & result.clientFileName );
writeOutput( "Saved as: " & result.serverFileName );
```

### **Improved Error Handling for Primitive Returns**

*Ticket:* [*BL-1680*](https://ortussolutions.atlassian.net/browse/BL-1680)

Better error messages when proxied UDFs return null where primitives are expected:

```javascript
// Before: Cryptic casting error
// After: Clear error message
function getScore() {
    return; // null return
}

numeric score = getScore(); // Now provides clear error about null->numeric conversion
```

### **Memory Leak Prevention**

*Ticket:* [*BL-1697*](https://ortussolutions.atlassian.net/browse/BL-1697)

Enhanced thread management prevents memory leaks with unbounded thread usage in long-running applications.

### **Virtual Thread Support for Parallel Operations**

*Ticket:* [*BL-1687*](https://ortussolutions.atlassian.net/browse/BL-1687)

All parallel BIFs now support a `virtual` argument to leverage Java's virtual threads for improved performance and resource efficiency. You can also pass it instead of the `maxThreads` argument as well.

```javascript
// Array operations with virtual threads
largeNumbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];

// Use virtual threads for parallel processing
results = arrayMap( largeNumbers, ( item ) => {
    // Simulate heavy computation
    sleep( 100 );
    return item * item;
}, true, true ); // maxThreads=true => virtual=true

// List operations with virtual threads  
csvData = "apple,banana,cherry,date,elderberry";
processed = listMap( csvData, ( item ) => {
    return uCase( item );
}, ",", true, true ); // delimiter, maxThreads=true => virtual=true

// Query operations with virtual threads
users = queryNew( "id,name,email", "integer,varchar,varchar", [
    [ 1, "John", "john@test.com" ],
    [ 2, "Jane", "jane@test.com" ],
    [ 3, "Bob", "bob@test.com" ]
] );

// Process query rows with virtual threads
queryEach( users, ( row, index ) => {
    // Simulate API call or heavy processing
    validateEmail( row.email );
}, true, true ); // maxThreads=true => virtual=true

// Struct operations with virtual threads
userPrefs = {
    "theme" : "dark",
    "language" : "en", 
    "notifications" : "enabled"
};

// Filter preferences with virtual threads
activePrefs = structFilter( userPrefs, ( key, value ) => {
    return value != "disabled";
}, true, true ); // maxThreads=true => virtual=true

// Traditional vs Virtual Thread comparison
// Traditional platform threads (limited by OS)
results1 = arrayMap( data, processor, 10, false ); // 10 platform threads

// Virtual threads (lightweight, managed by JVM)  
results2 = arrayMap( data, processor, true, true ); // Auto threads, virtual=true
```

**Performance Benefits:**

* **Reduced Memory Footprint**: Virtual threads use significantly less memory than platform threads
* **Better Scalability**: Handle thousands of concurrent operations without thread pool exhaustion
* **Improved Throughput**: Especially beneficial for I/O-bound operations like API calls or database queries

**Supported Methods:**

<table><thead><tr><th width="86.69140625">Type</th><th>Methods</th></tr></thead><tbody><tr><td><strong>Array</strong></td><td><code>arrayEach()</code>, <code>arrayEvery()</code>, <code>arrayFilter()</code>, <code>arrayMap()</code>, <code>arrayNone()</code>, <code>arraySome()</code></td></tr><tr><td><strong>List</strong></td><td><code>listEach()</code>, <code>listEvery()</code>, <code>listFilter()</code>, <code>listMap()</code>, <code>listNone()</code>, <code>listSome()</code></td></tr><tr><td><strong>Query</strong></td><td><code>queryEach()</code>, <code>queryEvery()</code>, <code>queryFilter()</code>, <code>queryMap()</code>, <code>queryNone()</code>, <code>querySome()</code></td></tr><tr><td><strong>Struct</strong></td><td><code>structEach()</code>, <code>structEvery()</code>, <code>structFilter()</code>, <code>structMap()</code>, <code>structNone()</code>, <code>structSome()</code></td></tr></tbody></table>

***

## 📊 Database & Query Enhancements

### **Multiple SQL Statement Support**

*Ticket:* [*BL-1186*](https://ortussolutions.atlassian.net/browse/BL-1186)

QueryExecute now properly handles multiple SQL statements:

```javascript
// Execute multiple statements in a single call
result = queryExecute( "
    UPDATE users SET last_login = NOW() WHERE id = :userID;
    INSERT INTO login_log (user_id, login_time) VALUES (:userID, NOW());
    SELECT * FROM users WHERE id = :userID;
", {
    "userID" : { value: 123, cfsqltype: "numeric" }
} );
```

### **Enhanced Generated Key Capture**

*Ticket:* [*BL-1700*](https://ortussolutions.atlassian.net/browse/BL-1700)

```javascript
// Capture all generated keys from INSERT operations
result = queryExecute( "
    INSERT INTO orders (customer_id, order_date) 
    VALUES (:customerID, NOW())
", {
    "customerID" : { value: 456, cfsqltype: "numeric" }
}, {
    result: "insertResult"
} );

// Access generated keys
newOrderID = insertResult.generatedKey;
writeOutput( "New order created with ID: " & newOrderID );
```

### **Update Count Tracking**

*Ticket:* [*BL-1701*](https://ortussolutions.atlassian.net/browse/BL-1701)

```javascript
// Track how many records were affected
result = queryExecute( "
    UPDATE products 
    SET price = price * 1.10 
    WHERE category = :category
", {
    "category" : { value: "Electronics", cfsqltype: "varchar" }
}, {
    result: "updateResult"  
} );

writeOutput( "Updated " & updateResult.recordCount & " products" );
```

### **Improved Parameter Handling**

*Ticket:* [*BL-1661*](https://ortussolutions.atlassian.net/browse/BL-1661)

Better handling of queries with both loose colons and positional parameters:

```javascript
// Now works correctly with mixed parameter styles
sql = "SELECT * FROM events WHERE start_time > '2024-01-01 00:00:00' AND user_id = ?";
result = queryExecute( sql, [ 123 ] );
```

***

## 🔗 Java Interoperability Improvements

### **Better Method Resolution**

*Ticket:* [*BL-1715*](https://ortussolutions.atlassian.net/browse/BL-1715)

Improved matching for overloaded Java methods:

```javascript
// Java class with multiple format() methods
formatter = createObject( "java", "java.text.DecimalFormat" ).init( "#,##0.00" );

// Now correctly resolves the right overloaded method
boxLangNumber = 1234.56;
formatted = formatter.format( boxLangNumber ); // "1,234.56"
```

*Ticket:* [*BL-1667*](https://ortussolutions.atlassian.net/browse/BL-1667)

Better preference handling when Java methods accept Object arguments:

```javascript
// BoxLang DateTime objects now properly handled
dateTime = now();
javaFormatter = createObject( "java", "java.time.format.DateTimeFormatter" )
    .ofPattern( "yyyy-MM-dd HH:mm:ss" );

// Now works correctly with BoxLang DateTime
formatted = javaFormatter.format( dateTime );
```

***

## 🏗️ CFML Compatibility Enhancements

### **Script Custom Tag Support**

*Ticket:* [*BL-1679*](https://ortussolutions.atlassian.net/browse/BL-1679)

Added support for Adobe ColdFusion script-based custom tags:

```javascript
// CustomButton.cfc (custom tag)
component {
    
    function onStart() {
        if ( !structKeyExists( attributes, "text" ) ) {
            attributes.text = "Click Me";
        }
        return true;
    }
    
    function onEnd() {
        writeOutput( '<button class="btn btn-primary">' & attributes.text & '</button>' );
        return true;
    }
}

// Usage in template
bx:customButton text="Save Changes";
```

### **Encrypted Datasource Password Support**

*Ticket:* [*BL-1127*](https://ortussolutions.atlassian.net/browse/BL-1127)

Support for Lucee-style encrypted datasource passwords:

```javascript
// BoxLang.json datasource configuration
{
    "datasources": {
        "myDB": {
            "driver": "mysql",
            "host": "localhost", 
            "database": "myapp",
            "username": "dbuser",
            "password": "encrypted:ABC123DEF456", // Encrypted password support
            "port": 3306
        }
    }
}
```

### **Component Name Annotation Fix**

*Ticket:* [*BL-1684*](https://ortussolutions.atlassian.net/browse/BL-1684)

The `name` annotation on components now correctly sets metadata without overwriting:

```javascript
/**
 * @name CustomService
 * @description Provides custom business logic
 */
component {
    // Component metadata.name is now correctly set to "CustomService"
    
    function init() {
        return this;
    }
}
```

***

## 🛠️ Developer Experience Improvements

### **Enhanced List Functions**

*Ticket:* [*BL-1660*](https://ortussolutions.atlassian.net/browse/BL-1660)

List BIFs now preserve custom delimiters when reassembling:

```javascript
// Custom delimiter is preserved
originalList = "apple|banana|cherry";
processedList = listSort( originalList, "text", "asc", "|" );
// Result maintains "|" delimiter: "apple|banana|cherry"

// Works with any delimiter
csvData = "John,25,Engineer";
sortedCsv = listSort( csvData, "text", "asc", "," );
// Maintains comma delimiter
```

*Tickets:* [*BL-1669*](https://ortussolutions.atlassian.net/browse/BL-1669)*,* [*BL-1670*](https://ortussolutions.atlassian.net/browse/BL-1670)

Duration objects can now be compared with integers and other numeric values:

```javascript
timeout = createTimeSpan( 0, 0, 5, 0 ); // 5 minutes
maxWait = 300; // 300 seconds

// Now works correctly
if ( timeout > maxWait ) {
    writeOutput( "Timeout exceeds maximum wait time" );
}

// Duration arithmetic with numbers
newTimeout = timeout + 60; // Add 60 seconds
```

### **Class Metadata Enhancement**

*Ticket:* [*BL-1686*](https://ortussolutions.atlassian.net/browse/BL-1686)

Box Class metadata now includes "output" key for better introspection:

```javascript
metadata = getMetadata( myComponent );
if ( metadata.output ) {
    writeOutput( "Component generates output" );
}
```

***

## 🐛 Notable Bug Fixes

#### **Query of Queries Parsing**

*Ticket:* [*BL-1678*](https://ortussolutions.atlassian.net/browse/BL-1678) Fixed parsing errors in Query of Queries when using parentheses in expressions.

#### **Super Reference Resolution**

*Ticket:* [*BL-1674*](https://ortussolutions.atlassian.net/browse/BL-1674) Corrected super reference resolution for mixin UDFs in parent classes.

#### **HTTP Header Handling**

*Ticket:* [*BL-1676*](https://ortussolutions.atlassian.net/browse/BL-1676) Resolved HTTP errors when Accept-Encoding and TE headers are set as HTTP parameters.

#### **Module Management**

*Ticket:* [*BL-1705*](https://ortussolutions.atlassian.net/browse/BL-1705) Fixed module unload process to properly remove and unregister module resources.

#### **Thread Context Handling**

*Ticket:* [*BL-1696*](https://ortussolutions.atlassian.net/browse/BL-1696) Ensured threads consistently use the correct context classloader.

#### **SQL Formatting**

*Ticket:* [*BL-1683*](https://ortussolutions.atlassian.net/browse/BL-1683) Fixed the `sqlPrettify` function for proper SQL formatting.

***

## 📊 Performance & Reliability

* **Memory Usage**: Reduced memory footprint through better thread management
* **AWS Cold Starts**: Significant improvement through lambda class caching
* **Database Operations**: Enhanced reliability with better error handling and connection management
* **Java Interop**: More efficient method resolution and argument handling

***

## 🔧 Configuration Updates

#### **Docker Environment Variables**

*Ticket:* [*BL-1673*](https://ortussolutions.atlassian.net/browse/BL-1673)

Resolved collision between Docker env var `BOXLANG_MODULES` and the config modules key.

#### **Cache Settings**

*Ticket:* [*BL-1709*](https://ortussolutions.atlassian.net/browse/BL-1709)

Cache settings now properly replaced by environment variables:

```bash
# Environment variables now correctly override cache settings
BOXLANG_CACHE_DEFAULT_TIMEOUT=3600
BOXLANG_CACHE_MAX_ELEMENTS=1000
```

***

## ⚡ Migration Notes

#### **Breaking Changes**

* None in this release

#### **Deprecations**

* No new deprecations

#### **Recommended Updates**

1. **AWS Users**: Set `BOXLANG_LAMBDA_CONNECTION_POOL_SIZE` environment variable for optimal performance
2. **File Upload**: Review code using `fileUpload()` to take advantage of new `blockedExtensions` security feature
3. **Module Developers**: Test module loading/unloading if you experienced issues in 1.4.x

***

## Release Notes

### Improvements

[BL-1556](https://ortussolutions.atlassian.net/browse/BL-1556) Bump org.semver4j:semver4j from 5.8.0 to 6.0.0.

[BL-1664](https://ortussolutions.atlassian.net/browse/BL-1664) fileUpload missing blockedExtensions argument

[BL-1680](https://ortussolutions.atlassian.net/browse/BL-1680) Better error if proxied UDF returns null where primitive is expected

[BL-1686](https://ortussolutions.atlassian.net/browse/BL-1686) add "output" key to Box Class Meta

[BL-1687](https://ortussolutions.atlassian.net/browse/BL-1687) Add \`Virtual\` Argument to BIF supporting parallel operations

[BL-1688](https://ortussolutions.atlassian.net/browse/BL-1688) DynamicObject not unwrapping arguments passed to method

[BL-1693](https://ortussolutions.atlassian.net/browse/BL-1693) Remove query column map from query metadata

[BL-1697](https://ortussolutions.atlassian.net/browse/BL-1697) Prevent memory leak with unbounded thread usage

[BL-1700](https://ortussolutions.atlassian.net/browse/BL-1700) Capture all generated keys

[BL-1701](https://ortussolutions.atlassian.net/browse/BL-1701) Capture update counts

[BL-1712](https://ortussolutions.atlassian.net/browse/BL-1712) AWS Runtime - Cache compiled lambda classes to avoid recompilations

[BL-1716](https://ortussolutions.atlassian.net/browse/BL-1716) AWS Runtime - Add aws runtime pool configuration via new ENV variable: BOXLANG\_LAMBDA\_CONNECTION\_POOL\_SIZE which defaults to 2

### Bugs

[BL-1186](https://ortussolutions.atlassian.net/browse/BL-1186) queryExecute multiple statements

[BL-1660](https://ortussolutions.atlassian.net/browse/BL-1660) List BIFs which reassemble the list don't preserve delimiters

[BL-1661](https://ortussolutions.atlassian.net/browse/BL-1661) queryExecute - cannot execute query containing loose ':' and positional parameters

[BL-1663](https://ortussolutions.atlassian.net/browse/BL-1663) fileUpload: serverFileName, serverFile, clientFile, clientFileName are not correct per the spec

[BL-1667](https://ortussolutions.atlassian.net/browse/BL-1667) Interop service when dealing with methods with \`Object\` arguments, would give preference to coercionable arguments. Ex: Formatter.format( BoxLang DateTime ) would fail

[BL-1668](https://ortussolutions.atlassian.net/browse/BL-1668) Trying to load module class before module is registered errors

[BL-1669](https://ortussolutions.atlassian.net/browse/BL-1669) duration can't compare against an integer

[BL-1670](https://ortussolutions.atlassian.net/browse/BL-1670) Compare operator cannot cast Duration to Number

[BL-1671](https://ortussolutions.atlassian.net/browse/BL-1671) JDBC - "driver not registered" log on engine startup despite being installed

[BL-1673](https://ortussolutions.atlassian.net/browse/BL-1673) Miniserver: Docker env var BOXLANG\_MODULES collides with modules key in config

[BL-1674](https://ortussolutions.atlassian.net/browse/BL-1674) super reference incorrect for mixin UDF in parent class

[BL-1675](https://ortussolutions.atlassian.net/browse/BL-1675) string caster not obeying fail flag when inputStream errors

[BL-1676](https://ortussolutions.atlassian.net/browse/BL-1676) HTTP Error When Accept-Encoding and TE Headers are being set as HTTP Params

[BL-1678](https://ortussolutions.atlassian.net/browse/BL-1678) Parsing error in QoQ with parentheses

[BL-1679](https://ortussolutions.atlassian.net/browse/BL-1679) Missing support for ACF script custom tags

[BL-1681](https://ortussolutions.atlassian.net/browse/BL-1681) Ignore extraneous return values from void proxies

[BL-1682](https://ortussolutions.atlassian.net/browse/BL-1682) Usage of quoted operators fails to compile.

[BL-1683](https://ortussolutions.atlassian.net/browse/BL-1683) sqlPrettify is broken

[BL-1684](https://ortussolutions.atlassian.net/browse/BL-1684) CFML Compat - \`name\` annotation on Component overwrites the metadata name

[BL-1696](https://ortussolutions.atlassian.net/browse/BL-1696) Threads not always using context classloader

[BL-1699](https://ortussolutions.atlassian.net/browse/BL-1699) JDBC not handling raised errors

[BL-1705](https://ortussolutions.atlassian.net/browse/BL-1705) Module unload fails to remove/unregister module resources

[BL-1706](https://ortussolutions.atlassian.net/browse/BL-1706) Issues with numberFormat masks

[BL-1709](https://ortussolutions.atlassian.net/browse/BL-1709) Cache settings do not get replaced by environment variables

[BL-1715](https://ortussolutions.atlassian.net/browse/BL-1715) Java interop matching in correct overloaded methods

### New Features

[BL-1127](https://ortussolutions.atlassian.net/browse/BL-1127) Add support for Lucee's encrypted datasource passwords in compat

[BL-1713](https://ortussolutions.atlassian.net/browse/BL-1713) AWS Runtime - Log performance metrics when in debug mode

[BL-1714](https://ortussolutions.atlassian.net/browse/BL-1714) AWS Runtime - URI Routing by convention using PascalCase: /products -> Products.bx, /home-savings -> HomeSavings.bx


# 1.4.0

August 2, 2025

We're excited to announce BoxLang v1.4.0, our biggest release yet! This major update brings powerful new features, performance improvements, and extensive bug fixes that make BoxLang more robust and developer-friendly than ever.

## 🚀 Core Runtime Updates

### Revolutionary Asynchronous Programming Framework

BoxLang v1.4.0 introduces a **game-changing asynchronous programming framework** that sets a new standard for JVM languages. This isn't just another async implementation—it's a comprehensive, battle-tested framework that makes parallel programming accessible, intuitive, and powerful in ways that other languages and frameworks simply don't offer.

**What makes this revolutionary:**

* **Zero boilerplate** - Write async code as naturally as synchronous code
* **Built-in parallel primitives** - No need for complex thread management or executor services
* **Functional composition** - Chain, compose, and transform async operations with ease
* **Exception safety** - Automatic error propagation and handling across async boundaries
* **Performance optimized** - Leverages modern JVM concurrency patterns under the hood
* **Dedicated logging** - Separate `async.log` and `scheduler.log` files for complete observability of async operations

**Core async primitives that change everything:**

* **`asyncRun()`** - Transform any operation into a non-blocking future (with `runAsync()` as an alias)
* **`asyncAll()`** - Execute multiple operations in parallel and aggregate results—no more callback hell or complex coordination
* **`asyncAllApply()`** - Map-reduce operations across collections in parallel with automatic work distribution
* **`asyncAny()`** - Race multiple operations and get the fastest result—perfect for timeout patterns and redundant services

**This is async programming reimagined.** While other languages force you to deal with complex promises, callbacks, or verbose async/await patterns, BoxLang gives you **declarative parallel programming** that just works.

This powerful new framework is fully documented in our comprehensive [Asynchronous Programming Guide](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming), including detailed sections on [Executors](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/executors), [BoxFutures](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/box-futures), [Async Pipelines](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/async-pipelines), [Parallel Computations](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/parallel-computations), and [Scheduled Tasks](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/scheduled-tasks).

```js
// Run multiple operations in parallel
results = asyncAll( [
    () => fetchUserData( userId ),
    () => fetchOrderHistory( userId ),
    () => fetchPreferences( userId )
] );

// Apply function to multiple inputs in parallel
processedData = asyncAllApply(
    [ "file1.txt", "file2.txt", "file3.txt" ],
    ( file ) => processFile( file )
);

// Get the first completed result
fastestResult = asyncAny( [
    () => callService1(),
    () => callService2(),
    () => callService3()
] );

// Powerful async pipelines - chain operations naturally
userPipeline = asyncRun( () => fetchUser( userId ) )
    .then( user => validateUser( user ) )
    .then( user => enrichUserData( user ) )
    .then( user => cacheUser( user ) )
    .onSuccess( user => auditLog( "User processed: #user.id#" ) )
    .onError( error => logError( "Pipeline failed: #error.message#" ) );

// Advanced scheduling with natural syntax
schedule.task( "data-cleanup" )
    .call( () => cleanupExpiredData() )
    .everyDayAt( "02:00" )  // Every day at 2 AM
    .timezone( "America/New_York" )
    .onSuccess( result => writeLog( "Cleanup completed: #result.recordsDeleted# records" ) )
    .onError( error => sendAlert( "Cleanup failed: #error.message#" ) );

// Weekly reports on business days
schedule.task( "weekly-report" )
    .call( () => generateWeeklyReport() )
    .onFridays( "17:00" )
    .withNoOverlaps()
    .onSuccess( report => emailReport( report ) );

// One-time delayed execution
schedule.task( "send-reminder" )
    .call( () => sendReminderEmail( userEmail ) )
    .delay( 1, "hours" )  // Execute in 1 hour
    .onSuccess( () => writeLog( "Reminder sent successfully" ) );

// Complex parallel data processing pipeline
reportData = asyncRun( () => fetchRawData() )
    .then( data => asyncAllApply( data, row => processRow( row ) ) )
    .then( processedRows => aggregateResults( processedRows ) )
    .then( summary => generateReport( summary ) )
    .onSuccess( report => emailReport( report ) )
    .get();  // Block and get the final result
```

### Enhanced BoxLang Mappings

Mappings now support an `external` flag (defaults to false) for better module organization and security. All mappings in the global runtime config `boxlang.json` and those in the `Application.bx|cfc` are `external = true` by default, meaning they can be accessed via the URL.

All module mappings are `external = false` by default, meaning they are not accessible via the URL.

````js
// Default External Mapping
this.mappings[ "myInternalMapping" ] = "/abc/internal/path";
this.mappings[ "myExternalMapping" ] = {
    path: "/abc/external/path",
    external: true  // Indicates this mapping CANNOT be accessed via URL
};

### Enhanced ZIP Functionality

New `zipparam`support provides fine-grained control over ZIP operations:

```js
zip( action="zip", file="myarchive.zip" ) {
    zipparam( source="folder1/", prefix="backup/" );
    zipparam( source="file.txt", entrypath="documents/readme.txt" );
}
````

### Loop Grouping Enhancements

BoxLang now supports complex nested grouping in queries and loops, allowing you to easily group data by multiple fields. This makes it simpler to generate reports and summaries directly in your templates.

```js
bx:loop( query="salesData", group="region,quarter" ) {
    writeOutput( "<h2>#region# - #quarter#</h2>" );

    bx:loop() {
        writeOutput( "<p>Sale: #amount# on #date#</p>" );
    }
}
```

## ⚡Miniserver Updates

Read all about the new miniserver features in our [MiniServer Guide](https://boxlang.ortusbooks.com/getting-started/running-boxlang/miniserver).

### Environment Variable Support (.env)

The BoxLang miniserver now supports `.env` files for configuration management. It will look for a `.env` file in the root of your project and load environment variables from it. This allows you to easily manage configuration settings without hardcoding them in your codebase.

```
# .env file
DATABASE_URL=jdbc:mysql://localhost:3306/mydb
API_KEY=your-secret-key
DEBUG_MODE=true
```

### Miniserver Health Checks

Added simple health check endpoints for container-based deployments, making BoxLang more cloud-native.

### Hidden File Protection

Basic protection against serving hidden files (dot files) in the miniserver for improved security.

## 🔧 Performance & Optimization Improvements

### String Performance Enhancements

* Significant performance improvements for `toScript()` BIF
* Optimized string operations throughout the runtime
* Better memory management for large string operations

### Custom Component Lookup Optimization

* Refactored custom component and class lookup for improved performance
* Better caching mechanisms for frequently accessed components
* Reduced overhead in component resolution

### Module Class Visibility

* Module classes are now properly visible to the context classloader
* Improved module loading and initialization performance

### JSON Processing Improvements

* Removed JSON serialization limits
* Enhanced JSON serialization of throwable objects
* Better handling of complex object graphs in JSON serialization

## 🛠️ Language & Runtime Improvements

### Enhanced Date/Time Handling

* Support for more natural date parsing masks (case-insensitive)
* Better timezone handling in `DateTimeCaster`
* Improved CFML compatibility for partial years
* Fixed issues with `GregorianCalendar.getTime()` return types

### Improved Type Coercion

* Skip type coercion for `===` operator (strict equality)
* Better handling of Java arrays in modifiable contexts
* Enhanced casting between BoxLang DateTime and Java Date types

### Better Error Handling

* Improved error messages in expression interpreter
* Enhanced `attempt.orThrow()` handling
* Better parsing errors for unclosed brackets

### Array & Collection Enhancements

* `ArrayResize` now accepts `long` values
* Added missing `max` and `min` member functions
* Fixed `WriteDump` errors on null array values

### Query Improvements

* Fixed query context issues in nested loops
* Resolved `queryDeleteColumn` data integrity issues
* Better handling of query serialization/deserialization
* Support for `queryObject.columnnames` property

### Regular Expression Enhancements

* Fixed back reference handling (including references > 9)
* Improved upper/lower case escapes in replacement text
* Better support for complex regex patterns

## 🐛 Major Bug Fixes

### JDBC & Database

* Fixed race conditions in threaded query execution
* Resolved nested transaction issues
* Fixed savepoint name length limitations
* Improved query caching with Redis integration

### File Operations

* Fixed `cfcontent` file corruption issues
* Better handling of relative file paths in `fileRead`
* Improved MIME type detection with strict mode
* Enhanced multipart form handling

### Session Management

* Fixed `SessionRotate` and `SessionInvalidate` JSessionId handling
* Better SameSite cookie attribute handling
* Improved session shutdown cache interceptor

### Component & Scope Handling

* Fixed private static struct function access
* Resolved scope access issues in custom tags
* Better handling of `thisComponent` scope (renamed from `thisTag`)

### Serialization & Casting

* Fixed `DeSerializeJSON` strictMapping parameter
* Better handling of Java primitive arrays
* Improved object serialization in various contexts

## 🏗️ Architectural Changes

### Dependency Updates

* Updated Jackson-jr to latest patch version
* Bumped semver4j from 5.8.0 to 6.0.0
* Updated Apache Commons FileUpload to jakarta-servlet5
* Updated Commons Text from 1.13.1 to 1.14.0
* Updated Commons IO from 2.19.0 to 2.20.0

### Code Organization

* Refactored `customTagsDirectory` to `customComponentsDirectory` (with backward compatibility)
* Renamed `thisTag` scope to `thisComponent` scope for consistency
* Removed external JavaParser dependencies unless explicitly checked

### Base64 & Encoding

* Improved base64 string handling with padding tolerance
* Better UTF-8 encoding support for multipart form data
* Enhanced encoding handling across the platform

## 📚 New Documentation

We've significantly expanded our documentation with comprehensive new guides:

* [**MiniServer Guide**](https://boxlang.ortusbooks.com/getting-started/running-boxlang/miniserver) - Complete miniserver setup and configuration
* [**Components Guide**](https://boxlang.ortusbooks.com/boxlang-framework/components) - In-depth component development
* [**Transactions Guide**](https://boxlang.ortusbooks.com/boxlang-framework/transactions) - Database transaction management
* [**XML Processing Guide**](https://boxlang.ortusbooks.com/boxlang-language/syntax/xml) - Working with XML in BoxLang
* [**Property Files Guide**](https://boxlang.ortusbooks.com/boxlang-framework/file-handling/property-files) - Configuration and property management
* [**Testing Guide**](https://boxlang.ortusbooks.com/extra-credit/testing) - Testing best practices and frameworks

### Comprehensive Asynchronous Programming Documentation

* [**Asynchronous Programming Overview**](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming)
* [**Executors**](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/executors) - Thread pool management
* [**BoxFutures**](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/box-futures) - Future-based programming
* [**Async Pipelines**](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/async-pipelines) - Chaining async operations
* [**Parallel Computations**](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/parallel-computations) - CPU-intensive parallel processing
* [**Scheduled Tasks**](https://boxlang.ortusbooks.com/boxlang-framework/asynchronous-programming/scheduled-tasks) - Background task scheduling

## 🎯 CFML Compatibility Improvements

This release includes numerous CFML compatibility enhancements:

* Better `parseDateTime` compatibility with ACF
* Improved handling of date masks and formatting
* Enhanced numeric operations and casting
* Better list BIF consistency across multi-character delimiters

***

## Release Notes

### Improvement

[BL-1517](https://ortussolutions.atlassian.net/browse/BL-1517) Update the feature audit tool with the correct modules

[BL-1518](https://ortussolutions.atlassian.net/browse/BL-1518) Remove all JavaParser dependencies externally unless you check if it exists

[BL-1565](https://ortussolutions.atlassian.net/browse/BL-1565) improve error message on expression interpreter

[BL-1566](https://ortussolutions.atlassian.net/browse/BL-1566) Handle attempt.orThrow() better

[BL-1571](https://ortussolutions.atlassian.net/browse/BL-1571) Support some more natural date parsing masks which aren't case sensitive

[BL-1577](https://ortussolutions.atlassian.net/browse/BL-1577) lookup of custom componets and classes refactoring for performance

[BL-1579](https://ortussolutions.atlassian.net/browse/BL-1579) String performance and optimizations improvements for toScript() bif

[BL-1581](https://ortussolutions.atlassian.net/browse/BL-1581) Bump org.semver4j:semver4j from 5.8.0 to 6.0.0

[BL-1601](https://ortussolutions.atlassian.net/browse/BL-1601) avoid calling unputStream.available() due to FusionReactor bug

[BL-1604](https://ortussolutions.atlassian.net/browse/BL-1604) make module classes visible to context classloader

[BL-1618](https://ortussolutions.atlassian.net/browse/BL-1618) Update jackson-jr to latest patch

[BL-1625](https://ortussolutions.atlassian.net/browse/BL-1625) skip type coercion for === operator

[BL-1636](https://ortussolutions.atlassian.net/browse/BL-1636) default non-existent request bodies to an empty string

[BL-1642](https://ortussolutions.atlassian.net/browse/BL-1642) Ignore extra padding on base64 encoded strings

[BL-1647](https://ortussolutions.atlassian.net/browse/BL-1647) remove JSON serialization limit

[BL-1648](https://ortussolutions.atlassian.net/browse/BL-1648) Improve JSON serialization of throwable

[BL-1651](https://ortussolutions.atlassian.net/browse/BL-1651) org.apache.commons:commons-fileupload2-jakarta-servlet5

[BL-1653](https://ortussolutions.atlassian.net/browse/BL-1653) Re-organize and add validation to loaded miniserver config options

[BL-1656](https://ortussolutions.atlassian.net/browse/BL-1656) Bump org.apache.commons:commons-text from 1.13.1 to 1.14.0 (#288)

[BL-1657](https://ortussolutions.atlassian.net/browse/BL-1657) Bump commons-io:commons-io from 2.19.0 to 2.20.0

[BL-1659](https://ortussolutions.atlassian.net/browse/BL-1659) Re-instate parsing errors for unclosed brackets

### Bug

[BL-1214](https://ortussolutions.atlassian.net/browse/BL-1214) Documentation of Image module

[BL-1367](https://ortussolutions.atlassian.net/browse/BL-1367) BX Compiler Issues

[BL-1415](https://ortussolutions.atlassian.net/browse/BL-1415) Cast error on BoxFuture.all()

[BL-1496](https://ortussolutions.atlassian.net/browse/BL-1496) Can't cast a Java Array to a modifiable Array.

[BL-1539](https://ortussolutions.atlassian.net/browse/BL-1539) DateFormat vs TimeFormat vs DateTimeFormat BIF Separations

[BL-1548](https://ortussolutions.atlassian.net/browse/BL-1548) Private static struct function not found

[BL-1555](https://ortussolutions.atlassian.net/browse/BL-1555) round does not accept second argument for number of places, despite being documented

[BL-1562](https://ortussolutions.atlassian.net/browse/BL-1562) Issue with clone when using zonedatetimes

[BL-1564](https://ortussolutions.atlassian.net/browse/BL-1564) dump template for Java class not handling static field

[BL-1567](https://ortussolutions.atlassian.net/browse/BL-1567) java boxpiler not always compiling array literal

[BL-1568](https://ortussolutions.atlassian.net/browse/BL-1568) JDBC - Unable to execute query in nested transaction unless outer transaction has a query that executes first

[BL-1569](https://ortussolutions.atlassian.net/browse/BL-1569) JDBC - Failed to set savepoint... is too long

[BL-1570](https://ortussolutions.atlassian.net/browse/BL-1570) date mask when parsing string dates

[BL-1573](https://ortussolutions.atlassian.net/browse/BL-1573) Fix for this scope access from function in custom tag

[BL-1575](https://ortussolutions.atlassian.net/browse/BL-1575) stack overflow in session shutdown cache interceptor

[BL-1578](https://ortussolutions.atlassian.net/browse/BL-1578) ToscriptTest not accounting for the timezone of the tests

[BL-1580](https://ortussolutions.atlassian.net/browse/BL-1580) ParseDateTimeTest using non timezone tests and would be unpredictable on certain conditions

[BL-1582](https://ortussolutions.atlassian.net/browse/BL-1582) bx:component is missing attributecollection argument

[BL-1584](https://ortussolutions.atlassian.net/browse/BL-1584) DateTimeCaster does not handle request timezones Zones correctly

[BL-1585](https://ortussolutions.atlassian.net/browse/BL-1585) CFML Compat with partial years

[BL-1587](https://ortussolutions.atlassian.net/browse/BL-1587) Different return type when calling \`getTime()\` on \`java.util.GregorianCalendar\`

[BL-1588](https://ortussolutions.atlassian.net/browse/BL-1588) StructSort numeric not sorting on values

[BL-1589](https://ortussolutions.atlassian.net/browse/BL-1589) Regular expression back reference is being ignored

[BL-1592](https://ortussolutions.atlassian.net/browse/BL-1592) ASM not compiling self-closing custom components the same as Java boxpiler

[BL-1593](https://ortussolutions.atlassian.net/browse/BL-1593) outer loop loses query context after inner loop

[BL-1594](https://ortussolutions.atlassian.net/browse/BL-1594) Issue with JSON serialization of dates in a BL class

[BL-1596](https://ortussolutions.atlassian.net/browse/BL-1596) session cookie - samesite handling

[BL-1597](https://ortussolutions.atlassian.net/browse/BL-1597) ArrayResize does not accept long

[BL-1598](https://ortussolutions.atlassian.net/browse/BL-1598) WriteDump Error on Null Array Values

[BL-1606](https://ortussolutions.atlassian.net/browse/BL-1606) Compat: DeSerializeJSON strictMapping ignored

[BL-1607](https://ortussolutions.atlassian.net/browse/BL-1607) SessionRotate and SessionInvalidate null out JSessionId

[BL-1610](https://ortussolutions.atlassian.net/browse/BL-1610) ACF parseDateTime compat

[BL-1611](https://ortussolutions.atlassian.net/browse/BL-1611) Casting ortus.boxlang.runtime.types.DateTime to java.util.Date

[BL-1612](https://ortussolutions.atlassian.net/browse/BL-1612) outer for loop loses query context with inner for loop

[BL-1613](https://ortussolutions.atlassian.net/browse/BL-1613) queryDeleteColumn deletes the column but not the data from the query object

[BL-1615](https://ortussolutions.atlassian.net/browse/BL-1615) fileRead should handle relative files

[BL-1616](https://ortussolutions.atlassian.net/browse/BL-1616) now isn't being cast to java.util.Date

[BL-1620](https://ortussolutions.atlassian.net/browse/BL-1620) Grouped looping is not showing expected output when not inner grouping

[BL-1621](https://ortussolutions.atlassian.net/browse/BL-1621) JDBC - Query caching into bx-redis throws 'failed to serialize object'

[BL-1622](https://ortussolutions.atlassian.net/browse/BL-1622) Httpparam formfield is adding a break line on values when multipart is true

[BL-1623](https://ortussolutions.atlassian.net/browse/BL-1623) FileGetMimeType with strict should be based on file content

[BL-1624](https://ortussolutions.atlassian.net/browse/BL-1624) Deserialized Query Columns are Invalid because they no longer contain query reference

[BL-1626](https://ortussolutions.atlassian.net/browse/BL-1626) DateTime does not properly deserialize because formatter is transient

[BL-1627](https://ortussolutions.atlassian.net/browse/BL-1627) val() with negative value returns 0

[BL-1628](https://ortussolutions.atlassian.net/browse/BL-1628) regex replacement backreferences greater than 9 don't wor

[BL-1629](https://ortussolutions.atlassian.net/browse/BL-1629) regex upper/lower case escapes should apply to all replacement text

[BL-1630](https://ortussolutions.atlassian.net/browse/BL-1630) JDBC race conditions present in threaded (or Future-ed) query execution

[BL-1632](https://ortussolutions.atlassian.net/browse/BL-1632) Zip includes target directory as first level parent.

[BL-1633](https://ortussolutions.atlassian.net/browse/BL-1633) queryObject.columnnames not supported

[BL-1634](https://ortussolutions.atlassian.net/browse/BL-1634) cfcontent is causing files to be corrupted

[BL-1635](https://ortussolutions.atlassian.net/browse/BL-1635) java double\[] not handled by writeoutput / SerializeJSON

[BL-1639](https://ortussolutions.atlassian.net/browse/BL-1639) \`max\` and \`min\` member functions missing

[BL-1641](https://ortussolutions.atlassian.net/browse/BL-1641) list BIFs have inconsistent support for multiCharacterDelimiter

[BL-1652](https://ortussolutions.atlassian.net/browse/BL-1652) PlacehbolderReplacer was not using the String Caster when dealing with map bindings.

[BL-1658](https://ortussolutions.atlassian.net/browse/BL-1658) Servlet: Missing UTF-8 encoding for form fields with multipart/form-data

### New Feature

[BL-842](https://ortussolutions.atlassian.net/browse/BL-842) .env support for the BoxLang miniserver

[BL-1464](https://ortussolutions.atlassian.net/browse/BL-1464) implement nested grouped output/looping

[BL-1515](https://ortussolutions.atlassian.net/browse/BL-1515) Add zipparam support for ZIP functionality

[BL-1525](https://ortussolutions.atlassian.net/browse/BL-1525) BoxLang mappings need to have an extra definition: external which defaults to false

[BL-1595](https://ortussolutions.atlassian.net/browse/BL-1595) runAsync is the alias, the main method is asyncRun() so we can use the \`asyncX\` namespace

[BL-1609](https://ortussolutions.atlassian.net/browse/BL-1609) asyncAll, asyncAllApply, asyncAny bifs and constructs for parallel programming

[BL-1654](https://ortussolutions.atlassian.net/browse/BL-1654) Add simple health checks for miniserver, especially for container based loading

[BL-1655](https://ortussolutions.atlassian.net/browse/BL-1655) Basic hidden file protection in MiniServer

### Task

[BL-1576](https://ortussolutions.atlassian.net/browse/BL-1576) Refactor customTagsDirectory to customComponentsDirectory and add shim to support it

[BL-1637](https://ortussolutions.atlassian.net/browse/BL-1637) Rename thisTag scope to thisComponent scope for consistency and transpile the old scope


# 1.3.0

June 23, 2025

We're excited to announce BoxLang v1.3.0, a significant update that brings new features, performance improvements, and important bug fixes to enhance your development experience.

## 🎉 New Features

### Compression & Serialization Enhancements

**Enhanced Zip Component (BL-1508)**

Added `compressionLevel` parameter to zip component and utilities for better control over compression settings. The default `compressionLevel` is `6` which is a balanced approach.

**Example:**

```javascript
// Zip Component
bx:zip compressionLevel="9"

// Compress BIF
compress( compressionLevel: 9 )
```

### **Pretty JSON Serialization (BL-1542)**

Added `pretty` argument to `jsonSerialize()` function to enable formatted JSON output for improved readability and storage.

**Example:**

```javascript
data = {
    name: "John Doe",
    age: 30,
    address: {
        street: "123 Main St",
        city: "Anytown",
        country: "USA"
    },
    hobbies: ["reading", "cycling", "photography"]
};

// Standard compact JSON (default behavior)
compactJson = jsonSerialize( data );
// Output: {"name":"John Doe","age":30,"address":{"street":"123 Main St","city":"Anytown","country":"USA"},"hobbies":["reading","cycling","photography"]}

// Pretty formatted JSON (new feature)
prettyJson = jsonSerialize( data, pretty=true );
/* Output:
{
  "name" : "John Doe",
  "age" : 30,
  "address" : {
    "street" : "123 Main St",
    "city" : "Anytown",
    "country" : "USA"
  },
  "hobbies" : [ "reading", "cycling", "photography" ]
}
*/

// Useful for debugging and configuration files
writeFile( "config.json", jsonSerialize( appConfig, pretty=true ) );
```

### Array, List, Query & Struct Operations

**New xNone() Functions (BL-1533)**

Introduced `xNone()` functions for BIF operations across arrays, lists, queries, and structs to check if no elements match specified criteria.

**Array Example:**

```javascript
numbers = [ 1, 3, 5, 7, 9 ]

// Using BIF with lambda notation
hasNoEvens = arrayNone( numbers, num -> num % 2 == 0 )
// Returns: true (no even numbers found)

hasNoneGreaterThan10 = arrayNone( numbers, num -> num > 10 )
// Returns: true (no numbers greater than 10)

// Using member method with lambda notation
hasNoEvens = numbers.none( num -> num % 2 == 0 )
// Returns: true (no even numbers found)

hasNoneGreaterThan10 = numbers.none( num -> num > 10 )
// Returns: true (no numbers greater than 10)

// More complex example with multiple conditions
products = [
    { name: "laptop", price: 999, category: "electronics" },
    { name: "book", price: 15, category: "education" },
    { name: "phone", price: 599, category: "electronics" }
]

// BIF: Check if none are free products
hasNoFreeProducts = arrayNone( products, product -> product.price == 0 )

// Member method: Check if none are luxury items (over $2000)
hasNoLuxuryItems = products.none( product -> product.price > 2000 )
```

**List Example:**

```javascript
fruits = "apple,banana,cherry,date"

// Using BIF with lambda notation
hasNoZFruits = listNone( fruits, fruit -> left( fruit, 1 ) == "z" )
// Returns: true (no fruits start with 'z')

// Using member method with lambda notation
hasNoZFruits = fruits.none( fruit -> left( fruit, 1 ) == "z" )
// Returns: true (no fruits start with 'z')
```

**Query Example:**

```javascript
users = queryNew( "name,age,status", "varchar,integer,varchar", [
    [ "Alice", 25, "active" ],
    [ "Bob", 30, "active" ],
    [ "Charlie", 35, "inactive" ]
] )

// Using BIF: Check if none of the users are minors
hasNoMinors = queryNone( users, row -> row.age < 18 )
// Returns: true (no users under 18)

// Using member method: Check if none have empty names
hasNoEmptyNames = users.none( row -> len( trim( row.name ) ) == 0 )
// Returns: true (all users have names)
```

**Struct Example:**

```javascript
config = {
    database: "mysql",
    port: 3306,
    ssl: true,
    timeout: 30
}

// Using BIF: Check if none of the values are null or empty
hasNoEmptyValues = structNone( config, ( key, value ) -> isNull( value ) || value == "" )
// Returns: true (all config values are populated)

// Using member method: Check if none of the keys contain "password"
hasNoPasswordKeys = config.none( ( key, value ) -> findNoCase( "password", key ) > 0 )
// Returns: true (no password-related keys found)
```

### Build & Security Improvements

**Binary Checksums (BL-1512)**

Added checksums to all binary creations in the build process for enhanced security and integrity verification.

**Usage in CI/CD:**

```yaml
# Example GitHub Actions step to verify BoxLang binary integrity
- name: Verify BoxLang Binary
  run: |
    wget https://downloads.boxlang.io/boxlang-1.3.0.jar.sha256
    sha256sum -c boxlang-1.3.0.jar.sha256
    echo "Binary integrity verified ✓"
```

## 🚀 Improvements

### Documentation & Developer Experience

* **Enhanced Documentation** (BL-1471): Added comprehensive examples to documentation for Built-in Functions (BIFs) and Components
* **Command Line Help** (BL-1521, BL-1522): Added `--help` and `-h` flags to Mini Server, Feature Audit, CFTranspiler, Scheduler, BoxRunner, and other command-line tools

### Performance & Architecture

* **HTTP Response Compression** (BL-1511): Added support for compressed HTTP responses to improve performance
* **Query Concurrency** (BL-1534): Significant improvements to query concurrency handling, resolving inconsistencies when adding data to queries in parallel threads
* **Lazy Cache Expiration** (BL-1528): Implemented lazy expiration for caching to optimize memory usage and performance
* **Scope Security** (BL-1494): Prevented scopes from being overridden through scope hunting for better security

### Error Handling & Type Safety

* **Array Type Matching** (BL-1516): Updated `arrayFind()` to handle mismatched types gracefully without throwing exceptions
* **Compile-time Annotations** (BL-1537): Refactored `@NonNull` and `@Nullable` annotations to use compile-time checkers instead of runtime dependencies

### Dependency Updates

* **Semver4j Update** (BL-1526): Bumped org.semver4j:semver4j from 5.7.0 to 5.7.1
* **Jackson Update** (BL-1536): Bumped com.fasterxml.jackson.jr:jackson-jr-stree from 2.19.0 to 2.19.1
* **Runtime Dependencies** (BL-1519): Optimized to ensure only runtime dependencies are stored in the `lib` folder

### CFML Compatibility

* **CFQuery Parameter Mapping** (BL-1544): Created transpiler rule for cfquery params, mapping `cfsqltype` to `sqltype` for better CFML compatibility

## 🐛 Bug Fixes

#### Image Processing

* **Image Scaling** (BL-1216): Fixed issue where `scaleToFit` was creating black images
* **Member Function Resize** (BL-1217): Resolved image resize functionality when used as member function

#### Database & Transactions

* **JDBC Transaction Handling** (BL-1472): Fixed transaction defaults to use app-default datasource instead of ignoring named datasources in queries
* **DATETIME Parameter Aliasing** (BL-1527): Resolved issue where DATETIME was not being properly aliased by query parameters in prepared statements

#### Mathematical Operations

* **Timestamp Math Operations** (BL-1501): Updated math operations encountering timestamps to cast as fractional days for CFML compatibility
* **fix() Function Behavior** (BL-1513): Aligned `fix()` function behavior with Lucee's implementation

#### Parallel Processing

* **Tiered Execution** (BL-1503): Updated parallel computations (`xSome`, `xEvery`, `xMap`, `xFilter`, `xEach`) to use improved tiered execution approach
* **Loop Group Handling** (BL-1504): Fixed issue where looping groups would break instead of continuing properly

#### File Handling & HTTP

* **File Upload Errors** (BL-1507): Resolved HTTP errors occurring during file uploads
* **Multi-part Form Fields** (BL-1523): Fixed issue where all multi-part form fields were being unnecessarily written to disk

#### Exception Handling

* **CFCatch Support** (BL-1524): Improved CFCatch support when catch variable is defined in bx-compat-cfml

#### Caching System

* **Cache Concurrency** (BL-1529): Resolved several concurrency issues affecting cache entries, creation timeouts, and last access timeouts
* **Cache Entry Collisions** (BL-1530): Fixed cache entry equals evaluation that was incorrectly evaluating hash codes and causing collisions

#### Class & Component System

* **Remote Method Templates** (BL-1531): Improved base template setting for remote methods in super classes
* **Class Metadata** (BL-1541): Fixed `type` property in class metadata to properly reference "class" instead of "component"
* **XML Object Duplication** (BL-1547): Resolved issue with duplicate function being broken when using XML objects

#### Path Handling

* **Servlet Path Resolution** (BL-1532): Enhanced handling of `../` patterns in servlet paths for better security and reliability

***

### 📋 Summary

BoxLang v1.3.0 delivers significant improvements across performance, reliability, and developer experience. With enhanced concurrency handling, improved caching mechanisms, and comprehensive bug fixes, this release strengthens BoxLang's foundation while maintaining excellent CFML compatibility.

**Key Highlights:**

* New compression and serialization capabilities
* Major query concurrency improvements
* Enhanced caching with lazy expiration
* Comprehensive documentation updates
* Critical bug fixes for image processing, database operations, and parallel processing

We recommend all users upgrade to v1.3.0 to benefit from these improvements and fixes.

For technical support or questions about this release, please visit our documentation or contact our support team.

***

## Raw Release Notes

### New Feature

[BL-1508](https://ortussolutions.atlassian.net/browse/BL-1508) Add \`compressionLevel\` to the zip component and utilities

[BL-1512](https://ortussolutions.atlassian.net/browse/BL-1512) Add checksums to all binary creations in the build process

[BL-1533](https://ortussolutions.atlassian.net/browse/BL-1533) xNone() for bif operations: array, list, query, struct

[BL-1542](https://ortussolutions.atlassian.net/browse/BL-1542) Added \`pretty\` argument to jsonSerialize() to allow for pretty serialization

### Improvement

[BL-1471](https://ortussolutions.atlassian.net/browse/BL-1471) Add Examples to docs for BIFs and Components

[BL-1494](https://ortussolutions.atlassian.net/browse/BL-1494) Don't allow scopes to be "overridden" with scope hunting

[BL-1511](https://ortussolutions.atlassian.net/browse/BL-1511) Add Support for Compressed HTTP responses

[BL-1516](https://ortussolutions.atlassian.net/browse/BL-1516) arrayFind shouldn't throw on mismatched types

[BL-1519](https://ortussolutions.atlassian.net/browse/BL-1519) Small update to make sure only runtime dependencies are stored in the \`lib\` folder using our maven pom in the Boxlang home.

[BL-1521](https://ortussolutions.atlassian.net/browse/BL-1521) Add --help -h to Mini Server

[BL-1522](https://ortussolutions.atlassian.net/browse/BL-1522) Add --help -h to Feature Audit, CFTranspiler, Scheduler, BoxRunner and more

[BL-1526](https://ortussolutions.atlassian.net/browse/BL-1526) Bumps org.semver4j:semver4j from 5.7.0 to 5.7.1.

[BL-1528](https://ortussolutions.atlassian.net/browse/BL-1528) Add lazy expiration for caching

[BL-1534](https://ortussolutions.atlassian.net/browse/BL-1534) Query Concurrency Improvements : There are some inconsistencies and issues when dealing with adding data to queries in parallel threads

[BL-1536](https://ortussolutions.atlassian.net/browse/BL-1536) Bumps com.fasterxml.jackson.jr:jackson-jr-stree from 2.19.0 to 2.19.1.

[BL-1537](https://ortussolutions.atlassian.net/browse/BL-1537) Refactor @NonNull and @Nullable to use compile time checkers instead of runtime dependencies

[BL-1544](https://ortussolutions.atlassian.net/browse/BL-1544) Create a transpiler rule for cfquery params: \`cfsqltype\` to \`sqltype\`

### Bugs

[BL-1216](https://ortussolutions.atlassian.net/browse/BL-1216) Image scaleToFit creating black images

[BL-1217](https://ortussolutions.atlassian.net/browse/BL-1217) Image resize not working as member func.

[BL-1472](https://ortussolutions.atlassian.net/browse/BL-1472) JDBC - Transaction defaults to app-default datasource, and ignores the datasource named in the first query

[BL-1501](https://ortussolutions.atlassian.net/browse/BL-1501) Compat: Math Operations Which Encounter Timestamps Should Cast as Fractional Days

[BL-1503](https://ortussolutions.atlassian.net/browse/BL-1503) Update parallel computations to use a tiered execution approach; xSome, xEvery, xMap, xFilter, xEach

[BL-1504](https://ortussolutions.atlassian.net/browse/BL-1504) looping groups breaks when it should continue

[BL-1507](https://ortussolutions.atlassian.net/browse/BL-1507) HTTP Errors When Uploading File

[BL-1513](https://ortussolutions.atlassian.net/browse/BL-1513) fix() behaviour is not equal to Lucee's behaviour

[BL-1523](https://ortussolutions.atlassian.net/browse/BL-1523) All multi-part form fields are being written to disk

[BL-1524](https://ortussolutions.atlassian.net/browse/BL-1524) CFCatch support when catch variable defined in bx-compat-cfml

[BL-1527](https://ortussolutions.atlassian.net/browse/BL-1527) DATETIME is not being aliased by query parameters in prepared statements

[BL-1529](https://ortussolutions.atlassian.net/browse/BL-1529) Several concurrency issues on cache entries created and last access timeouts

[BL-1530](https://ortussolutions.atlassian.net/browse/BL-1530) cache entry equals evaluating the hash codes incorrectly and causing collisions

[BL-1531](https://ortussolutions.atlassian.net/browse/BL-1531) Set base template for remote methods in super class

[BL-1532](https://ortussolutions.atlassian.net/browse/BL-1532) Better handle ../ in servlet paths

[BL-1541](https://ortussolutions.atlassian.net/browse/BL-1541) The \`type\` property in class metadata still references "component" instead of being "class"

[BL-1547](https://ortussolutions.atlassian.net/browse/BL-1547) duplicate function broken when using xml objects


# 1.2.0

May 29, 2025

## BoxLang 1.2: Performance-Driven Innovation

We're excited to announce the release of **BoxLang 1.2**, a significant milestone that demonstrates our commitment to delivering both cutting-edge features and exceptional performance. This release represents how much innovation the entire BoxLang team can accomplish in just **2 weeks** of focused development, bringing you powerful new capabilities while dramatically improving the runtime efficiency that makes BoxLang a compelling choice for modern applications.

### What Makes 1.2 Special

BoxLang 1.2 isn't just another incremental update—it's a performance powerhouse packed with developer-friendly enhancements. We've implemented **over 30 targeted optimizations** across the runtime, from string operations and file handling to function invocations and memory management. These improvements mean your applications will run faster and more efficiently, often without requiring any changes to your existing code.

### Headline Features

<div align="left"><figure><img src="/files/PDF77EJayysZbLSIImUl" alt=""><figcaption><p>Maven Home Integration</p></figcaption></figure></div>

**Enhanced Java Integration**: The new Maven `pom.xml` support for BoxLang Home opens up seamless integration with the entire Java ecosystem, making it easier than ever to leverage existing Java libraries in your BoxLang applications. You can now add any Java dependencies in your BoxLang Home's `pom.xml` run `mvn install` and your runtime will be seeded with all the Java Libraries your application needs!

```bash
mvn install
```

**Advanced Logging Control**: Take complete control of your application's logging with new encoder options (`text` or `json`) and flexible appender choices between file and console output. Your logs, your way. You can also now chose between a `file` or `console` appender in all of your configuration files.

**Developer Experience**: From nested grouped output support to the new `BoxModuleReload()` function for testing workflows, we've focused on making your development process smoother and more productive.

### Performance at the Core

This release includes extensive performance optimizations that touch nearly every aspect of the runtime:

* **Optimized Hot Code Paths**: Critical operations like string comparisons, numeric casting, and function invocations have been streamlined
* **Smarter Caching**: From configuration lookups to file path resolution, we've added intelligent caching where it matters most
* **Reduced Overhead**: Eliminated unnecessary operations in frequently-called code, including regex optimizations and stream-to-loop conversions
* **Memory Efficiency**: Improved struct operations, hash encoding, and object creation patterns

### Compatibility & Stability

We've strengthened BoxLang's compatibility with existing CFML codebases through numerous fixes and enhancements, including better date/time handling, improved query parameter support, and enhanced file operations. Whether you're migrating existing applications or building new ones, BoxLang 1.2 provides a more stable and predictable foundation.

### Ready to Upgrade

BoxLang 1.2 includes **50+ improvements and bug fixes** that enhance stability, performance, and developer experience. From small quality-of-life improvements to significant runtime optimizations, this release delivers value across the board.

The combination of new features, performance enhancements, and rock-solid stability makes BoxLang 1.2 our most compelling release yet. Whether you're building high-performance web applications, integrating with Java ecosystems, or modernizing legacy CFML code, BoxLang 1.2 provides the tools and performance you need to succeed.

**Download BoxLang 1.2 today and experience the difference that thoughtful optimization and feature development can make.**

## New Features

* [BL-1453](https://ortussolutions.atlassian.net/browse/BL-1453) Maven pom.xml for the BoxLang Home so you can integrate with any Java library
* [BL-1464](https://ortussolutions.atlassian.net/browse/BL-1464) implement nested grouped output/looping
* [BL-1474](https://ortussolutions.atlassian.net/browse/BL-1474) Logger appenders in the boxlang.json can now chose their own encoder: text or json
* [BL-1476](https://ortussolutions.atlassian.net/browse/BL-1476) Added ability for loggers to chose between file and console appenders
* [BL-1482](https://ortussolutions.atlassian.net/browse/BL-1482) new event ON\_FUNCTION\_EXCEPTION
* [BL-1485](https://ortussolutions.atlassian.net/browse/BL-1485) Update the error template to include a section where the user can contact us if the error is not good enough or we can improve it.

## Improvements

* [BL-1393](https://ortussolutions.atlassian.net/browse/BL-1393) Add executionTime to result object of bx:http
* [BL-1397](https://ortussolutions.atlassian.net/browse/BL-1397) FileCopy( source, targetDirectory ) when using a target directory doesn't work on BoxLang but works on Lucee
* [BL-1400](https://ortussolutions.atlassian.net/browse/BL-1400) File bifs have too many casts, do one cast for performance
* [BL-1404](https://ortussolutions.atlassian.net/browse/BL-1404) Add a unique request id metadata header when making requests in http so it can track easily
* [BL-1405](https://ortussolutions.atlassian.net/browse/BL-1405) Add missing contexts to data interceptors
* [BL-1406](https://ortussolutions.atlassian.net/browse/BL-1406) Add a \`request\` struct to the bxhttp result object
* [BL-1417](https://ortussolutions.atlassian.net/browse/BL-1417) Add Allow Arguments to FileCopy and FileMove for granular extension security overrides
* [BL-1419](https://ortussolutions.atlassian.net/browse/BL-1419) server.java.defaultLocale, server.java.availableLocales
* [BL-1420](https://ortussolutions.atlassian.net/browse/BL-1420) New bif: BoxModuleReload( \[name] ) to easily reload modules for testing purposes
* [BL-1421](https://ortussolutions.atlassian.net/browse/BL-1421) optimize when LocalizationUtil string casts
* [BL-1422](https://ortussolutions.atlassian.net/browse/BL-1422) optimize Struct.putAll()
* [BL-1423](https://ortussolutions.atlassian.net/browse/BL-1423) optimize when basescope creates lockname to on demand
* [BL-1424](https://ortussolutions.atlassian.net/browse/BL-1424) optimize string compare check for unicode
* [BL-1425](https://ortussolutions.atlassian.net/browse/BL-1425) optimize case insensitive instanceof check
* [BL-1426](https://ortussolutions.atlassian.net/browse/BL-1426) optimize isNumeric locale parsing and casting
* [BL-1427](https://ortussolutions.atlassian.net/browse/BL-1427) optimize file detection/reading from disk unless needed
* [BL-1428](https://ortussolutions.atlassian.net/browse/BL-1428) optimize getConfig() by caching at request context
* [BL-1429](https://ortussolutions.atlassian.net/browse/BL-1429) Improve performance of string lowercasing and key creation
* [BL-1433](https://ortussolutions.atlassian.net/browse/BL-1433) Only include source lines in exceptions when in debug mode
* [BL-1434](https://ortussolutions.atlassian.net/browse/BL-1434) Optimize hash base 64 encoding
* [BL-1435](https://ortussolutions.atlassian.net/browse/BL-1435) Optimize regex cache key generation
* [BL-1436](https://ortussolutions.atlassian.net/browse/BL-1436) Move/Copy BIFs should all default to an overwrite value of true
* [BL-1437](https://ortussolutions.atlassian.net/browse/BL-1437) Update the way loggers are setup and retrieved to avoid string and key lookups and accelerate the runtime
* [BL-1438](https://ortussolutions.atlassian.net/browse/BL-1438) bif invocation interceptors missing the actual bif
* [BL-1439](https://ortussolutions.atlassian.net/browse/BL-1439) BIF Interceptors hot code, only create events if they are states for it
* [BL-1443](https://ortussolutions.atlassian.net/browse/BL-1443) order keys in struct dump alphabetically
* [BL-1445](https://ortussolutions.atlassian.net/browse/BL-1445) DateTime and Duration Math Should Represent Fractional Days in Math Operations
* [BL-1446](https://ortussolutions.atlassian.net/browse/BL-1446) Compat: DateAdd Should accept numeric fractional days as date argument
* [BL-1450](https://ortussolutions.atlassian.net/browse/BL-1450) Exclude javaparser and other debug libraries from final jar
* [BL-1454](https://ortussolutions.atlassian.net/browse/BL-1454) Optimize FQN class by removing regex usage in hot code
* [BL-1455](https://ortussolutions.atlassian.net/browse/BL-1455) optimize generated setter by caching resolved file path
* [BL-1456](https://ortussolutions.atlassian.net/browse/BL-1456) Optimize dynamic object by converting stream to loop in hot code
* [BL-1457](https://ortussolutions.atlassian.net/browse/BL-1457) optimize output check by caching recursive lookups
* [BL-1458](https://ortussolutions.atlassian.net/browse/BL-1458) optimize isEmpty code paths
* [BL-1459](https://ortussolutions.atlassian.net/browse/BL-1459) optimize getting function enclosing class by caching
* [BL-1460](https://ortussolutions.atlassian.net/browse/BL-1460) optimize number caster true/false string checks
* [BL-1461](https://ortussolutions.atlassian.net/browse/BL-1461) optimize BoxStructSerializer class by avoiding struct.entrySet()
* [BL-1462](https://ortussolutions.atlassian.net/browse/BL-1462) optimize string compare by removing unnecessary string to lower case
* [BL-1473](https://ortussolutions.atlassian.net/browse/BL-1473) Update to use StatusPrinter2 from deprecated StatusPrinter using LogBack
* [BL-1481](https://ortussolutions.atlassian.net/browse/BL-1481) Speed improvements for function invocation on hot code
* [BL-1486](https://ortussolutions.atlassian.net/browse/BL-1486) Better handle low level parsing errors like java.util.EmptyStackException
* [BL-1489](https://ortussolutions.atlassian.net/browse/BL-1489) Improve error messages when registering interceptors using the registration bifs when sending things other than interceptors
* [BL-1490](https://ortussolutions.atlassian.net/browse/BL-1490) Add function name to interceptor data for ease of use
* [BL-1493](https://ortussolutions.atlassian.net/browse/BL-1493) Accelerate dynamic object method handle executions

## Bugs

* [BL-1356](https://ortussolutions.atlassian.net/browse/BL-1356) postBIFInvocation event
* [BL-1357](https://ortussolutions.atlassian.net/browse/BL-1357) Simple preFunctionInvoke interceptor throws errors due to recursing into itself
* [BL-1385](https://ortussolutions.atlassian.net/browse/BL-1385) Module that defines an interceptor has to specify "too much" for the class path
* [BL-1386](https://ortussolutions.atlassian.net/browse/BL-1386) ModuleService reload and reloadAll() methods to provide ability for module reloading on development
* [BL-1394](https://ortussolutions.atlassian.net/browse/BL-1394) forgot to populate the \`populateServerSystemScope\` from the override boxlang.json
* [BL-1396](https://ortussolutions.atlassian.net/browse/BL-1396) isValid Boolean Returning Incorrect Result on Struct
* [BL-1398](https://ortussolutions.atlassian.net/browse/BL-1398) Move default disallowed file extensions to web support and keep CLI open
* [BL-1399](https://ortussolutions.atlassian.net/browse/BL-1399) Compat: CreateTime Should Support 0 hour argument
* [BL-1401](https://ortussolutions.atlassian.net/browse/BL-1401) FileSystemUtil not absoluting paths when checking existence
* [BL-1402](https://ortussolutions.atlassian.net/browse/BL-1402) \`replaceNoCase\` does not handle \`null\` strings like Lucee or ACF
* [BL-1403](https://ortussolutions.atlassian.net/browse/BL-1403) http not using the user agent if passed by the user
* [BL-1409](https://ortussolutions.atlassian.net/browse/BL-1409) Compat: add \`server.coldfusion.supportedLocales\`
* [BL-1412](https://ortussolutions.atlassian.net/browse/BL-1412) Add Application.bx/cfc support for overriding allowed and disallowed extensions
* [BL-1414](https://ortussolutions.atlassian.net/browse/BL-1414) this.logger is null in when getting an attempt() from a box future
* [BL-1416](https://ortussolutions.atlassian.net/browse/BL-1416) Compat: Support ACF/Lucee \`blockedExtForFileUpload\` Application Setting
* [BL-1418](https://ortussolutions.atlassian.net/browse/BL-1418) parameterized QoQ with maxLength errors
* [BL-1431](https://ortussolutions.atlassian.net/browse/BL-1431) function dump template doesn't work in compat
* [BL-1432](https://ortussolutions.atlassian.net/browse/BL-1432) CF transpiler not turning off accessors for child classes
* [BL-1441](https://ortussolutions.atlassian.net/browse/BL-1441) getPageContext().getRequest() has no getScheme()
* [BL-1442](https://ortussolutions.atlassian.net/browse/BL-1442) empty file fields in forms throw error on submit
* [BL-1444](https://ortussolutions.atlassian.net/browse/BL-1444) Boxlang does not pickup custom tags that are in the same folder as the file that calls them
* [BL-1447](https://ortussolutions.atlassian.net/browse/BL-1447) Compat: DateDiff should support fractional days as date argument
* [BL-1449](https://ortussolutions.atlassian.net/browse/BL-1449) when doing a boxlang {action} command it should break and execute
* [BL-1451](https://ortussolutions.atlassian.net/browse/BL-1451) Custom tag search is case-sensitive
* [BL-1452](https://ortussolutions.atlassian.net/browse/BL-1452) inline annotation errors when literal value is a negative number
* [BL-1463](https://ortussolutions.atlassian.net/browse/BL-1463) parser errors on class annotation called abstract
* [BL-1466](https://ortussolutions.atlassian.net/browse/BL-1466) self-closing defaultcase tag not parsing
* [BL-1467](https://ortussolutions.atlassian.net/browse/BL-1467) if you use options or params that include file extensions, the runner explodes
* [BL-1468](https://ortussolutions.atlassian.net/browse/BL-1468) cfqueryparam tag not allowed outside of cfquery tag
* [BL-1469](https://ortussolutions.atlassian.net/browse/BL-1469) Building query fails when part of the query is build inside function that outputs directly
* [BL-1470](https://ortussolutions.atlassian.net/browse/BL-1470) query escaping of single quotes only escapes the first one, not all
* [BL-1475](https://ortussolutions.atlassian.net/browse/BL-1475) \`this.sessionStorage\` assignment with Application-defined cache throws error.
* [BL-1477](https://ortussolutions.atlassian.net/browse/BL-1477) Errors within application startup leave app in unusable state
* [BL-1479](https://ortussolutions.atlassian.net/browse/BL-1479) Compat: Error thrown in QueryCompat interception when null param is encountered
* [BL-1483](https://ortussolutions.atlassian.net/browse/BL-1483) calling java method with invoke() and no args fails
* [BL-1484](https://ortussolutions.atlassian.net/browse/BL-1484) filewrite operations on existing files were not truncating it and leaving content behind.
* [BL-1488](https://ortussolutions.atlassian.net/browse/BL-1488) isSimpleValue doesn't work with Keys


# 1.1.0

May 12, 2025

## New Features

* [BL-1365](https://ortussolutions.atlassian.net/browse/BL-1365) Add parse() helper methods directly to runtime, which returns parse result
* [BL-1388](https://ortussolutions.atlassian.net/browse/BL-1388) new security configuration item: populateServerSystemScope that can allow or not the population of the server.system scope or not

## Improvements

* [BL-1333](https://ortussolutions.atlassian.net/browse/BL-1333) Create links to BoxLang modules
* [BL-1351](https://ortussolutions.atlassian.net/browse/BL-1351) match getHTTPTimeString() and default time to now
* [BL-1358](https://ortussolutions.atlassian.net/browse/BL-1358) Work harder to return partial AST on invalid parse
* [BL-1363](https://ortussolutions.atlassian.net/browse/BL-1363) Error executing dump template \[/dump/html/BoxClass.bxm]
* [BL-1375](https://ortussolutions.atlassian.net/browse/BL-1375) Compat - Move Legacy Date Format Interception to Module-Specific Interception Point
* [BL-1381](https://ortussolutions.atlassian.net/browse/BL-1381) allow box class to be looped over as collection
* [BL-1382](https://ortussolutions.atlassian.net/browse/BL-1382) Rework event bus interceptors to accelerate during executions
* [BL-1383](https://ortussolutions.atlassian.net/browse/BL-1383) Compat - Allow handling of decimals where timespan is used
* [BL-1387](https://ortussolutions.atlassian.net/browse/BL-1387) Allow Numeric ApplicationTimeout assignment to to be decimal

## Bugs

* [BL-1354](https://ortussolutions.atlassian.net/browse/BL-1354) BoxLang date time not accepted by JDBC as a date object
* [BL-1359](https://ortussolutions.atlassian.net/browse/BL-1359) contracting path doesn't work if casing of mapping doesn't match casing of abs path
* [BL-1366](https://ortussolutions.atlassian.net/browse/BL-1366) sessionInvalidate() "Cannot invoke String.length() because "s" is null"
* [BL-1370](https://ortussolutions.atlassian.net/browse/BL-1370) Some methods not found in java interop
* [BL-1372](https://ortussolutions.atlassian.net/browse/BL-1372) string functions accepting null
* [BL-1374](https://ortussolutions.atlassian.net/browse/BL-1374) onMissingTemplate event mystyped as missingtemplate
* [BL-1377](https://ortussolutions.atlassian.net/browse/BL-1377) fileExists() not working with relative paths
* [BL-1378](https://ortussolutions.atlassian.net/browse/BL-1378) optional capture groups throw NPE in reReplace()
* [BL-1379](https://ortussolutions.atlassian.net/browse/BL-1379) array length incorrect for xml nodes
* [BL-1384](https://ortussolutions.atlassian.net/browse/BL-1384) Numeric Session Timeout Values Should Be Duration of Days not Seconds


# 1.0.1

May 1, 2025

## Bugs

[BL-1353](https://ortussolutions.atlassian.net/browse/BL-1353) BoxRunner fails on some input args


# 1.0.0

May 1, 2025

This was our first stable release of the BoxLang language. It grouped the entire betas and release candidate features and fixes. This specific version included the following release notes from issues that changed between release candidate 3.

## New Features

[BL-1319](https://ortussolutions.atlassian.net/browse/BL-1319) Create the config \`runtimes\` struct so any runtime can store their settings there by convention

[BL-1327](https://ortussolutions.atlassian.net/browse/BL-1327) Add simple rewrites to miniserver

## Improvements

[BL-1199](https://ortussolutions.atlassian.net/browse/BL-1199) Add a \`version\` key to the boxlang.json to track the current version of the runtime.

[BL-1275](https://ortussolutions.atlassian.net/browse/BL-1275) expandPath(".") when running boxlang as a shell script does not point to the current working directory

[BL-1278](https://ortussolutions.atlassian.net/browse/BL-1278) Possible minor bug in Mail

[BL-1285](https://ortussolutions.atlassian.net/browse/BL-1285) Can we improve URL to PDF support?

[BL-1286](https://ortussolutions.atlassian.net/browse/BL-1286) Pre-compiled matchers for exception stack builds for performance

[BL-1287](https://ortussolutions.atlassian.net/browse/BL-1287) LineNumber alias on exception traces for multiple Box tools in the open

[BL-1293](https://ortussolutions.atlassian.net/browse/BL-1293) Upate isObject, isArray and IsStruct to have more edge cases and consistencies across engines

[BL-1296](https://ortussolutions.atlassian.net/browse/BL-1296) looping over XMLNode as collection only loops over child nodes

[BL-1310](https://ortussolutions.atlassian.net/browse/BL-1310) BoxLang file with no extension should try to determine if it's an executable class

[BL-1311](https://ortussolutions.atlassian.net/browse/BL-1311) Expand relative this.mappings in application class

[BL-1323](https://ortussolutions.atlassian.net/browse/BL-1323) change extract() BIF so filter argument works the same as directoryList()

[BL-1324](https://ortussolutions.atlassian.net/browse/BL-1324) make missing template error use relative path, not absolute path

[BL-1334](https://ortussolutions.atlassian.net/browse/BL-1334) Support samesite and expires in servlet

[BL-1336](https://ortussolutions.atlassian.net/browse/BL-1336) change compress() BIF so filter argument works the same as directoryList()

[BL-1337](https://ortussolutions.atlassian.net/browse/BL-1337) generatePBKDFKey() compat issues

[BL-1339](https://ortussolutions.atlassian.net/browse/BL-1339) SCryptVerify() doesn't support hashes generated in Adobe ColdFusion

## Bugs

[BL-1098](https://ortussolutions.atlassian.net/browse/BL-1098) Compat: FileMove in ACF/Lucee automatically overwrites the destination file

[BL-1123](https://ortussolutions.atlassian.net/browse/BL-1123) Use of compat-transpiled name in scoped variable throws error

[BL-1131](https://ortussolutions.atlassian.net/browse/BL-1131) Compat: Error parsing date with zero month

[BL-1218](https://ortussolutions.atlassian.net/browse/BL-1218) Cookie with Quoted Value Intermittently comes back with URL-Escaped quotes

[BL-1266](https://ortussolutions.atlassian.net/browse/BL-1266) Rethrown Exception Inside Transaction Being Wrapped In Application Exception

[BL-1267](https://ortussolutions.atlassian.net/browse/BL-1267) Elvis using nullValue on right hand side throws error

[BL-1271](https://ortussolutions.atlassian.net/browse/BL-1271) Using BIFS in CLI schedulers throws an error that request context is empty

[BL-1272](https://ortussolutions.atlassian.net/browse/BL-1272) Dumping class with top argument results in Struct template error.

[BL-1273](https://ortussolutions.atlassian.net/browse/BL-1273) Class which implements IReferenceable alone throws errors when Attempting Serialize to JSON

[BL-1274](https://ortussolutions.atlassian.net/browse/BL-1274) Error with parseDateTime on ISO with fully numeric offset

[BL-1279](https://ortussolutions.atlassian.net/browse/BL-1279) relative include with ../../ can result in illegal class name

[BL-1280](https://ortussolutions.atlassian.net/browse/BL-1280) caches set operations relies on timeouts being Objects, do stricter validation and conversion to avoid can't cast string to longs

[BL-1281](https://ortussolutions.atlassian.net/browse/BL-1281) hash CFML compatability

[BL-1282](https://ortussolutions.atlassian.net/browse/BL-1282) cfml compat: returnformat is case sensitive for remote methods

[BL-1283](https://ortussolutions.atlassian.net/browse/BL-1283) cfml compat - cfinclude with non cfml files

[BL-1284](https://ortussolutions.atlassian.net/browse/BL-1284) CFML compat. Undefined query values are strings in ACF / Lucee

[BL-1289](https://ortussolutions.atlassian.net/browse/BL-1289) CacheLocator cache is too aggressive on same name but different location classes

[BL-1290](https://ortussolutions.atlassian.net/browse/BL-1290) dump templates for Function, Map and XML missing expand null checks

[BL-1291](https://ortussolutions.atlassian.net/browse/BL-1291) XML structkeyExists returns false when objects are there but isNull returns false

[BL-1292](https://ortussolutions.atlassian.net/browse/BL-1292) jsonSerialize() or deserialize with cookie setting is adding extra "

[BL-1294](https://ortussolutions.atlassian.net/browse/BL-1294) static initializer above properties is giving a syntax error

[BL-1297](https://ortussolutions.atlassian.net/browse/BL-1297) Update session storage key removal interceptor so it can detect if the clear is a session or not, as it could be in a cache that holds much more data

[BL-1299](https://ortussolutions.atlassian.net/browse/BL-1299) Serializing queries to JSON compatibility

[BL-1301](https://ortussolutions.atlassian.net/browse/BL-1301) DynamicObject.hasMethodNoCase() is returning false for methods that clearly exist and are invokable

[BL-1302](https://ortussolutions.atlassian.net/browse/BL-1302) JDBC - Missing support for no connection limit

[BL-1303](https://ortussolutions.atlassian.net/browse/BL-1303) Static access is not a valid construct for array access

[BL-1304](https://ortussolutions.atlassian.net/browse/BL-1304) featureAudit incorrectly reports the valueList() BIF as missing

[BL-1306](https://ortussolutions.atlassian.net/browse/BL-1306) cfhtmlhead does not work properly

[BL-1307](https://ortussolutions.atlassian.net/browse/BL-1307) Implement CFCookie Expires

[BL-1308](https://ortussolutions.atlassian.net/browse/BL-1308) cfcookie samesite attribute not honored

[BL-1309](https://ortussolutions.atlassian.net/browse/BL-1309) CFML Compat - cfcookie encodevalue attribute not honored

[BL-1312](https://ortussolutions.atlassian.net/browse/BL-1312) overriding \`/\` mapping in this.mappings not working

[BL-1313](https://ortussolutions.atlassian.net/browse/BL-1313) dump/abort doesn't always default response content type in servlet

[BL-1317](https://ortussolutions.atlassian.net/browse/BL-1317) ASM Boxpiler is not generating the correct bytecode when dealing with abstract classes

[BL-1321](https://ortussolutions.atlassian.net/browse/BL-1321) bx:location throws error in console

[BL-1325](https://ortussolutions.atlassian.net/browse/BL-1325) BX-PDF - Issue with PDF support and document section, specifically Acrobat Reader

[BL-1326](https://ortussolutions.atlassian.net/browse/BL-1326) documentsection name not properly setting bookmark name

[BL-1328](https://ortussolutions.atlassian.net/browse/BL-1328) Relax default permissions of bx:document

[BL-1331](https://ortussolutions.atlassian.net/browse/BL-1331) Compat: dateTimeFormat "h" mask

[BL-1340](https://ortussolutions.atlassian.net/browse/BL-1340) SCryptVerify() function aliases

[BL-1341](https://ortussolutions.atlassian.net/browse/BL-1341) hash() returns lower case from CFM pages

[BL-1343](https://ortussolutions.atlassian.net/browse/BL-1343) Schedulers defined in Application.bx do not have access to application scope values defined in onApplicationStart

[BL-1345](https://ortussolutions.atlassian.net/browse/BL-1345) cliread was closing the system.in instead of sharing across the cli

[BL-1346](https://ortussolutions.atlassian.net/browse/BL-1346) bitwise complement doesn't work with variable

[BL-1348](https://ortussolutions.atlassian.net/browse/BL-1348) Expansion of "/tmp" resolves to relative path.

[BL-1349](https://ortussolutions.atlassian.net/browse/BL-1349) elvis doesn't work in lambda

## Tasks

[BL-179](https://ortussolutions.atlassian.net/browse/BL-179) TimeBox Certification

[BL-1136](https://ortussolutions.atlassian.net/browse/BL-1136) Compat: Document DateAdd Behavior with Decimal Number Difference from ACF/Lucee


# RC Stage

This is the collection of Release Candidates we released since our first version.


# 1.0.0-RC.1

February 18, 2025

🚀 **BoxLang Release Candidate 1 is Here!** 🚀

After nearly a year of relentless iteration, rigorous testing, blood, sweat, lots of praying, tears, and over **1,000 resolved tickets**, we proudly announce the first **Release Candidate (RC1) of BoxLang**! With **27 beta versions** behind us, we are now on the final stretch toward the **official 1.0 release**.

This milestone ensures that **most of our libraries are fully compatible and certified for BoxLang**, making it production-ready. **RC1 delivers significant bug fixes, performance optimizations, and stability enhancements**, enabling teams to deploy and fine-tune their applications in real-world environments confidently. **We strongly encourage the community to start running production workloads now**—your feedback will be instrumental in refining BoxLang ahead of the final release.

### Licenses Available TODAY!

{% embed url="<https://www.boxlang.io/plans>" %}
[www.boxlang.io/plans](http://www.boxlang.io/plans)
{% endembed %}

Additionally, we are thrilled to open up **support license subscriptions (**[**https://www.boxlang.io/plans**](https://www.boxlang.io/plans)**)** for BoxLang **+/++**, offering enterprise-grade support, priority fixes, and exclusive benefits. As an introductory offer, all licenses are available at **50% off** for February. In March, with the release of **RC2**, discounts will adjust to **25% off**—scaling down progressively until our **official launch at Into The Box 2025** ([**www.intothebox.org**](http://www.intothebox.org)).

**Let me also remind you that our Visionary Licenses will cease to be offered by the end of this month. Visionary licenses are unique for 10 years and 5 years of support. If you are interested in securing a visionary license, please email us at** [**sales@ortussolutions.com**](mailto:sales@ortussolutions.com)**.**

### Production Tips

We encourage you to pre-compile your applications using our BoxLang compiler for incredibly safe and high-performance deployments since no parsing is involved. Combined with our new [trusted cache settings](/getting-started/configuration/directives), your applications will fly and be highly performant.

## Release Notes

### New Features

[BL-1065](https://ortussolutions.atlassian.net/browse/BL-1065) Make sure execution exceptions are propagated to an \`exception.log\` for all runtimes

[BL-1070](https://ortussolutions.atlassian.net/browse/BL-1070) Create `getHTTPTimeString` bif in the CFML Compat Module

[BL-1071](https://ortussolutions.atlassian.net/browse/BL-1071) Missing bif: `createTime()`

### Improvement

[BL-1020](https://ortussolutions.atlassian.net/browse/BL-1020) returns 500 status code when hitting the default error page

[BL-1027](https://ortussolutions.atlassian.net/browse/BL-1027) Allow annotation values of unquoted strings

[BL-1028](https://ortussolutions.atlassian.net/browse/BL-1028) allow RHS of castas operator to omit quotes

[BL-1029](https://ortussolutions.atlassian.net/browse/BL-1029) default output to true in Application classes

[BL-1034](https://ortussolutions.atlassian.net/browse/BL-1034) Disable external DTD validation

[BL-1050](https://ortussolutions.atlassian.net/browse/BL-1050) Migrate usage of LoggerFactory.getLogger to the internal BoxLang logger classes in the core

[BL-1052](https://ortussolutions.atlassian.net/browse/BL-1052) BIF and Component abstract objects now have a logger that maps to a \`runtime\` logger for ease of use

[BL-1054](https://ortussolutions.atlassian.net/browse/BL-1054) Favor native java methods on a struct if there is a key of that name, but it's not a function

[BL-1062](https://ortussolutions.atlassian.net/browse/BL-1062) Improve boxpiler selection by using the interface not classes or direct implementations

### Bugs

[BL-816](https://ortussolutions.atlassian.net/browse/BL-816) Abort should not fire the \`onRequestEnd\` method ( or it should fail quietly )

[BL-1008](https://ortussolutions.atlassian.net/browse/BL-1008) Struct.put Usage Throws Error

[BL-1023](https://ortussolutions.atlassian.net/browse/BL-1023) BX-ORM: When First Request to Application is a CFC, the application scope is undefined when starting ORMApp attempts to instantiate

[BL-1025](https://ortussolutions.atlassian.net/browse/BL-1025) numeric key access of struct failing for BigDecimal keys

[BL-1030](https://ortussolutions.atlassian.net/browse/BL-1030) directoryList does not sort by name

[BL-1031](https://ortussolutions.atlassian.net/browse/BL-1031) Too many pattern letters: m

[BL-1032](https://ortussolutions.atlassian.net/browse/BL-1032) Trivial: Typo in error message

[BL-1033](https://ortussolutions.atlassian.net/browse/BL-1033) thread attribute scope needs to be headlessly accessible

[BL-1035](https://ortussolutions.atlassian.net/browse/BL-1035) structget() incorrectly returning true with cfml-compat installed

[BL-1037](https://ortussolutions.atlassian.net/browse/BL-1037) String caster doesn't work on char\[] and produces incorrect results for Character\[]

[BL-1038](https://ortussolutions.atlassian.net/browse/BL-1038) class dump template doesn't work with compat module

[BL-1039](https://ortussolutions.atlassian.net/browse/BL-1039) Access and mutation of native Java unboxed arrays doesn't work

[BL-1040](https://ortussolutions.atlassian.net/browse/BL-1040) Query objects do not allow complex data when adding columns via \`queryAddColumn()\` with no data type.

[BL-1041](https://ortussolutions.atlassian.net/browse/BL-1041) Can't use EMail as a returntype from EMail object

[BL-1043](https://ortussolutions.atlassian.net/browse/BL-1043) shebang detection not working and skipping execution to the REPL

[BL-1044](https://ortussolutions.atlassian.net/browse/BL-1044) isValid uuid returns false

[BL-1045](https://ortussolutions.atlassian.net/browse/BL-1045) Error executing dump template

[BL-1047](https://ortussolutions.atlassian.net/browse/BL-1047) default string representation of exception object

[BL-1048](https://ortussolutions.atlassian.net/browse/BL-1048) Dereferencing property on Java class not calling getter

[BL-1049](https://ortussolutions.atlassian.net/browse/BL-1049) Jakarta servlet removed response.setStatus( int, String ) from API

[BL-1051](https://ortussolutions.atlassian.net/browse/BL-1051) Typo in exception string for parseDateTime

[BL-1053](https://ortussolutions.atlassian.net/browse/BL-1053) getDirectoryFromPath breaks when passed a null value

[BL-1055](https://ortussolutions.atlassian.net/browse/BL-1055) Durations created by \`createTimespan\` can't be casted to strings

[BL-1058](https://ortussolutions.atlassian.net/browse/BL-1058) \`this\` scope can no longer be mutated

[BL-1059](https://ortussolutions.atlassian.net/browse/BL-1059) final access modifier with explicit static scope on assignment not working

[BL-1060](https://ortussolutions.atlassian.net/browse/BL-1060) static method access on non-imported identifer not working

[BL-1061](https://ortussolutions.atlassian.net/browse/BL-1061) boxpiler was defaulting to javaboxpiler internally, remove it, it should be null and seeded later

[BL-1066](https://ortussolutions.atlassian.net/browse/BL-1066) isSimpleValue returns true on Exception in Compat Mode

[BL-1068](https://ortussolutions.atlassian.net/browse/BL-1068) QueryParam: SQL Server Unknown Column Type \`datetime\`

[BL-1069](https://ortussolutions.atlassian.net/browse/BL-1069) ParseDateTime failure with \`hh:nn a\` mask - e.g. \`03:00 PM\`

[BL-1075](https://ortussolutions.atlassian.net/browse/BL-1075) onRequestEnd() not firing for on class requests


# 1.0.0-RC.2

March 4th, 2025

🚀 **BoxLang Release Candidate 2 is Here!** 🚀

We’re entering the final stretch of our pre-releases, and we couldn’t be more excited to introduce RC2! 🚀 This release marks a major leap in performance and compatibility, the result of over six months of intensive development. Beyond enhanced stability and seamless integration, RC2 delivers game-changing performance optimizations that push the boundaries of efficiency. Get ready for our fastest, most refined release yet!

### Feel the Need for Speed :rocket::fire:

RC2 is blazing fast! 🚀 Our latest release delivers unmatched performance in both parsing and runtime execution, outperforming Adobe ColdFusion 2021 and 2023 by 25-37% in many scenarios. These results are backed by rigorous certification testing across TestBox, ColdBox, and over 35 modules, ensuring real-world speed and reliability. You can now check all of our repos and see the performance for yourself.

### Adobe ColdFusion / Lucee Drop-In Replacement

This means you can **seamlessly** migrate your Adobe ColdFusion or Lucee applications to BoxLang with no code changes—and they’ll run faster, smoother, and across multiple runtimes! 🚀

But that’s not all—our subscription-based licensing can save you over 70% compared to Adobe ColdFusion, with no restrictions on cores or limitations on SaaS and multi-tenant applications. **No restrictions. Just pure freedom to scale.** 🔥

### Ray Camden BoxLang Evangelist

<figure><img src="/files/xqhGMw76YrPEIBj4q2aV" alt=""><figcaption></figcaption></figure>

We’re excited to welcome Raymond Camden, a renowned leader in the CFML community, as a BoxLang Advocate! 🎉

Raymond, currently collaborating with us as a contractor, brings deep expertise in web development and a passion for making complex technologies more accessible. His insights and experience make him the perfect advocate to explore and champion BoxLang—our modern, CFML-compatible programming language. 🚀

[Read More](https://www.ortussolutions.com/blog/meet-raymond-camden-boxlang-advocate)

### Premium Modules Have Landed

We have now our first premium module for BoxLang +/++ subscribers: BX-REDIS. Our `bx-redis`module is now available for you to use if you have a subscription. You can also try it out free of charge by installing it today:

```
# OS
install-bx-module bx-redis

# CommandBox
box install bx-redis
```

Giving you great capabilities for caching, distributed sessions, pub-subscribe and much more. You can find out about this initial release here (<https://forgebox.io/view/bx-redis>)

{% embed url="<https://forgebox.io/view/bx-redis>" %}

### Licenses Available!

{% embed url="<https://www.boxlang.io/plans>" %}
[www.boxlang.io/plans](http://www.boxlang.io/plans)
{% endembed %}

Remember that our **support license subscriptions (**[**https://www.boxlang.io/plans**](https://www.boxlang.io/plans)**)** for BoxLang **+/++ are available now. O**ffering enterprise-grade support, priority fixes, premium modules, and exclusive benefits. As an introductory offer, all licenses are available at 2&#x35;**% off** for March.

### Production Tips

We encourage you to pre-compile your applications using our BoxLang compiler for incredibly safe and high-performance deployments since no parsing is involved. Combined with our new [trusted cache settings](/getting-started/configuration/directives), your applications will fly and be highly performant.

***

## Release Notes

### Improvements

[BL-1021](https://ortussolutions.atlassian.net/browse/BL-1021) Explore speed improvements to parser

[BL-1084](https://ortussolutions.atlassian.net/browse/BL-1084) Support CF syntax of space inside elvis operator

[BL-1089](https://ortussolutions.atlassian.net/browse/BL-1089) allow getSystemSetting() to default to a non-simple value

[BL-1090](https://ortussolutions.atlassian.net/browse/BL-1090) bx-compat - Client Scope Listener should not start up or look for cache if client management is disabled

[BL-1093](https://ortussolutions.atlassian.net/browse/BL-1093) Make miniserver bind to 0.0.0.0 by default

[BL-1143](https://ortussolutions.atlassian.net/browse/BL-1143) Change order of app shutdown

[BL-1147](https://ortussolutions.atlassian.net/browse/BL-1147) boxAnnounce() and boxAnnounceAsync() get a poolname so you can announce globally or to the request pools

[BL-1148](https://ortussolutions.atlassian.net/browse/BL-1148) missing bif: BoxRegisterInterceptionPoints() to register interception points for global or request pools

[BL-1149](https://ortussolutions.atlassian.net/browse/BL-1149) In BL files, only default output=false in tag-based UDFs

[BL-1153](https://ortussolutions.atlassian.net/browse/BL-1153) Setup the hikari defaults for connection pooling to modern standards

[BL-1155](https://ortussolutions.atlassian.net/browse/BL-1155) Update query object to return array of structs into a consolidated method: toArrayOfStructs()

[BL-1158](https://ortussolutions.atlassian.net/browse/BL-1158) Attempts needed remail of left over isSimplevalue evaluations

[BL-1159](https://ortussolutions.atlassian.net/browse/BL-1159) Rename bx:module to be bx:component

### Bugs

[BL-1018](https://ortussolutions.atlassian.net/browse/BL-1018) esapiEncode does not allow an zero length input string

[BL-1024](https://ortussolutions.atlassian.net/browse/BL-1024) BX-ORM: Datasource with name \[defaultDatasource] not found in the application or globally

[BL-1026](https://ortussolutions.atlassian.net/browse/BL-1026) \`try\`/\`finally\` doesn't always run \`finally\`

[BL-1036](https://ortussolutions.atlassian.net/browse/BL-1036) ASM regression - break exiting out of more than just the loop

[BL-1056](https://ortussolutions.atlassian.net/browse/BL-1056) LinkedHashMap right-hand assignments are always null.

[BL-1063](https://ortussolutions.atlassian.net/browse/BL-1063) ReEscape result doesn't match ACF

[BL-1064](https://ortussolutions.atlassian.net/browse/BL-1064) Classes getting cleared in debug mode

[BL-1077](https://ortussolutions.atlassian.net/browse/BL-1077) Simplify CLI to install modules

[BL-1078](https://ortussolutions.atlassian.net/browse/BL-1078) cgi items not being found until you access them

[BL-1079](https://ortussolutions.atlassian.net/browse/BL-1079) encrypt not working with AES and UU

[BL-1080](https://ortussolutions.atlassian.net/browse/BL-1080) Encrypt Fails when salt is below 16 bytes in length

[BL-1082](https://ortussolutions.atlassian.net/browse/BL-1082) bx-mail not reading mail configurations

[BL-1085](https://ortussolutions.atlassian.net/browse/BL-1085) HTTP - Ensure all exceptions are caught and handled

[BL-1086](https://ortussolutions.atlassian.net/browse/BL-1086) Mail Module not Loading root-level boxlang.json Mail Server Settings

[BL-1087](https://ortussolutions.atlassian.net/browse/BL-1087) StructUtil.deepMerge wraps arrays in nested array if left hand side contains the same array

[BL-1088](https://ortussolutions.atlassian.net/browse/BL-1088) Can't set cookies using a struct

[BL-1092](https://ortussolutions.atlassian.net/browse/BL-1092) Mail: Classloader issues when sending MultiPart email in Servlet Context

[BL-1094](https://ortussolutions.atlassian.net/browse/BL-1094) \`.duplicate()\` Member Method Not Available on Struct,DateTime objects, Queries and Arrays

[BL-1095](https://ortussolutions.atlassian.net/browse/BL-1095) DirectoryCopy Does not Allow Closure for Filter Arg

[BL-1096](https://ortussolutions.atlassian.net/browse/BL-1096) QueryNew Does not accept array of Columns as only first arg

[BL-1097](https://ortussolutions.atlassian.net/browse/BL-1097) Compat: CachePut does not allow numeric decimal number of days for timeSpan or idleTime

[BL-1099](https://ortussolutions.atlassian.net/browse/BL-1099) String Hash Result Different Between Text and Byte Array

[BL-1100](https://ortussolutions.atlassian.net/browse/BL-1100) Compat: HTTP result.statusCode Does not Include the status text.

[BL-1101](https://ortussolutions.atlassian.net/browse/BL-1101) HTTP Request for Binary Object casts fileContent to String

[BL-1102](https://ortussolutions.atlassian.net/browse/BL-1102) Integer caster not always consistent

[BL-1103](https://ortussolutions.atlassian.net/browse/BL-1103) HTTP Component getAsBinary attribute does not support \`true\` and \`false\` boolean arguments

[BL-1104](https://ortussolutions.atlassian.net/browse/BL-1104) HTTP Component throws an error when \`Host\` is explicitly passed as a header

[BL-1105](https://ortussolutions.atlassian.net/browse/BL-1105) HTTP Component Throws Error when sending Binary Content

[BL-1106](https://ortussolutions.atlassian.net/browse/BL-1106) HTTP getAsBinary should be treated as an explicit request for binary content unless \`never\` is passed.

[BL-1109](https://ortussolutions.atlassian.net/browse/BL-1109) HTTP: Query Params Are Being Double Encoded Even When Encode=false

[BL-1110](https://ortussolutions.atlassian.net/browse/BL-1110) Within a cfmodule, the variables scope is not available within a .each() loop if the .each loop is called in a function within the module.

[BL-1111](https://ortussolutions.atlassian.net/browse/BL-1111) When a form is submitted but none of the inputs have names and the form scope is dumped, an error is thrown

[BL-1112](https://ortussolutions.atlassian.net/browse/BL-1112) Type coercion of an numeric argument passed to java constructor is not being done

[BL-1113](https://ortussolutions.atlassian.net/browse/BL-1113) Function NOT not found

[BL-1114](https://ortussolutions.atlassian.net/browse/BL-1114) bx-orm - 'Datasource with name \[defaultDatasource] not found ...'

[BL-1115](https://ortussolutions.atlassian.net/browse/BL-1115) bx-orm - Unable to call generated methods from within class

[BL-1116](https://ortussolutions.atlassian.net/browse/BL-1116) bx-orm - Generated method hasX() is missing support for value comparison

[BL-1117](https://ortussolutions.atlassian.net/browse/BL-1117) bx-orm - AddX() method fails on many-to-many relationship properties with "bag is null" error

[BL-1118](https://ortussolutions.atlassian.net/browse/BL-1118) HMAC Method not supporting binary keys

[BL-1120](https://ortussolutions.atlassian.net/browse/BL-1120) HTTP \`file\` attribute not implemented

[BL-1121](https://ortussolutions.atlassian.net/browse/BL-1121) Math Operations Leave trailing zeros after operation when result is whole number

[BL-1122](https://ortussolutions.atlassian.net/browse/BL-1122) HTTP ACF and Lucee Treat all Unknown or malformed \`Content-Type\` Headers as a string response

[BL-1124](https://ortussolutions.atlassian.net/browse/BL-1124) Compat: Default throw error not a type of \`Application\`

[BL-1125](https://ortussolutions.atlassian.net/browse/BL-1125) Error compiling - 'in' was unexpected expecting one of ...

[BL-1126](https://ortussolutions.atlassian.net/browse/BL-1126) this.customtagpaths not respected - Could not find custom tag

[BL-1128](https://ortussolutions.atlassian.net/browse/BL-1128) Common Text Cert/Key extensions are being read as Binary data

[BL-1129](https://ortussolutions.atlassian.net/browse/BL-1129) for loop using var and in throws parsing error

[BL-1130](https://ortussolutions.atlassian.net/browse/BL-1130) Custom Error Thrown Is Being Wrapped in "Error invoking Supplier" exception

[BL-1132](https://ortussolutions.atlassian.net/browse/BL-1132) FileRead should only ever return strings

[BL-1133](https://ortussolutions.atlassian.net/browse/BL-1133) DateTime Comparison equals/isEqual discrepancies

[BL-1134](https://ortussolutions.atlassian.net/browse/BL-1134) DateCompare Issues when Time units are specified

[BL-1135](https://ortussolutions.atlassian.net/browse/BL-1135) DateAdd No Longer Allowing Decimals

[BL-1137](https://ortussolutions.atlassian.net/browse/BL-1137) Allow customTagPaths to be relative

[BL-1138](https://ortussolutions.atlassian.net/browse/BL-1138) EqualsEquals operator should use \`equalTo\` method of DateTime in compat mode

[BL-1139](https://ortussolutions.atlassian.net/browse/BL-1139) Cannot pass BoxLang Functions into ScheduledTask

[BL-1140](https://ortussolutions.atlassian.net/browse/BL-1140) Nested config values for modules do not get replaced by environment variables

[BL-1142](https://ortussolutions.atlassian.net/browse/BL-1142) thread safety issue in feature audit

[BL-1144](https://ortussolutions.atlassian.net/browse/BL-1144) Custom setter that assigns to this scope causes stack overflow with implicit accessor invocation

[BL-1146](https://ortussolutions.atlassian.net/browse/BL-1146) return type of function not always parsing

[BL-1150](https://ortussolutions.atlassian.net/browse/BL-1150) Invalid stack height when using a ternary in a context that doesn't expect a return value

[BL-1151](https://ortussolutions.atlassian.net/browse/BL-1151) semicolon not allowed after pre annotation

[BL-1152](https://ortussolutions.atlassian.net/browse/BL-1152) \`variablename\` is not supported as a type

[BL-1156](https://ortussolutions.atlassian.net/browse/BL-1156) Compat: Date Comparisons in Compat should only be precise to the second

[BL-1157](https://ortussolutions.atlassian.net/browse/BL-1157) len() BIF needs to treat byte arrays as an array, not a string

[BL-1160](https://ortussolutions.atlassian.net/browse/BL-1160) return not expr parsing error

### Tasks

[BL-814](https://ortussolutions.atlassian.net/browse/BL-814) CBSecurity Certification

[BL-1076](https://ortussolutions.atlassian.net/browse/BL-1076) isWDDX BIF missing from wddx module


# 1.0.0-RC.3

April 3, 2025

We are so excited to release RC.3 for BoxLang. We have squashed almost 100 tickets for this release. Making it the most performant and solid release to date. We do not have any more release candidates scheduled, so this might be the last before our final release on May 1st. So please, please test your applications and report any issues.

Below, you can find some of the significant accomplishments of this release and the full release notes.

## Performance

We have tested the runtime against all our major libraries, ColdBox, TestBox, and ContentBox, and included our major ColdBox modules. BoxLang now officially runs all of our test suites faster than Adobe 2021, 2023, and 2025, with a give-or-take with the Lucee CFML engine.

## BXORM

We have now released our `bx-orm` module, which gives you full integration with JPA/Hibernate into your BoxLang applications. The documentation site is coming soon at [bxorm.ortusbooks.com](https://commandbox.ortusbooks.com/5.6.0/)

```
install-bx-module bx-orm
```

## Virtual Threads

We have finalized our core executors in BoxLang and fully integrated Java Virtual threads so you can use them in your applications. The core executors in BoxLang now are:

```json
"executors": {
	// Use this for IO bound tasks, does not support scheduling
	// This is also the default executor for parallel operations
	// This is also the default when requestion an executor service via executorGet()
	"io-tasks": {
		"type": "virtual"
	},
	// Use this for CPU bound tasks, supports scheduling
	"cpu-tasks": {
		"type": "scheduled",
		"threads": 10
	},
	// Used for all scheduled tasks in the runtime
	"scheduled-tasks": {
		"type": "scheduled",
		"threads": 10
	}
},
```

As you can see, we have 3 executors pre-defined for the runtime:

* `io-tasks`- A virtual thread executor for high I/O intensive tasks
* `cpu-tasks`- A scheduled executor with 10 base threads for your CPU-intensive tasks
* `scheduled-tasks`- A dedicated executor with 10 base threads for scheduling

{% hint style="success" %}
You can learn more about virtual threads here: <https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html>
{% endhint %}

This now allows us to create Java-based virtual threads using BoxLang constructs `threadNew()`BIF or the `thread`component:

```java
threadNew( 
  runnable: () => {},
  virtual: true
)

bx:thread name="virtualTest" virtual=true{
  // A virtual thread.
}
```

The default for parallel executions in `map(), filter(), each()`have also been updated to leverage virtual threads by default. You can use the `virtual = false`so they can execute in the `cpu-tasks`executor if needed. Enjoy the power of virtual threads.

## Schedulers

We now can do schedulers in pure BoxLang. This allows us to integrate it into every corner of the runtime. All the docs for scheduling are coming. Here is a sneak peek of a pure BoxLang scheduler:

```java
class {

	// Properties
	property name="scheduler";
	property name="runtime";
	property name="logger";
	property name="asyncService";
	property name="cacheService";
	property name="interceptorService";

	/**
	 * The configure method is called by the BoxLang runtime
	 * to allow the scheduler to configure itself.
	 *
	 * This is where you define your tasks and setup global configuration.
	 */
	function configure(){
		// Setup Scheduler Properties
		scheduler.setSchedulerName( "My-Scheduler" )
		scheduler.setTimezone( "UTC" )

		// Define a lambda task
		scheduler.task( "My test Task" )
			.call( () -> {
				println( "I am a lambda task: #now()#" );
			} )
			.every( 2, "second" );
	}

	/**
	 * --------------------------------------------------------------------------
	 * Life - Cycle Callbacks
	 * --------------------------------------------------------------------------
	 */

	/**
	 * Called after the scheduler has registered all schedules
	 */
	void function onStartup(){
		println( "I have started!" & scheduler.getSchedulerName() );
	}

	/**
	 * Called before the scheduler is going to be shutdown
	 */
	void function onShutdown(){
		println( "I have shutdown!" & scheduler.getSchedulerName() );
	}

	/**
	 * Called whenever ANY task fails
	 *
	 * @task      The task that got executed
	 * @exception The exception object
	 */
	function onAnyTaskError( task, exception ){
		println( "Any task [#task.getName()#]  blew up " & exception.getMessage() );
	}

	/**
	 * Called whenever ANY task succeeds
	 *
	 * @task   The task that got executed
	 * @result The result (if any) that the task produced as an Optional
	 */
	function onAnyTaskSuccess( task, result ){
		println( "on any task success [#task.getName()#]"  );
		println( "results for task are: " & result.orElse( "No result" ) );
	}

	/**
	 * Called before ANY task runs
	 *
	 * @task The task about to be executed
	 */
	function beforeAnyTask( task ){
		println( "before any task [#task.getName()#]"  );
	}

	/**
	 * Called after ANY task runs
	 *
	 * @task   The task that got executed
	 * @result The result (if any) that the task produced as an Optional
	 */
	function afterAnyTask( task, result ){
		println( "after any task completed [#task.getName()#]"  );
		println( "results for task are: " & result.orElse( "No result" ) );
	}

}
```

You can find the scheduler API Docs here: <https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-rc.3/ortus/boxlang/runtime/async/tasks/BaseScheduler.html>

### CLI Scheduler

You can now run schedulers from the CLI in any operating system using our new `boxlang schedule`command. Just tell it which scheduler to spin up and forget about CRON.

```
boxlang schedule MyScheduler.bx
```

This will spawn our scheduled tasks, run your scheduler, and wait until you manually block it; if not, it runs forever.

### Runtime Schedulers & Configuration

You can also now declare schedulers in your `boxlang.json`that once the runtime starts, it will startup your schedulers.

```json
"scheduler": {
    // The default scheduler for all scheduled tasks
    // Each scheduler can have a different executor if needed
    "executor": "scheduled-tasks",
    // The cache to leverage for server fixation or distribution
    "cacheName": "default",
    // An array of BoxLang Schedulers to register upon startup
    // Must be an absolute path to the scheduler file
    // You can use the ${user-dir} or ${boxlang-home} variables or any other environment variable
    // Example: "schedulers": [ "/path/to/Scheduler.bx" ]
    "schedulers": [],
    // You can also define tasks manually here
    // Every task is an object defined by a unique name
    // The task object is a struct with the following properties:
    // - `crontime:string` - The cron time to run the task (optional), defaults to empty string
    // - `eventhandler:path` - The absolute path to the task event handler(optional), defaults to empty string
    // - `exclude:any` - Comma-separated list of dates or date range (d1 to d2) on which to not execute the scheduled task
    // - `file:name` - Name of the log file to store output of the task (optional), defaults to `scheduler`
    // - `group:string` - The group name of the task (optional), defaults to empty string
    "tasks": {}
},
```

You can now also choose the default executor and cache to use for server fixations. The `schedulers`is an array of absolute paths to your scheduler bx classes to load.

### Application.bx Schedulers

You can also define schedulers for your particular applications using the `Application.bx`file and the `this.schedulers`setting.

```java
class{

    ...
    
    this.schedulers = [ "path.to.Scheduler" ]

}
```

As you can see, the value is an array of instantiation paths. At application startup, the schedulers will be created, registered, and started for you.

### Scheduler BIFs

You also now have a collection of new BIFs to interact with your schedulers and even submit schedulers programmatically.

* `SchedulerStart( path, [force=false] )` - Create, register and start a new scheduler class.
* `SchedulerShutdown( name, [force=false], [timeout=0] )` - Shutdown a scheduler
* `SchedulerRestart( name, [force=false], [timeout=0] )` - Restart a scheduler
* `SchedulerStats( [name] )` - Get a strut of stats of one or all registered schedulers
* `SchedulerList()` - Get an array of names of all schedulers
* `SchedulerGet( name )` - Get a scheduler instance by name
* `SchedulerGetAll()` - Get all the registered schedulers

## Release Notes

### Improvements

[BL-1262](https://ortussolutions.atlassian.net/browse/BL-1262) Command to schedule Schedulers: `boxlang schedule {path.bx}`

[BL-1265](https://ortussolutions.atlassian.net/browse/BL-1265) Allows for an array of BoxLang schedulers to be loaded on the startup of the runtime

[BL-1269](https://ortussolutions.atlassian.net/browse/BL-1269) `this.schedulers` for Application.bx loading of schedulers

[BL-1268](https://ortussolutions.atlassian.net/browse/BL-1268) Scheduler BIFS for managing schedulers programmatically

[BL-1264](https://ortussolutions.atlassian.net/browse/BL-1264) configuration for \``schedulers`\` in the \``boxlang.json`\`

[BL-1212](https://ortussolutions.atlassian.net/browse/BL-1212) Add parser methods to report on and clear ANTLR cache

[BL-1207](https://ortussolutions.atlassian.net/browse/BL-1207) `this.moduleDependencies` for Modules so they can activate module dependencies

[BL-1170](https://ortussolutions.atlassian.net/browse/BL-1170) New convention `boxlang_modules` wherever you start a BoxLang app it loads those modules first

[BL-1171](https://ortussolutions.atlassian.net/browse/BL-1171) Added Liberica JDK as a supported version of our language

[BL-1172](https://ortussolutions.atlassian.net/browse/BL-1172) Add HttpVersion key to http component

[BL-1176](https://ortussolutions.atlassian.net/browse/BL-1176) add missing "hex" validation to isValid()

[BL-1181](https://ortussolutions.atlassian.net/browse/BL-1181) executorGet() with no params must return the default executor

[BL-1182](https://ortussolutions.atlassian.net/browse/BL-1182) Allow throw; with no expression

[BL-1183](https://ortussolutions.atlassian.net/browse/BL-1183) change listener improvements

[BL-1193](https://ortussolutions.atlassian.net/browse/BL-1193) Support @module-name suffix for class loading

[BL-1195](https://ortussolutions.atlassian.net/browse/BL-1195) missing bifs: BoxUnregisterInterceptor(), BoxUnregisterRequestInterceptor()

[BL-1196](https://ortussolutions.atlassian.net/browse/BL-1196) Added isVirtual, isDaemon, threadGroup, id to the thread metadata

[BL-1197](https://ortussolutions.atlassian.net/browse/BL-1197) Threading Improvements: isThreadAlive(), isThreadInterrupted(), threadInterrupt() bifs

[BL-1206](https://ortussolutions.atlassian.net/browse/BL-1206) modules directories being created unecesarrily if not found

[BL-1208](https://ortussolutions.atlassian.net/browse/BL-1208) enable transparent anchors in java regex

[BL-1209](https://ortussolutions.atlassian.net/browse/BL-1209) Ensure implicit onRequest() method allows output, even if output=false at the application level

[BL-1239](https://ortussolutions.atlassian.net/browse/BL-1239) Add Virtual Attribute to Thread Component

[BL-1240](https://ortussolutions.atlassian.net/browse/BL-1240) Solidify all the executors that ship with the runtime: io-tasks, cpu-tasks, and scheduled-tasks

[BL-1251](https://ortussolutions.atlassian.net/browse/BL-1251) Put debug mode cache clearing behind a config flag: clearClassFilesOnStartup

[BL-1258](https://ortussolutions.atlassian.net/browse/BL-1258) Make Java interop varargs optional

[BL-1259](https://ortussolutions.atlassian.net/browse/BL-1259) only populate form.fieldNames on POST method

[BL-1260](https://ortussolutions.atlassian.net/browse/BL-1260) Add \`modules\` key to server.boxlang struct

[BL-1263](https://ortussolutions.atlassian.net/browse/BL-1263) Add \`BoxCache\` annotation to allow aliasing cache providers

### Bugs

[BL-1023](https://ortussolutions.atlassian.net/browse/BL-1023) When First Request to Application is a CFC, the application scope is undefined

[BL-1083](https://ortussolutions.atlassian.net/browse/BL-1083) cliRead adds a line break

[BL-1107](https://ortussolutions.atlassian.net/browse/BL-1107) Dump of XML Object Does not Include Node Names

[BL-1145](https://ortussolutions.atlassian.net/browse/BL-1145) When calling a remote Bx method, specifying returnformat in the pseudo-constructor does not work

[BL-1154](https://ortussolutions.atlassian.net/browse/BL-1154) ASM BoxPiler is setting up properties after pseudoconstructor runs instead of before

[BL-1162](https://ortussolutions.atlassian.net/browse/BL-1162) BoxLang BIF Proxy losing context of execution

[BL-1163](https://ortussolutions.atlassian.net/browse/BL-1163) Key instance not being coerced to string

[BL-1164](https://ortussolutions.atlassian.net/browse/BL-1164) Super Scope is Lost When UDF in child class from closure in parent class

[BL-1165](https://ortussolutions.atlassian.net/browse/BL-1165) Static method calling static method loses static context

[BL-1166](https://ortussolutions.atlassian.net/browse/BL-1166) application.applicationName is a Key instance, not a string

[BL-1168](https://ortussolutions.atlassian.net/browse/BL-1168) GetContextRoot Returning Slash-Prefixed Root

[BL-1169](https://ortussolutions.atlassian.net/browse/BL-1169) Strings which contain invalid octals are not casting correctly in the NumberCaster

[BL-1174](https://ortussolutions.atlassian.net/browse/BL-1174) access remote not recognised

[BL-1175](https://ortussolutions.atlassian.net/browse/BL-1175) Unable to compile/call box class with java override

[BL-1177](https://ortussolutions.atlassian.net/browse/BL-1177) \`expandPath\` not expanding mappings when used in the Application pseudo constructor

[BL-1178](https://ortussolutions.atlassian.net/browse/BL-1178) Compat: reMatchNoCase should find matches but generates error

[BL-1179](https://ortussolutions.atlassian.net/browse/BL-1179) expandPath() matches partial folders when mapping path doesn't have trailing slash

[BL-1185](https://ortussolutions.atlassian.net/browse/BL-1185) getMetata getClass().getSimpleName()|.getName() on IBoxRunnable returns Struct class names

[BL-1187](https://ortussolutions.atlassian.net/browse/BL-1187) NPE when passing null to first constructor arg of a box class

[BL-1188](https://ortussolutions.atlassian.net/browse/BL-1188) Space missing when cfquery in function

[BL-1189](https://ortussolutions.atlassian.net/browse/BL-1189) bx:zip doesn't implement result

[BL-1191](https://ortussolutions.atlassian.net/browse/BL-1191) Add support for \`this.caches\` in Application.bx|cfc

[BL-1192](https://ortussolutions.atlassian.net/browse/BL-1192) Can't create box class with literal @ symbol in name

[BL-1198](https://ortussolutions.atlassian.net/browse/BL-1198) CGI Scope should check variable name before attempting http\_header\_name convention

[BL-1200](https://ortussolutions.atlassian.net/browse/BL-1200) DynamicObject does not support dereference and invocation of non-static BoxLang class methods

[BL-1201](https://ortussolutions.atlassian.net/browse/BL-1201) Invoke BIF No Longer Functioning on Java Objects in Compat mode

[BL-1202](https://ortussolutions.atlassian.net/browse/BL-1202) java list dump template breaks in compat mode when expand is not passed

[BL-1203](https://ortussolutions.atlassian.net/browse/BL-1203) Java Interop - Typed Primitive Arrays passed as Java Args are always \`Object\[]\`

[BL-1204](https://ortussolutions.atlassian.net/browse/BL-1204) Compiler error - Non-literal value in BoxExpr type with hash expression

[BL-1205](https://ortussolutions.atlassian.net/browse/BL-1205) ClassMetaDataVisitor cannot find super class in same directory

[BL-1210](https://ortussolutions.atlassian.net/browse/BL-1210) cfhttp port attribute is not supported

[BL-1211](https://ortussolutions.atlassian.net/browse/BL-1211) servlet runtime using wrong getPageContext() BIF

[BL-1213](https://ortussolutions.atlassian.net/browse/BL-1213) Error accessing Map\<String,Object> when the key doesn't exist

[BL-1215](https://ortussolutions.atlassian.net/browse/BL-1215) directoryList has odd behavior when using 'dot' paths

[BL-1220](https://ortussolutions.atlassian.net/browse/BL-1220) Java Interop - StringBuilder usage is incorrectly passed through to String \`replace\` BIF

[BL-1221](https://ortussolutions.atlassian.net/browse/BL-1221) Error in cfdump when dumping a xml variable

[BL-1222](https://ortussolutions.atlassian.net/browse/BL-1222) Array Index Assignment for appending XML Children Not Working

[BL-1223](https://ortussolutions.atlassian.net/browse/BL-1223) class java.lang.Integer cannot be cast to class java.lang.String

[BL-1224](https://ortussolutions.atlassian.net/browse/BL-1224) Error serializing to JSON

[BL-1225](https://ortussolutions.atlassian.net/browse/BL-1225) getPageContext Lucee compatibility

[BL-1226](https://ortussolutions.atlassian.net/browse/BL-1226) DateConvert BIF Not Locale Aware

[BL-1227](https://ortussolutions.atlassian.net/browse/BL-1227) cftransaction - Failed to set savepoint

[BL-1228](https://ortussolutions.atlassian.net/browse/BL-1228) Can't cast \[] to a DateTime

[BL-1229](https://ortussolutions.atlassian.net/browse/BL-1229) Illegal class name

[BL-1230](https://ortussolutions.atlassian.net/browse/BL-1230) ListToArray on a Null value Throws Exception

[BL-1231](https://ortussolutions.atlassian.net/browse/BL-1231) ReplaceNoCase with Integer Replacement throws Exception

[BL-1232](https://ortussolutions.atlassian.net/browse/BL-1232) Compat - can't cast Short month with time to date

[BL-1233](https://ortussolutions.atlassian.net/browse/BL-1233) Java Interop - Explicit java.time.Duration is cast to BigDecimal upon use

[BL-1234](https://ortussolutions.atlassian.net/browse/BL-1234) current template not set in static initializer block

[BL-1236](https://ortussolutions.atlassian.net/browse/BL-1236) apparent connection leak detected

[BL-1237](https://ortussolutions.atlassian.net/browse/BL-1237) Issue with Java interop and var args

[BL-1238](https://ortussolutions.atlassian.net/browse/BL-1238) Array element type mismatch when using primitive arrays of non-well-known classes

[BL-1241](https://ortussolutions.atlassian.net/browse/BL-1241) Modify dump when dumping a class instance

[BL-1242](https://ortussolutions.atlassian.net/browse/BL-1242) Default cache was not being defaulted

[BL-1243](https://ortussolutions.atlassian.net/browse/BL-1243) Default cache should only allow properties to be overriden, not type

[BL-1244](https://ortussolutions.atlassian.net/browse/BL-1244) system cache clear now can clear query caching

[BL-1245](https://ortussolutions.atlassian.net/browse/BL-1245) Cache Component Not Accepting Timespan Timeout and IdleTime Args Correctly

[BL-1246](https://ortussolutions.atlassian.net/browse/BL-1246) Replace BIF fails when replacement argument is numeric

[BL-1247](https://ortussolutions.atlassian.net/browse/BL-1247) cfcatch key detail is missing

[BL-1248](https://ortussolutions.atlassian.net/browse/BL-1248) Can't cast \[Tue Nov 22 11:01:51 CET 2022] to a DateTime

[BL-1249](https://ortussolutions.atlassian.net/browse/BL-1249) class java.lang.Integer cannot be cast to class java.lang.String

[BL-1250](https://ortussolutions.atlassian.net/browse/BL-1250) Invoke Throws Error When Null Value is Assigned on Generated Setter

[BL-1252](https://ortussolutions.atlassian.net/browse/BL-1252) Consider renaming jsonDeserialize member function

[BL-1255](https://ortussolutions.atlassian.net/browse/BL-1255) JDBC - SQL Server Error When Using Date Time in Query Param

[BL-1256](https://ortussolutions.atlassian.net/browse/BL-1256) Incorrect parsing of string times when used in time format when Zone is different from system

[BL-1257](https://ortussolutions.atlassian.net/browse/BL-1257) Unsupported isolation level: READ\_COMMITTED

[BL-1261](https://ortussolutions.atlassian.net/browse/BL-1261) Miniserver getPageContext().getResponse().reset() not clearing status code and headers


# Beta Stage

This is the collection of Betas we released since our first version.


# 1.0.0-Beta26

January 14, 2025

## BoxLang Beta 26 Has Landed!

We’re thrilled to announce the release of **BoxLang 1.0.0 Beta 26**, a monumental update that takes performance and functionality to the next level. This beta officially **certifies the ColdBox HMVC Framework to run on BoxLang**, marking a significant milestone in compatibility. Not only can you now run all ColdBox applications seamlessly on BoxLang, but with the latest ColdBox snapshot, you can also build your entire applications in BoxLang, unlocking the full potential of this dynamic and expressive language for modern application development.

This release also introduces blazing-fast Query of Queries (QoQ) support, delivering speeds up to 70 times faster than Adobe or Lucee in specific scenarios, along with exciting new features like list parameter support in JDBC queries and custom QoQ functions. Over 70 bugs have been resolved, and significant improvements have been made, such as enhanced debugging capabilities, refined Box Script syntax, and robust session and metadata handling. With Beta 26, BoxLang continues to push the boundaries, empowering developers to build robust, efficient, and fully modern JVM-based applications.

Welcome to what could be our last beta before the final release of our initial 1.0.0 version of BoxLang and its multi-runtimes.

### New Features

[BL-94](https://ortussolutions.atlassian.net/browse/BL-94) Create query of queries support

[BL-883](https://ortussolutions.atlassian.net/browse/BL-883) Implement list parameters in JDBC queries

[BL-933](https://ortussolutions.atlassian.net/browse/BL-933) Ability to register custom functions for QoQ

[BL-942](https://ortussolutions.atlassian.net/browse/BL-942) Interceptor Service now does a service loader load of all interceptors found in the runtime to auto-load them

### Improvements

[BL-852](https://ortussolutions.atlassian.net/browse/BL-852) dump Lots of UI quality of life improvements: show length of strings, show full classes for some Java integrations, and much more.

[BL-860](https://ortussolutions.atlassian.net/browse/BL-860) Update `getMetaadata()` for dynamic proxies to leverage the class metadata instead of instances

[BL-865](https://ortussolutions.atlassian.net/browse/BL-865) CFTranspiler should not turn off accessors for persistent classes

[BL-866](https://ortussolutions.atlassian.net/browse/BL-866) Exception type matching check cause

[BL-919](https://ortussolutions.atlassian.net/browse/BL-919) Implement "Quick" algorithm for Hash BIF

[BL-920](https://ortussolutions.atlassian.net/browse/BL-920) Compat: CacheGet second argument is boolean for Lucee

[BL-926](https://ortussolutions.atlassian.net/browse/BL-926) ASM error in do/while with a break

[BL-938](https://ortussolutions.atlassian.net/browse/BL-938) Update the `getOrCreateSession`() to verify if the session has expired, and if so, rotate it.

[BL-939](https://ortussolutions.atlassian.net/browse/BL-939) Change generic tag-in-script syntax for Box Script to prefix with bx:

### Bugs

[BL-621](https://ortussolutions.atlassian.net/browse/BL-621) Allow a productivity hack to add ability to pass queries to some struct functions by taking the first row and converting the query to a struct.

[BL-732](https://ortussolutions.atlassian.net/browse/BL-732) structsort with callback errors

[BL-758](https://ortussolutions.atlassian.net/browse/BL-758) QofQ shouldn't require global DSN

[BL-764](https://ortussolutions.atlassian.net/browse/BL-764) xmlsearch - invalid XPath

[BL-801](https://ortussolutions.atlassian.net/browse/BL-801) ASM Failing test - fix bx:output transformer

[BL-802](https://ortussolutions.atlassian.net/browse/BL-802) ASM Failing test - fix abort exception

[BL-834](https://ortussolutions.atlassian.net/browse/BL-834) Dump Top Updates will not dump certain classes without a top argument, top shows as reached for subsequent dumps

[BL-847](https://ortussolutions.atlassian.net/browse/BL-847) BL GenericProxies cannot have java.lang.Object methods call on them

[BL-849](https://ortussolutions.atlassian.net/browse/BL-849) Class properties are merged from all inheritance levels in the metadata

[BL-850](https://ortussolutions.atlassian.net/browse/BL-850) Dumps are not in order of execution

[BL-851](https://ortussolutions.atlassian.net/browse/BL-851) Java List dumps are not working with top and are off by 1

[BL-854](https://ortussolutions.atlassian.net/browse/BL-854) Wirebox Block: testbuildJavaClass Methods on Java objects cannot be called with named arguments when using invoke()

[BL-855](https://ortussolutions.atlassian.net/browse/BL-855) Coercion for constructors from string to numbers are not working

[BL-856](https://ortussolutions.atlassian.net/browse/BL-856) Coercion from strings to numbers does not exist

[BL-857](https://ortussolutions.atlassian.net/browse/BL-857) isInstanceOf bif and keyword are not working on createObject("java") proxies. It gives a negative result

[BL-858](https://ortussolutions.atlassian.net/browse/BL-858) var scoping issues for bleeding scopes on class dump template

[BL-859](https://ortussolutions.atlassian.net/browse/BL-859) Calling getMetadata() on an instance of dynamic object that has not yet been inited, shows the metadata of DynamicObject instead of the proxy class

[BL-861](https://ortussolutions.atlassian.net/browse/BL-861) ORM: getter setters are not enabled for persistent CFCs

[BL-863](https://ortussolutions.atlassian.net/browse/BL-863) ORM: writedump causes ClassInfo not found

[BL-864](https://ortussolutions.atlassian.net/browse/BL-864) ORM: entityLoad should only require entity name

[BL-867](https://ortussolutions.atlassian.net/browse/BL-867) Show the right exception type when invoking dynamic objects and there are exceptions from a caused by

[BL-868](https://ortussolutions.atlassian.net/browse/BL-868) caching does not handle quoted numbers or booleans in config

[BL-869](https://ortussolutions.atlassian.net/browse/BL-869) ORM: EntityLoad errors when using a filter

[BL-870](https://ortussolutions.atlassian.net/browse/BL-870) soft reference cannot be stored directly in a struct

[BL-875](https://ortussolutions.atlassian.net/browse/BL-875) rework onSessionEnd to make sure the application exists when calling the listeners

[BL-877](https://ortussolutions.atlassian.net/browse/BL-877) Lucee allows params to be passed to cfquery tag via \`params\` attribute

[BL-879](https://ortussolutions.atlassian.net/browse/BL-879) IsNumeric() returns true for "true" and "false"

[BL-880](https://ortussolutions.atlassian.net/browse/BL-880) QueryNew() throws exception if row data array is empty

[BL-884](https://ortussolutions.atlassian.net/browse/BL-884) MSSQL throws error when executing certain queries if language is not English

[BL-885](https://ortussolutions.atlassian.net/browse/BL-885) Setting a dynamic variable name doesn't work

[BL-886](https://ortussolutions.atlassian.net/browse/BL-886) Can't cast \[now] to a DateTime

[BL-887](https://ortussolutions.atlassian.net/browse/BL-887) cfloop step not implemented

[BL-888](https://ortussolutions.atlassian.net/browse/BL-888) allow "switch" as struct key name in CF script

[BL-889](https://ortussolutions.atlassian.net/browse/BL-889) The instance \[ortus.boxlang.runtime.types.exceptions.ParseException] has no public field or inner class \[ERRORCODE]

[BL-890](https://ortussolutions.atlassian.net/browse/BL-890) In function \[numberFormat], argument \[number] with a type of \[java.lang.Boolean] does not match the declared type of \[number]

[BL-891](https://ortussolutions.atlassian.net/browse/BL-891) Datasources created after module load take on custom DSN parameters defined in bx-mssql

[BL-892](https://ortussolutions.atlassian.net/browse/BL-892) cfqueryparam with list attribute causes "The index 2 is out of range"

[BL-893](https://ortussolutions.atlassian.net/browse/BL-893) Queryparam list=true is unsupported

[BL-894](https://ortussolutions.atlassian.net/browse/BL-894) Key in arguments scope gets lost

[BL-895](https://ortussolutions.atlassian.net/browse/BL-895) Allow "switch" to be used in dot access

[BL-896](https://ortussolutions.atlassian.net/browse/BL-896) Can't cast ts to a Number.

[BL-897](https://ortussolutions.atlassian.net/browse/BL-897) named query params not handled correctly

[BL-898](https://ortussolutions.atlassian.net/browse/BL-898) Account for placeholder text in comments and quoted strings in SQL

[BL-899](https://ortussolutions.atlassian.net/browse/BL-899) numberFormat is displaying a leading 0 when formatting integers < 10

[BL-901](https://ortussolutions.atlassian.net/browse/BL-901) Duplicate() on CGI scope creates empty struct

[BL-902](https://ortussolutions.atlassian.net/browse/BL-902) CGI-Scope weirdness

[BL-903](https://ortussolutions.atlassian.net/browse/BL-903) MSSQL connection gets lost

[BL-904](https://ortussolutions.atlassian.net/browse/BL-904) Empty test fails when using ASM

[BL-905](https://ortussolutions.atlassian.net/browse/BL-905) MSSQL Query columns have wrong values

[BL-906](https://ortussolutions.atlassian.net/browse/BL-906) Using <bx:output> inside of <bx:catch> causes bxCatch scope to disappear

[BL-907](https://ortussolutions.atlassian.net/browse/BL-907) Array Loop with negative step doesn't work

[BL-909](https://ortussolutions.atlassian.net/browse/BL-909) Cannot invoke "ortus.boxlang.runtime.components.Component$BodyResult.isEarlyExit()" because "bodyResult" is null

[BL-910](https://ortussolutions.atlassian.net/browse/BL-910) Passing query column to listToArray() BIF fails

[BL-911](https://ortussolutions.atlassian.net/browse/BL-911) IsNumeric BIF returns true on booleans in compat mode

[BL-912](https://ortussolutions.atlassian.net/browse/BL-912) getBaseTemplatePath returns \`Application.cfc\` in onRequestStart

[BL-913](https://ortussolutions.atlassian.net/browse/BL-913) Throw with exception object as unnamed argument fails

[BL-914](https://ortussolutions.atlassian.net/browse/BL-914) Null session scope when attempting to update the last visit

[BL-917](https://ortussolutions.atlassian.net/browse/BL-917) Compat GetComponentMetadata Failures with "Can't cast null to a Key".

[BL-918](https://ortussolutions.atlassian.net/browse/BL-918) String \[1 LTE 5] cannot be cast to a boolean

[BL-923](https://ortussolutions.atlassian.net/browse/BL-923) Compat: Attributes to Functions Are Scoped in to nested Parameters Struct

[BL-925](https://ortussolutions.atlassian.net/browse/BL-925) Cannot invoke method \[clearbuffer()] on a null object

[BL-927](https://ortussolutions.atlassian.net/browse/BL-927) Double variable assignment failing in ASM

[BL-928](https://ortussolutions.atlassian.net/browse/BL-928) Compat: Invoke method has different required object method

[BL-930](https://ortussolutions.atlassian.net/browse/BL-930) StructFindKey Returns a Null Value when Struct being searched contains nulls

[BL-932](https://ortussolutions.atlassian.net/browse/BL-932) toBinary() not lenient enough for decoding with line paddings

[BL-936](https://ortussolutions.atlassian.net/browse/BL-936) When doing named parameter queries and you send more parameters than required, it should ignore them, not throw an exception that you sent more

[BL-937](https://ortussolutions.atlassian.net/browse/BL-937) getOrCreateSession() relying on the starting listener for settings, when it should look at the context to reflect changes if any

[BL-941](https://ortussolutions.atlassian.net/browse/BL-941) WebRequest interceptor in web support is not auto-loading, also will affect any other composable runtimes

[BL-944](https://ortussolutions.atlassian.net/browse/BL-944) node.xmlText explicit assignment throws error that value is not node or XML instance

[BL-945](https://ortussolutions.atlassian.net/browse/BL-945) xmlAttributes assignment error - key not found

### Task

[BL-217](https://ortussolutions.atlassian.net/browse/BL-217) ColdBox Test Suite

[BL-220](https://ortussolutions.atlassian.net/browse/BL-220) Quick Test Suite

[BL-548](https://ortussolutions.atlassian.net/browse/BL-548) Parser performance and removing ambiguity

[BL-767](https://ortussolutions.atlassian.net/browse/BL-767) CFcasts Suite

[BL-837](https://ortussolutions.atlassian.net/browse/BL-837) UnleashSDK Certification

[BL-908](https://ortussolutions.atlassian.net/browse/BL-908) Incorporate TestBox test suite

### Stories

[BL-237](https://ortussolutions.atlassian.net/browse/BL-237) Phase II : Update all the toAST() methods to the new and consolidated approach

[BL-238](https://ortussolutions.atlassian.net/browse/BL-238) Phase III : Performance tests for phase I + II toolchains

[BL-239](https://ortussolutions.atlassian.net/browse/BL-239) Phase V : Create the QoQ SQL grammar, parser, and astss


# 1.0.0-Beta25

December 13, 2024

## BoxLang Beta 25 Has Landed!

This release takes BoxLang to the next level, delivering a mix of critical bug fixes, thoughtful improvements, and exciting new features designed to enhance your development experience. With Beta25, we’ve solidified and made the **ASM ByteCode BoxPiler** the default compiler, refined module, and logging management, and added long-requested query of queries and JSON-based logging encoders. Additionally, we’ve tackled critical issues around debugging, compatibility, and system settings to make this the most stable and feature-complete beta yet.

At this point, we have a handful of small bugs open, which will completely certify all of the major Ortus frameworks like ColdBox, ContentBox, and over 50 modules. Complete certification is around the corner.

As a bonus, we are almost ready to release our Hibernate ORM module (`bx-orm`) and move into a Release Candidate phase for our entire lineup. So please test test test, and give us your feedback.

### ✨ New Features

• [BL-121](https://ortussolutions.atlassian.net/browse/BL-121): createObject() now supports classloading arguments as the third argument.

Easily manage and control classloading with arguments to enhance flexibility and modularity.

```java
createObject( "java", "HelloWorld", [ "/libs/paths" ]
```

• [BL-699](https://ortussolutions.atlassian.net/browse/BL-699): Dynamic Task Management in Schedulers

Added `startupTask(task)` to dynamically initialize tasks by name or task object.

• [BL-794](https://ortussolutions.atlassian.net/browse/BL-794): JSON-based Logging Support

Appenders and root configurations now include JSON encoders for enhanced logging formats.

• [BL-828](https://ortussolutions.atlassian.net/browse/BL-828): Improved Scheduler Logging

Scheduler logs are now effectively reported to provide better insights.

• [BL-829](https://ortussolutions.atlassian.net/browse/BL-829): Enhanced Module Logging

Modules now have dedicated logs to improve debugging and diagnostics.

• [BL-832](https://ortussolutions.atlassian.net/browse/BL-832): New Event Lifecycle: `onConfigurationLoad`

Introduced a new lifecycle event for IServices to optimize configuration handling.

• [BL-833](https://ortussolutions.atlassian.net/browse/BL-833): Enhanced Compatibility Assignments

Assignments now accurately interpret null variables for better compatibility.

• [BL-846](https://ortussolutions.atlassian.net/browse/BL-846): New Logging Setting: `statusPrinterOnLoad`

Added statusPrinterOnLoad for much-needed debugging of logging configurations.

***

### 🛠 Improvements

• [BL-682](https://ortussolutions.atlassian.net/browse/BL-682): Streamlined Method Expectations

Improved handling of methods that don’t expect return values for better consistency.

• [BL-706](https://ortussolutions.atlassian.net/browse/BL-706): Enhanced Session Cookie Controls

Added missing controls for session cookie management to improve security and compliance.

• [BL-760](https://ortussolutions.atlassian.net/browse/BL-760): Bytecode Line Number Enhancements

Added line number details to bytecode generated with ASM for improved debugging.

• [BL-766](https://ortussolutions.atlassian.net/browse/BL-766): ASM is Now the Default BoxPiler

Streamlined the toolchain by making ASM the only default stock BoxPiler.

• [BL-784](https://ortussolutions.atlassian.net/browse/BL-784): Optimized Replace Operations

Updated replaceAll() methods to use pre-compiled patterns for better performance.

• [BL-787](https://ortussolutions.atlassian.net/browse/BL-787): Unified Logging Configuration

Consolidated logging startups and configurations for both servlet and non-servlet environments.

• [BL-788](https://ortussolutions.atlassian.net/browse/BL-788): Support for this.componentPaths

Introduced implicit mapping support for more intuitive path management.

• [BL-791](https://ortussolutions.atlassian.net/browse/BL-791): Module Enable/Disable Support

Modules can now be enabled or disabled using enabled in boxlang.json, removing double negatives like disabled.

• [BL-809](https://ortussolutions.atlassian.net/browse/BL-809): Forms Module Introduced

A new module for handling forms was added, enhancing the BoxLang ecosystem.

• [BL-812](https://ortussolutions.atlassian.net/browse/BL-812): Improved Scope Assignment

Allowed reassignment of a scope to a struct for more flexible programming.

• [BL-822](https://ortussolutions.atlassian.net/browse/BL-822): Collision Prevention in IClassRunnable Methods

Prefixed methods to prevent naming collisions for safer execution.

• [BL-830](https://ortussolutions.atlassian.net/browse/BL-830): Graceful Module Unloading

Added defensive coding for module unloading failures to ensure runtime stability.

• [BL-831](https://ortussolutions.atlassian.net/browse/BL-831): Consistent Struct Collector Outputs

Resolved inconsistencies by ensuring collectors return Struct objects.

• [BL-839](https://ortussolutions.atlassian.net/browse/BL-839): Improved Parent Class Delegation

Enhanced module class loaders to delegate certain parent classes to the parent loader exclusively.

***

### 🐞 Bug Fixes

• ASM and Debugging Fixes:

[BL-694](https://ortussolutions.atlassian.net/browse/BL-694), [BL-742](https://ortussolutions.atlassian.net/browse/BL-742), [BL-759](https://ortussolutions.atlassian.net/browse/BL-759), [BL-762](https://ortussolutions.atlassian.net/browse/BL-762), [BL-760](https://ortussolutions.atlassian.net/browse/BL-760)

• Localization and Formatting Issues:

[BL-819](https://ortussolutions.atlassian.net/browse/BL-819), [BL-825](https://ortussolutions.atlassian.net/browse/BL-825), [BL-820](https://ortussolutions.atlassian.net/browse/BL-820)

• Parsing Errors:

[BL-823](https://ortussolutions.atlassian.net/browse/BL-823), [BL-824](https://ortussolutions.atlassian.net/browse/BL-824), [BL-827](https://ortussolutions.atlassian.net/browse/BL-827)

• Thread and Scope Resolution Bugs:

[BL-813](https://ortussolutions.atlassian.net/browse/BL-813), [BL-815](https://ortussolutions.atlassian.net/browse/BL-815), [BL-817](https://ortussolutions.atlassian.net/browse/BL-817)

• Miscellaneous:

[BL-826](https://ortussolutions.atlassian.net/browse/BL-826), [BL-836](https://ortussolutions.atlassian.net/browse/BL-836), [BL-841](https://ortussolutions.atlassian.net/browse/BL-841), [BL-845](https://ortussolutions.atlassian.net/browse/BL-845)


# 1.0.0-Beta24

December 2, 2024

### Introducing BoxLang 1.0.0 Beta 24!

We’re excited to announce the release of Beta 24, packed with powerful new features, essential bug fixes, and impactful improvements that enhance performance and security. This release brings more robust logging capabilities, enhanced configuration flexibility, and new query-handling methods to streamline your development experience. We’ve also squashed several parsing bugs, ensuring smoother code execution.

Whether you’re optimizing your runtime with custom logging encoders or leveraging the new `queryColumnList` for seamless data manipulation, Beta 24 is designed to empower developers with a more secure, customizable, and efficient development environment.

### 🐞 Bug Fixes

• BL-797: Parsing issue fixed when using a < symbol before a tag. No more parsing hiccups!

• BL-798: = sign after an if tag? No problem now! Fixed to handle this scenario smoothly.

• BL-799: Parentheses confusion resolved! Opening parentheses (afterword operators will no longer be mistaken for function calls.

• BL-800: Environmental safety improved: BOXLANG\_DEBUG will now be parsed only if non-null to prevent unexpected behavior.

### ✨ New Features

#### Improved Logging

BoxLang's logging features have been completely revamped in preparation for its stable release. You also have fine-grain control over them, and module developers will be able to register and leverage custom loggers and appenders.

Please note that the `logsDirectory` setting has been moved from the root of the `boxlang.json` to the new `logging` section.

Check out the new configuration:

```json
// Logging Settings for the runtime
"logging": {
	// The location of the log files the runtime will produce
	"logsDirectory": "${boxlang-home}/logs",
	// The maximum number of days to keep log files before rotation
	// Default is 90 days or 3 months
	// Set to 0 to never rotate
	"maxLogDays": 90,
	// The maximum file size for a single log file before rotation
	// You can use the following suffixes: KB, MB, GB
	// Default is 100MB
	"maxFileSize": "100MB",
	// The total cap size of all log files before rotation
	// You can use the following suffixes: KB, MB, GB
	// Default is 5GB
	"totalCapSize": "5GB",
	// The root logger level
	// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
	// If the runtime is in Debug mode, this will be set to DEBUG
	"rootLevel": "WARN",
	// Default Encoder for file appenders.
	// The available options are "text" and "json"
	"defaultEncoder": "text",
	// A collection of pre-defined loggers and their configurations
	"loggers": {
		// The runtime main and default log
		"runtime": {
			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
			// Leave out if it should inherit from the root logger
			//"level": "WARN",
			// Valid values are: "file", "console",
			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
			// Please note that we only use Rolling File Appenders
			"appender": "file",
			// Use the defaults from the runtime
			"appenderArguments": {},
			// The available options are "text" and "json"
			"encoder": "text",
			// Additive logging: true means that this logger will inherit the appenders from the root logger
			// If false, it will only use the appenders defined in this logger
			"additive": true
		},
		// The modules log
		"modules": {
			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
			// Leave out if it should inherit from the root logger
			//"level": "WARN",
			// Valid values are: "file", "console",
			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
			// Please note that we only use Rolling File Appenders
			"appender": "file",
			// Use the defaults from the runtime
			"appenderArguments": {},
			// The available options are "text" and "json"
			"encoder": "text",
			// Additive logging: true means that this logger will inherit the appenders from the root logger
			// If false, it will only use the appenders defined in this logger
			"additive": true
		},
		// All applications will use this logger
		"application": {
			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
			// Leave out if it should inherit from the root logger
			"level": "TRACE",
			// Valid values are: "file", "console",
			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
			// Please note that we only use Rolling File Appenders
			"appender": "file",
			// Use the defaults from the runtime
			"appenderArguments": {},
			// The available options are "text" and "json"
			"encoder": "text",
			// Additive logging: true means that this logger will inherit the appenders from the root logger
			// If false, it will only use the appenders defined in this logger
			"additive": true
		},
		// All scheduled tasks logging
		"scheduler": {
			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
			// Leave out if it should inherit from the root logger
			"level": "INFO",
			// Valid values are: "file", "console",
			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
			// Please note that we only use Rolling File Appenders
			"appender": "file",
			// Use the defaults from the runtime
			"appenderArguments": {},
			// The available options are "text" and "json"
			"encoder": "text",
			// Additive logging: true means that this logger will inherit the appenders from the root logger
			// If false, it will only use the appenders defined in this logger
			"additive": true
		}
	}
},
```

#### JSON Anyone?

We have added support for [JSON Lines](https://jsonlines.org/) log files. You can now switch the default encoder for the log files from `text` to `json` and see the JSON log files in full splendor!

• BL-792: Introducing CFConfig support and named loggers for more precise control over your logging setup!

• BL-793: Added the ability to configure logging items, giving you more flexibility in managing your logs.

• BL-803: Choose your logging format! You can now select text and JSON logging encoders for better runtime output customization.

\\

📈 Improvements\\

• BL-782: Refined the LoggingService to encapsulate all logging characteristics, streamlining log management.

• BL-783: Strengthened security by disabling absolute path logging and prohibiting custom log extensions. Your logs are safer now!

• BL-785: Upgraded logging to follow ISO8601 date/time format and threading standards for more standardized logs.

• BL-786: Replaced FileAppender with RollingFileAppender to better handle large log files through automatic rotation.

• BL-795: Introduced queryColumnList BIF and a columnList() member method for easier Query column management.

• BL-804: Enhanced support for customTagPaths in Application.cfc/bx, expanding customization capabilities.


# 1.0.0-Beta23

November 23, 2024

## Introducing BoxLang 1.0.0 Beta 23

The latest release of BoxLang, Beta 23, marks a significant step forward in our journey to create the ultimate dynamic language for the JVM. Packed with powerful new features, important bug fixes, and thoughtful optimizations, this update is designed to make your development experience smoother, faster, and more reliable, especially after now starting to take 100s of comments and bug reports from our community.

**Modularity** takes center stage in this release with the ability to define BoxLang components (aka Tags) within modules and a new version-checking mechanism that ensures module compatibility. Database interactions are now more intuitive with enhancements to the Generic JDBC Driver, and the introduction of the `getSemver()` function brings a robust tool for managing semantic versioning with precision and ease.

Debugging and performance have also seen **major** improvements. The `dump` function now outputs directly to the console in scripting contexts, simplifying debugging workflows, while significant optimizations in functions like `len()` and the `DateTimeCaster` improve execution speed and efficiency. We've also addressed critical issues around argument handling, JDBC URL creation, and logging performance, ensuring a more stable and predictable environment for your applications.

Please continue to test your applications as we continue to push forwards towards stable release this winter.

## 🚀 New Features

1. **Component in BX for Modules** *(BL-750)*\
   Modules in BoxLang just got a serious upgrade! You can now build components for BoxLang using BoxLang. No more Java ma!

```java
/**
 * This is a BoxLang only Component
 *
 * Annotations you can use on a component:
 * <pre>
 * // The alias of the Component, defaults to the name of the Class
 * @BoxComponent 'myComponentAlias'
 * @BoxComponent [ 'myComponentAlias', 'anotherAlias' ]
 * @AllowsBody [boolean=false]
 * @RequiresBody [boolean=false]
 * </pre>
 *
 * The runtime injects the following into the variables	scope:
 * - boxRuntime : BoxLangRuntime
 * - log : A logger
 * - functionService : The BoxLang FunctionService
 * - interceptorService : The BoxLang InterceptorService
 * - moduleRecord : The ModuleRecord instance
 *
 * The runtime also injects the following helpers into the variables scope:
 * - newBuffer() : Create and return a new StringBuffer
 * - newBuilder() : Create and return a new StringBuilder
 * - processBody( context, body, [buffer] ) : Process the body of a component
 * - getName() : Get the name of the component
 */
@BoxComponent 'HolaComponent'
@AllowsBody true
@RequiresBody false
class{

	/**
	 * The execution of this Component
	 *
	 * <pre>
	 * <bx:holaComponent>This is my output</bx:holaComponent>
	 * </pre>
	 *
	 * @param context The context of the execution (IBoxContext)
	 * @param attributes The attributes of the component that were passed in
	 * @param body The body of the component that you can pass to `processBody(context, body, [buffer])` for execution and buffer retreival
	 * @param executionState The execution state of the component. Each component get's one as an isolated state.
	 *
	 * @return A BodyResult instance or null for a default result return.
	 */
	function invoke( required context, Struct attributes, any body, Struct executionState ){
		// A buffer to capture the body output
		var	buffer		= newBuffer();
		var	bodyResult	= processBody( context, body, buffer );

		// // If there was a return statement inside our body, we early exit now
		if ( bodyResult.isEarlyExit() ) {
			return bodyResult;
		}
		// // reverse the buffer contents and place into a string
		var newContent	= buffer.reverse().toString();
		// // output it to the page buffer
		context.writeToBuffer( newContent );
	}

}
```

2. **Module Compatibility Check** *(BL-768)*\
   The `ModuleService` now includes a powerful compatibility check for the "boxlang" version in your `box.json`. This ensures that your modules are running on a supported version of BoxLang, avoiding unexpected runtime issues. Just add the `minimumVersion` to the `box.json` under the `boxlang` section and it will tell the Module Service which supported minimum version your module will work on.

```json
"boxlang": {
    "minimumVersion": "1.0.0",
    "moduleName": "test",
}
```

3. **Generic JDBC Driver Enhancement** *(BL-771)*\
   We've added a **default URL delimiter** to the Generic JDBC Driver. This improvement makes BoxLang more adaptable to various database configurations, simplifying JDBC URL handling for databases with unique delimiter requirements.
4. **New `getSemver()` BIF** *(BL-777)*\
   Introducing the `getSemver()` built-in function! You can now quickly parse or construct semantic versioning (**semver**) strings and work with them as `Semver` objects for enhanced version management. The new BIF will parse and give you a `Semver` object to work with. You can also use it to build fluent semantic version strings.

```cfscript
var version = GetSemver( "1.2.3-alpha+20151212" )
var version = GetSemver( "1.2.3-alpha" )
var version = GetSemver( "1.2.3" )
var version = GetSemver( "1.2.3+20151212" )
var version = GetSemver( "1.2.3-alpha.1" )
var version = GetSemver( "1.2.3-alpha.beta" )

var version1 = GetSemver( "1.2.3" )
var version2 = GetSemver( "1.2.4" )
var version3 = GetSemver( "1.3.0" )

version1.compare( version2 ); // -1
version1.compare( version3 ); // -1
version2.compare( version3 ); // -1

var version = GetSemver().withMajor( 1 ).withMinor( 2 ).withPatch( 3 ).withPreRelease( "alpha" ).toSemver()
var versionString = GetSemver().withMajor( 1 ).withMinor( 2 ).withPatch( 3 ).withPreRelease( "alpha" ).toString()
```

***

## 🔧 Improvements

* **Console Output for `dump` in Scripting Contexts** *(BL-769)*\
  Debugging just got easier! By default, the `dump` function now outputs to the console when running in scripting contexts, making it seamless to debug CLI scripts.
* **Optimized `len()` Function** *(BL-770)*\
  The `len()` function is now smarter and faster! We've removed unnecessary date parsing, resulting in better performance.

***

## 🛠️ Tasks

* **Query Options Completion** *(BL-116)*\
  We've implemented unfinished query options, giving you more control and flexibility when working with data queries.

***

## 🐞 Bug Fixes

1. **`abort` in `cfdump` Tag** *(BL-761)*\
   Resolved an issue where using `abort` in conjunction with the `cfdump` tag caused unexpected errors.
2. **Whitespace Handling in HTTP Responses** *(BL-763)*\
   Improved handling of whitespace in responses where the `Content-Type` header was not yet set, ensuring better compatibility with various HTTP clients.
3. **Positional vs Named Arguments** *(BL-765)*\
   Fixed inconsistent behavior when handling arguments passed by position versus named.
4. **Invalid JDBC URLs** *(BL-772)*\
   Corrected the handling of the `dsn` key for JDBC drivers, ensuring compatibility with `cfconfig` replacements and producing valid JDBC URLs.
5. **Improved DateTime Performance** *(BL-774)*\
   Enhanced the performance of the `DateTimeCaster` and `DateTime` object instantiation when working with strings.
6. **Endless Recursion in `onSessionStart()`** *(BL-775)*\
   Addressed an issue where the `onSessionStart()` event could cause infinite recursion under certain conditions.
7. **`debugmode` in `boxlang.json`** *(BL-776)*\
   Fixed a problem where the `debugmode` flag was not being utilized as expected.
8. **Servlet Debug Mode Reconfiguration** *(BL-778)*\
   Resolved issues with reconfiguring debug mode in servlet-based environments.
9. **Logging Performance** *(BL-779)*\
   Overhauled the `LoggingInterceptor` to prevent inefficient recreation of appenders and loggers, especially under heavy stress.
10. **Missing `application` Argument in Logging** *(BL-780)*\
    The `writelog` and `log` components now properly support the `application` boolean argument.

***

#### Why Upgrade?

This release has powerful new features, performance enhancements, and critical bug fixes. Whether you're a developer building complex applications or managing modular systems, Beta 23 makes your BoxLang experience smoother and more efficient.

Ready to dive in? 🚀 Update to Beta 23 now and take your BoxLang projects to the next level!


# 1.0.0-Beta22

The BoxLang 1.0.0-Beta22 release includes several improvements, bug fixes, new features, and stories. Key improvements include enhanced redirection for the Miniserver, better transactional event broadcasting, and added convenience methods like `getRequestContext()` and `getApplicationContext()`. Bug fixes address issues such as JSON deserialization, whitespace management, and various errors related to data types and loops. New features include support for multiple statements inside queries and a new `datasourceRegister()` BIF for easier SaaS integrations.

## Release Notes

#### New Features

[BL-123](https://ortussolutions.atlassian.net/browse/BL-123) Implement multiple statements inside queries

[BL-383](https://ortussolutions.atlassian.net/browse/BL-383) new bif: datasourceRegister() to allow for easy saas integrations to create datasources

[BL-658](https://ortussolutions.atlassian.net/browse/BL-658) MIgrate AST Capture to it's own experimental flag

[BL-748](https://ortussolutions.atlassian.net/browse/BL-748) Add getApplicationContext() method on all contexts for convenience, especially when calling from CF/BL

#### Improvement

[BL-730](https://ortussolutions.atlassian.net/browse/BL-730) Miniserver needs to 302 redirect when hitting a directory without the trailing slash

[BL-734](https://ortussolutions.atlassian.net/browse/BL-734) Broadcast Transactional events at the Application listener-level

[BL-735](https://ortussolutions.atlassian.net/browse/BL-735) Allow unregistering a java class (IInterceptor) from an InterceptorPool

[BL-737](https://ortussolutions.atlassian.net/browse/BL-737) Add getRequestContext() method on all contexts for convenience, especially when calling from CF/BL

[BL-738](https://ortussolutions.atlassian.net/browse/BL-738) Allow output from functional wrappers

[BL-740](https://ortussolutions.atlassian.net/browse/BL-740) Autocast simple values to Keys when calling java methods from BL

[BL-741](https://ortussolutions.atlassian.net/browse/BL-741) Allow :: static access to be chained to any expression

[BL-746](https://ortussolutions.atlassian.net/browse/BL-746) Add toLegacyDate BIF and Member Function to Compat module

[BL-751](https://ortussolutions.atlassian.net/browse/BL-751) Make generated getters return null when property is not initialized

[BL-116](https://ortussolutions.atlassian.net/browse/BL-116) Implement unfinished query options

#### Bug

[BL-694](https://ortussolutions.atlassian.net/browse/BL-694) Fix tests that fail when using ASM

[BL-695](https://ortussolutions.atlassian.net/browse/BL-695) large json fails to deserialise with bx-compat

[BL-714](https://ortussolutions.atlassian.net/browse/BL-714) Add Whitespace Management

[BL-731](https://ortussolutions.atlassian.net/browse/BL-731) dump errors with compat installed due to null variable

[BL-733](https://ortussolutions.atlassian.net/browse/BL-733) RandRange seems to never return upper range

[BL-736](https://ortussolutions.atlassian.net/browse/BL-736) JDBC Transaction listeners not firing upon transaction event announcement

[BL-739](https://ortussolutions.atlassian.net/browse/BL-739) shebang checks in BoxRunner don't nicely handle invalid file paths

[BL-743](https://ortussolutions.atlassian.net/browse/BL-743) WDDX not parsing booleans correctly

[BL-744](https://ortussolutions.atlassian.net/browse/BL-744) Cannot cast ortus.boxlang.runtime.types.DateTime to java.util.Date

[BL-745](https://ortussolutions.atlassian.net/browse/BL-745) parseDateTime failing

[BL-747](https://ortussolutions.atlassian.net/browse/BL-747) for (sentinel) loop is evaluating the step/increment expression one final time too many when a break is used

[BL-752](https://ortussolutions.atlassian.net/browse/BL-752) error using negative indices to get characters from strings

[BL-754](https://ortussolutions.atlassian.net/browse/BL-754) error: integer number too large

[BL-755](https://ortussolutions.atlassian.net/browse/BL-755) SerializeJSON not working with named params


# 1.0.0-Beta21

October 25th, 2024

This release brings another round of powerful tools and refinements to the BoxLang community, making development more dynamic and robust than ever. We’ve added new capabilities for debugging and tracing, expanded context-sensitive controls for thread management, and introduced new methods for fluent attachment handling.

For deeper flexibility, our improvements enhance configurability, streamline session control, and add deeper levels of JSON serialization management. Plus, we’ve squashed a wide range of bugs, enhancing stability across database connections, date handling, and runtime compatibility with CFML.

In addition, CSRF Token functionality is now provided via [the `bx-csrf` module](https://forgebox.io/view/bx-csrf).

#### New Feature

[BL-713](https://ortussolutions.atlassian.net/browse/BL-713) Global events for Application events

[BL-720](https://ortussolutions.atlassian.net/browse/BL-720) Implement table filter for dbinfo component

[BL-721](https://ortussolutions.atlassian.net/browse/BL-721) getComponentList() should also return the declared attributes of a component

[BL-722](https://ortussolutions.atlassian.net/browse/BL-722) getFunctionList() should also return the declared arguments of a BIF

#### Improvement

[BL-710](https://ortussolutions.atlassian.net/browse/BL-710) Implement Algorithm Argument for RandRange

[BL-716](https://ortussolutions.atlassian.net/browse/BL-716) Set request class loader into thread as context class loader

[BL-717](https://ortussolutions.atlassian.net/browse/BL-717) Retain directories in dynamic class loader

[BL-728](https://ortussolutions.atlassian.net/browse/BL-728) Add nullIsUndefined flag to control how null variables are handled

[BL-729](https://ortussolutions.atlassian.net/browse/BL-729) Don't default properties with no default value to null when compat has enabled nullIsUndefined scope behavior

#### Bug

[BL-638](https://ortussolutions.atlassian.net/browse/BL-638) Passing a null named argument hides outer bindings by the same name

[BL-641](https://ortussolutions.atlassian.net/browse/BL-641) Missing BIF - CSRFGenerateToken is now supplied with the `bx-csrf` module

[BL-669](https://ortussolutions.atlassian.net/browse/BL-669) Difference in args vs local variables handling

[BL-677](https://ortussolutions.atlassian.net/browse/BL-677) Incompat: metadata annotations from inherited sub classses added to top level class

[BL-679](https://ortussolutions.atlassian.net/browse/BL-679) cfloop collection with an array throws casting exception

[BL-697](https://ortussolutions.atlassian.net/browse/BL-697) argument collection optional param is null

[BL-711](https://ortussolutions.atlassian.net/browse/BL-711) dot access not chaining to static access

[BL-712](https://ortussolutions.atlassian.net/browse/BL-712) NPE when calling non-existent Java method

[BL-715](https://ortussolutions.atlassian.net/browse/BL-715) Duplicate of cfc instance presenting as struct

[BL-718](https://ortussolutions.atlassian.net/browse/BL-718) Key access in StructMapWrapper not working

[BL-719](https://ortussolutions.atlassian.net/browse/BL-719) GetTagData(), GetFunctionData() function not implemented, implement in the COMPAT module

[BL-724](https://ortussolutions.atlassian.net/browse/BL-724) import name restrictions too strict

[BL-726](https://ortussolutions.atlassian.net/browse/BL-726) Assignment not working on static fields of an imported class

[BL-727](https://ortussolutions.atlassian.net/browse/BL-727) Adding two ints uneccessarily returns a long


# 1.0.0-Beta20

October 25th, 2024

<figure><img src="/files/D4SAVALWFEg3dG96GNVF" alt=""><figcaption></figcaption></figure>

**🚀 Introducing BoxLang 1.0.0 Beta 20! 🚀**

This release brings another round of powerful tools and refinements to the BoxLang community, making development more dynamic and robust than ever. We’ve added new capabilities for debugging and tracing, expanded context-sensitive controls for thread management, and introduced new methods for fluent attachment handling.

For deeper flexibility, our improvements enhance configurability, streamline session control, and add deeper levels of JSON serialization management. Plus, we’ve squashed a wide range of bugs, enhancing stability across database connections, date handling, and runtime compatibility with CFML.

## New Feature

[BL-117](https://ortussolutions.atlassian.net/browse/BL-117) trace bif and component

[BL-670](https://ortussolutions.atlassian.net/browse/BL-670) Setup the thread's context class loader when an application is defined with the correct loader from the Applications java settings

[BL-684](https://ortussolutions.atlassian.net/browse/BL-684) showDebugOuput added to request box context to allow for tracer/debugging outputs

[BL-688](https://ortussolutions.atlassian.net/browse/BL-688) new computeAttachmentIfAbsent, to make fluent attachments on IBoxAttachable implementations

[BL-689](https://ortussolutions.atlassian.net/browse/BL-689) refactor escapeHTML to the lib we use instead of multiple functions

[BL-698](https://ortussolutions.atlassian.net/browse/BL-698) DateTime objects don't have a len member method

## Improvements

[BL-672](https://ortussolutions.atlassian.net/browse/BL-672) Add line break in dump console output

[BL-673](https://ortussolutions.atlassian.net/browse/BL-673) Allow access to super scope from thread

[BL-683](https://ortussolutions.atlassian.net/browse/BL-683) reuse config of validTemplateExtensions

[BL-686](https://ortussolutions.atlassian.net/browse/BL-686) Add ability to deep merge config items from the environment.

[BL-687](https://ortussolutions.atlassian.net/browse/BL-687) track current request context in thread

[BL-690](https://ortussolutions.atlassian.net/browse/BL-690) improve concurrency of session ID creation

[BL-693](https://ortussolutions.atlassian.net/browse/BL-693) Move from immutable verbiage to unmodifiable

[BL-703](https://ortussolutions.atlassian.net/browse/BL-703) Need to set explicit \`/\` path on session cookies

[BL-707](https://ortussolutions.atlassian.net/browse/BL-707) if calling serializeJSON() on a class, and the class is marked as not serializable, then return empty struct

[BL-708](https://ortussolutions.atlassian.net/browse/BL-708) if calling serializeJSON() on a class, properties marked as not serialiable should be skipped.

[BL-709](https://ortussolutions.atlassian.net/browse/BL-709) Arrays/Lists/Structs/Maps/Classes that have been visited already by JSON will not serialize again but show a recursion marker

## Bugs

[BL-640](https://ortussolutions.atlassian.net/browse/BL-640) bx-compat-cfml datediff fails to convert string

[BL-645](https://ortussolutions.atlassian.net/browse/BL-645) Update parser to allow for \`@module\` notations on imports and \`new\` operators

[BL-663](https://ortussolutions.atlassian.net/browse/BL-663) NOT operator precedence not grabbing operators in the chain

[BL-668](https://ortussolutions.atlassian.net/browse/BL-668) Java Doc implementation is stricter that ACF and Lucee

[BL-671](https://ortussolutions.atlassian.net/browse/BL-671) Missed module class hierarchy to have the runtime class loader as the parent

[BL-675](https://ortussolutions.atlassian.net/browse/BL-675) ortus.boxlang.runtime.events.InterceptorPool: Errors announcing \[logMessage] interception ortus.boxlang.runtime.types.exceptions.BoxRuntimeException: An error occurred while attempting to log the message

[BL-676](https://ortussolutions.atlassian.net/browse/BL-676) Dump not showing BoxLang type NullValue as null

[BL-678](https://ortussolutions.atlassian.net/browse/BL-678) DBInfo schema and several other columns can be null, make sure you address it

[BL-680](https://ortussolutions.atlassian.net/browse/BL-680) boxclass dump looping construct exception

[BL-696](https://ortussolutions.atlassian.net/browse/BL-696) java class method not found

[BL-697](https://ortussolutions.atlassian.net/browse/BL-697) argument collection optional param is null

[BL-701](https://ortussolutions.atlassian.net/browse/BL-701) Cannot convert class ortus.boxlang.runtime.types.DateTime to SQL type requested due to com.mysql.cj.exceptions.WrongArgumentException - Conversion from ortus.boxlang.runtime.types.DateTime to TIMESTAMP is not supported.

[BL-702](https://ortussolutions.atlassian.net/browse/BL-702) DatabaseException: There is no known date-time pattern for '09/24/2024' value at ortus.boxlang.runtime.jdbc.PendingQuery.executeStatement(PendingQuery.java:390)

[BL-704](https://ortussolutions.atlassian.net/browse/BL-704) cannot get lenght of native java date time objects

[BL-705](https://ortussolutions.atlassian.net/browse/BL-705) Can't cast \[2021-01-01 12:00:00 pm] to a DateTime.


# 1.0.0-Beta19

October 18th, 2024

<figure><img src="/files/2rvD9ktT2ZSm90NwzhZR" alt=""><figcaption></figcaption></figure>

Welcome to the latest release of BoxLang, where innovation takes center stage with groundbreaking enhancements and features designed to elevate your development experience. With the introduction of the **ASMBoxPiler**, we're pioneering a direct pathway to converting BoxLang code into highly optimized Java bytecode, offering an unprecedented boost in performance and efficiency. By eliminating traditional bottlenecks, we're empowering developers to achieve seamless integration with Java environments, transforming the way applications are built and executed. Prepare to explore the full potential of your projects with this transformative update!

## New Features

### [BL-667](https://ortussolutions.atlassian.net/browse/BL-667) ASMBoxPiler to do direct Java bytecode creation

With the implementation of the **ASMBoxPiler**, developers can now compile BoxLang source code directly into Java bytecode, streamlining the process and improving performance by over 4 times. This feature eliminates the intermediate steps previously required for code execution, resulting in faster compilation times and seamless integration with Java environments.

```mermaid
---
title: BoxLang Debug Compilation Flow
---
graph LR
    A[BoxLang Source] --> B[Java Source]
    B --> C[Java ByteCode]
```

The **JavaBoxPiler** will remain in BoxLang as it's an integral debugging piece. It might be moved later to it's own module, but having the capability to transpile BoxLang/CFML code to Java will remain.

```mermaid
---
title: BoxLang Production Compilation Flow
---
graph LR
    A[BoxLang Source] --> B[Java ByteCode]
```

The direct bytecode generation allows for enhanced optimization and leverages the full potential of Java's JVM, leading to more efficient and scalable applications. By default, right now this is an experimental feature and it will need to be turned ON in order to use it via our `boxlang.json` configuration, via the `compiler : "asm"`

```json5
// This is the experimental features flags.
// Please see the documentation to see which flags are available
"experimental": {
	// This choose the compiler to use for the runtime
	// Valid values are: "java", "asm"
	"compiler": "java",
	// If enabled, it will generate AST JSON data under the project's /grapher/data folder
	"ASTCapture": false
},
```

### [BL-232](https://ortussolutions.atlassian.net/browse/BL-232) Star-import for boxlang classes

You can now use `*` imports for BoxLang classes, which allows you to bring in all the classes found in the imported package into the class namespace so you can create them by just using their name. In practice, the use of star-imports is a trade-off between convenience and potential issues such as namespace collisions. While they can make code more concise, especially when many classes from a package are needed, they may also import unintended classes, leading to ambiguities. Therefore, it's generally recommended to use specific imports when only a few classes are required and reserve star-imports for when numerous classes from the same package are genuinely required.

```java
import cbvalidation.models.*;
import cbvalidation.models.result.*;

class accessors="true" serialize="false" singleton {

    ...
    // cbvalidation.models.GenericObject
    target = new GenericObject( arguments.target )
    
    ...

}
```

### [BL-653](https://ortussolutions.atlassian.net/browse/BL-653) Java wildcard imports from loaded jars

The feature [BL-653](https://ortussolutions.atlassian.net/browse/BL-653) enhances import capabilities by allowing Java wildcard imports from loaded JAR files. This means you can use the `*` notation to import all classes within a JAR package, reducing the need to import each class manually. This functionality streamlines the process of utilizing numerous classes within a package and is particularly beneficial when dealing with extensive libraries. However, similar to BoxLang star-imports, it is essential to be aware of possible namespace conflicts and ensure that unintended classes do not get imported, maintaining code clarity and preventing ambiguity.

```java
// Star-import of all classes in the package
import org.apache.commons.lang3.*;

class{
    
    function main( args=[] ){
        // Using StringUtils from Apache Commons Lang
        var reversed = StringUtils.reverse("BoxLang");
        println("Reversed: " + reversed);

        // Using RandomStringUtils from Apache Commons Lang
        var randomString = RandomStringUtils.randomAlphanumeric(10);
        println("Random String: " + randomString);
    }
}
```

### [BL-646](https://ortussolutions.atlassian.net/browse/BL-646) Ability to import/create BoxLang classes from modules via direct \`@{moduleName}\` notation.

The @ notation in BoxLang’s import system allows for more efficient and precise class referencing. By explicitly addressing classes from a specific module, performance is improved because it avoids the need for BoxLang to search through all available modules, reducing ambiguity in cases where classes with the same name exist in different modules. The module’s root serves as the base for addressing the class.

Here’s a breakdown of how it works:

```java
// Import from the cborm module
import models.ActiveEntity@cborm
target = new ActiveEntity()

// Import from the cborm module using aliases
import models.ActiveEntity@cborm as AC
target = new AC()
```

By using this method, developers can avoid potential issues like performance degradation due to unnecessary module scanning and the possibility of naming conflicts. It provides a clear and concise way to manage dependencies and class imports in BoxLang.

### [BL-647](https://ortussolutions.atlassian.net/browse/BL-647) Ability to import create java classes from modules explicitly using the \`@\`notation

Just like with BoxLang classes, you can also do the same for all Java libraries modules are packaged with. This allows you to import and create Java classes from specific modules by addressing them using the `@` notation.

```java
// Importing a specific class from the ESAPI Module
import org.owasp.esapi.ESAPI@bx-esapi
encoder = ESAPI.encoder()

// Importing and aliasing a class from the ESAPI library
import org.owasp.esapi.ESAPI@bx-esapi as SecurityAPI
encoder = SecurityAPI.encoder()

// Creating Java Classes
encoder = new java:org.owasp.esapi.reference.DefaultEncoder@bx-esapi();

```

The following were support tickets for all of these functionalities

* [BL-648](https://ortussolutions.atlassian.net/browse/BL-648) Import Definitions now support module addressing for simple, wildcard and aliases
* [BL-657](https://ortussolutions.atlassian.net/browse/BL-657) JavaResolver module targeted resolution

### [BL-658](https://ortussolutions.atlassian.net/browse/BL-658) MIgrate AST Capture to it's own experimental flag

If you want to capture AST JSON for debugging purposes you will need to activate the new AST experimental flag:

```json5
// This is the experimental features flags.
// Please see the documentation to see which flags are available
"experimental": {
	// This choose the compiler to use for the runtime
	// Valid values are: "java", "asm"
	"compiler": "java",
	// If enabled, it will generate AST JSON data under the project's /grapher/data folder
	"ASTCapture": true
},
```

### [BL-612](https://ortussolutions.atlassian.net/browse/BL-612) Add STOMP subprotocols in miniserver

We continue to make great strides with easy websocket support for BoxLang. Now we have added our very own STOMP implementation which makes our websockets behave like AMQP Messaging Brokers like RabbitMQ.

<https://community.ortussolutions.com/t/introducing-the-socketbox-stomp-broker-demo/10396>

## Improvements

[BL-328](https://ortussolutions.atlassian.net/browse/BL-328) Move `CFID` to compat module

[BL-637](https://ortussolutions.atlassian.net/browse/BL-637) Have servlet runtime return actual pagecontext object instead of fake

[BL-644](https://ortussolutions.atlassian.net/browse/BL-644) Update the `allowedFileOperationExtensions` and `disallowedFileOperationExtensions` to the security block

[BL-650](https://ortussolutions.atlassian.net/browse/BL-650) Allow casting to array of primitive types

[BL-652](https://ortussolutions.atlassian.net/browse/BL-652) Improve exception when trying to invoke null as a function

[BL-654](https://ortussolutions.atlassian.net/browse/BL-654) Get ColdBox Loading via ASM

[BL-655](https://ortussolutions.atlassian.net/browse/BL-655) Improve logic surrounding loading of pre-compiled source files

[BL-660](https://ortussolutions.atlassian.net/browse/BL-660) added a \`isCommitted()\` to the PageContext to match the servlet response to assist when doing resets without exceptions

[BL-661](https://ortussolutions.atlassian.net/browse/BL-661) StopGaps and config from cfconfig.json to boxlang.json

[BL-662](https://ortussolutions.atlassian.net/browse/BL-662) NotImplemented updated to check if it's a string and if empty, then ignore it to provide leeway

[BL-666](https://ortussolutions.atlassian.net/browse/BL-666) Rename default sessions cache to \`bxSessions\` to create the \`bx\` prefix standards. Add configuration to boxlang.json

## Bug

[BL-635](https://ortussolutions.atlassian.net/browse/BL-635) boxlang invokes private onApplicationStart

[BL-636](https://ortussolutions.atlassian.net/browse/BL-636) expandPath does not preserve file system case

[BL-639](https://ortussolutions.atlassian.net/browse/BL-639) cfml2wddx action missing

[BL-642](https://ortussolutions.atlassian.net/browse/BL-642) deserializeJSON not handling white space / control characters

[BL-645](https://ortussolutions.atlassian.net/browse/BL-645) Update parser to allow for \`@module\` notations on imports and \`new\` operators

[BL-649](https://ortussolutions.atlassian.net/browse/BL-649) listFind() and listFindNoCase() are allowing partial matches

[BL-651](https://ortussolutions.atlassian.net/browse/BL-651) Can't dump null in console

[BL-659](https://ortussolutions.atlassian.net/browse/BL-659) Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null


# 1.0.0-Beta27

January 31, 2025

This release brings **enhanced XML handling, new CLI app support, improved error handling, and expanded interoperability** with Java and CFML runtimes. We've also added **new HTTP event hooks, improved caching strategies, and a streamlined class resolution** process to make your applications more performant, even in debug modes.

#### 🌟 Highlights:

✅ **Enhanced XML Support** – Improved cloning, merging, and namespace handling in XML operations.\
✅ **Unified Template & Script Grammars** – BoxLang now seamlessly integrates both styles, bringing performance updates to the parser.\
✅ **Improved Java Interop** – Automatic coercion of BoxLang arrays to native Java arrays and `varargs` support.\
✅ **Better Error Handling** – More robust dump rendering and exception management.\
✅ **New CLI Features** – Built-in functions like `cliRead()`, `cliGetArgs()`, and `cliExit()` for pure CLI apps.\
✅ **Improved HTTP Handling** – Proxy support, authentication, and new request/response events.

✅ **Trusted Cache** – Trusted cache is in the house, to get high performance in production.

✅ **Class location caches** – More performance updates for class resolutions for BoxLang classes.

With **over 40 improvements, new features, and fixes**, this release makes BoxLang even more powerful and stable! 🔥

### Improvements

[BL-953](https://ortussolutions.atlassian.net/browse/BL-953) Implement Node pass-through methods to handle cloning and merging of XML objects

[BL-955](https://ortussolutions.atlassian.net/browse/BL-955) Combine template and script grammars for boxlang

[BL-956](https://ortussolutions.atlassian.net/browse/BL-956) Error Getting method keyExists for class ortus.boxlang.runtime.types.XML

[BL-958](https://ortussolutions.atlassian.net/browse/BL-958) StructFindKey returns two findings on the same node if top level key is array

[BL-959](https://ortussolutions.atlassian.net/browse/BL-959) Better error handling when dump template errors

[BL-964](https://ortussolutions.atlassian.net/browse/BL-964) Return callback return value from runThreadInContext()

[BL-966](https://ortussolutions.atlassian.net/browse/BL-966) java interop coerce BL arrays to native arrays

[BL-967](https://ortussolutions.atlassian.net/browse/BL-967) Add toOptional() method to Attempt

[BL-968](https://ortussolutions.atlassian.net/browse/BL-968) coerce return values of proxied methods

[BL-983](https://ortussolutions.atlassian.net/browse/BL-983) output class of non-simple valued fields in class output for cfdump

[BL-984](https://ortussolutions.atlassian.net/browse/BL-984) prefer same mapping for relative class lookups in box resolver

[BL-998](https://ortussolutions.atlassian.net/browse/BL-998) Client scope needs more consistencies like the session scope when validating and expiration determination

[BL-999](https://ortussolutions.atlassian.net/browse/BL-999) Module service record was not registering interceptors with the module settings

[BL-1002](https://ortussolutions.atlassian.net/browse/BL-1002) HTTP Component - Implement Proxy Server handling

[BL-1010](https://ortussolutions.atlassian.net/browse/BL-1010) add default itnerface helper for the IBoxContext to get the running application name if any

[BL-1013](https://ortussolutions.atlassian.net/browse/BL-1013) Servlet to support Jakarta namespace

### New Features

[BL-843](https://ortussolutions.atlassian.net/browse/BL-843) Move defaultCache to the caches section as default, verify it exists, else create it anyways

[BL-935](https://ortussolutions.atlassian.net/browse/BL-935) add http events: onHTTPRequest, onHTTPResponse

[BL-952](https://ortussolutions.atlassian.net/browse/BL-952) Expose buildRegistry() and encapsulate per location registration

[BL-989](https://ortussolutions.atlassian.net/browse/BL-989) CLI BIFS for working with pure cli apps: cliRead(), cliGetArgs(), cliExit()

[BL-1009](https://ortussolutions.atlassian.net/browse/BL-1009) Activate box resolvers cache according to request and app settings

[BL-1016](https://ortussolutions.atlassian.net/browse/BL-1016) New setting: classResolverCache : boolean \[true] which controls if the class locators caches resolve lookups

### Bugs

[BL-389](https://ortussolutions.atlassian.net/browse/BL-389) varargs not working

[BL-931](https://ortussolutions.atlassian.net/browse/BL-931) CF casts Class instances to a String

[BL-947](https://ortussolutions.atlassian.net/browse/BL-947) Namespaced XML nodes not accessible by their non-namespaced names

[BL-949](https://ortussolutions.atlassian.net/browse/BL-949) XMLSearch Not Finding Correct Results When Namespaces are Present

[BL-950](https://ortussolutions.atlassian.net/browse/BL-950) XML asString Generates trailing line break

[BL-951](https://ortussolutions.atlassian.net/browse/BL-951) StructFindKey Not Returning owner values correctly

[BL-960](https://ortussolutions.atlassian.net/browse/BL-960) ASM compilation error

[BL-961](https://ortussolutions.atlassian.net/browse/BL-961) query with empty column name can't be dumped

[BL-965](https://ortussolutions.atlassian.net/browse/BL-965) WriteDump()/Dump() is broken in current snapshot build

[BL-969](https://ortussolutions.atlassian.net/browse/BL-969) DateCompare on two zero-hour strings fails with long overflow

[BL-970](https://ortussolutions.atlassian.net/browse/BL-970) XMLElemNew Illegal Character exception when using the namespace URI as the second argument

[BL-977](https://ortussolutions.atlassian.net/browse/BL-977) HTTP Component - Implement Basic Authentication

[BL-978](https://ortussolutions.atlassian.net/browse/BL-978) Cannot access variables scope in a static context -- but there is no variables access

[BL-981](https://ortussolutions.atlassian.net/browse/BL-981) timezone not always used in datetime caster

[BL-982](https://ortussolutions.atlassian.net/browse/BL-982) toUnmodifiableStruct() method not threadsafe

[BL-985](https://ortussolutions.atlassian.net/browse/BL-985) directoryList filter param does not accept a closure

[BL-991](https://ortussolutions.atlassian.net/browse/BL-991) Support for guid and uuid type

[BL-994](https://ortussolutions.atlassian.net/browse/BL-994) getDirectoryFromPath returns different result to Lucee and ACF

[BL-995](https://ortussolutions.atlassian.net/browse/BL-995) argument type of binary is not supported

[BL-996](https://ortussolutions.atlassian.net/browse/BL-996) argument type of email is not supported

[BL-1000](https://ortussolutions.atlassian.net/browse/BL-1000) CGI scope reporting 0 items

[BL-1003](https://ortussolutions.atlassian.net/browse/BL-1003) JSONSerialize pretty prints JSON which blows up outbound NDJSON

[BL-1004](https://ortussolutions.atlassian.net/browse/BL-1004) CFHTTParam Encodes Query Strings By Default

[BL-1005](https://ortussolutions.atlassian.net/browse/BL-1005) URLEncodedFormat Replaces Spaces with Plus Symbols

[BL-1015](https://ortussolutions.atlassian.net/browse/BL-1015) Bracket Notation Usage on Java Hashmaps Does not work.

[BL-1017](https://ortussolutions.atlassian.net/browse/BL-1017) Detail and Extended Info Can Be Null In Thrown Exceptions


# 1.0.0-Beta18

This release introduces several new features and configurations to enhance functionality and security. It also continues to squash tons of bugs to bring about CFML compatibility. Key updates include:

* Enhanced `arrayFind` and `arrayFindNoCase` functions, allowing value closures to accept item indices.
* New `validBoxLangTemplates` configuration for filtering templates processable by the Runnable Loader.
* New `validClassExtensions` configuration to specify permissible class extensions.
* A new `security` configuration section designed to disallow BIFs, Components, and Imports, enhancing security.

## New Feature

[BL-617](https://ortussolutions.atlassian.net/browse/BL-617) `arrayFind`, `arrayFindNoCase` value closures, accept the value and now the index of the item as the second param

[BL-626](https://ortussolutions.atlassian.net/browse/BL-626) New configuration: `validBoxLangTemplates` to determine which templates the Runnable Loader can process

[BL-627](https://ortussolutions.atlassian.net/browse/BL-627) New configuration: `validClassExtensions` to determine which class extensions to work with

[BL-629](https://ortussolutions.atlassian.net/browse/BL-629) New `security` configuration section for disallowing: BIFS, Components, Imports

[BL-630](https://ortussolutions.atlassian.net/browse/BL-630) Internal refactor to make the class locator and resolvers have a life-cycle based on the runtime and not alone

## Improvement

[BL-611](https://ortussolutions.atlassian.net/browse/BL-611) Remove debugmode capture on miniserver, delegate to the core runtime.

[BL-622](https://ortussolutions.atlassian.net/browse/BL-622) Consolidate `CastAttempt` and `Attempt` into a hierarchy

[BL-623](https://ortussolutions.atlassian.net/browse/BL-623) New `DynamicFunction` type that can be used to generate dynamic BoxLang functions using Java Lambda proxies. Great for code generation

## Bug

[BL-614](https://ortussolutions.atlassian.net/browse/BL-614) Import nested classes

[BL-615](https://ortussolutions.atlassian.net/browse/BL-615) Java static funcitons not behaving as expected

[BL-616](https://ortussolutions.atlassian.net/browse/BL-616) array.find does not use cf rules to convert result of predicate to boolean

[BL-619](https://ortussolutions.atlassian.net/browse/BL-619) QueryColumnType doesn't handle "idstamp" (mssql)

[BL-620](https://ortussolutions.atlassian.net/browse/BL-620) static scope in application.cfc not initialized before psuedoConstructor runs

[BL-624](https://ortussolutions.atlassian.net/browse/BL-624) Auto-escaping of {} in regex needs to ignore already-escaped braces

[BL-625](https://ortussolutions.atlassian.net/browse/BL-625) Instead of removing special chars from Java FQN, replace with \_\_ to avoid conflicts

[BL-628](https://ortussolutions.atlassian.net/browse/BL-628) Tag expressions not parsing inside template island inside braces

[BL-631](https://ortussolutions.atlassian.net/browse/BL-631) duplicate() doesn't work on empty structs

[BL-633](https://ortussolutions.atlassian.net/browse/BL-633) randrange() not inclusive of upper bound

[BL-634](https://ortussolutions.atlassian.net/browse/BL-634) array.find - can't cast closure to string


# 1.0.0-Beta17

October 4th, 2024

In this release, we've introduced the exciting addition of websockets support to BoxLang through the powerful [SocketBox](https://forgebox.io/view/socketbox) module. This enhancement is not limited to our [CommandBox](/getting-started/running-boxlang/commandbox) Runtime but also extends to our [MiniServer](/getting-started/running-boxlang/miniserver) runtime, creating a more dynamic and efficient framework for real-time communication. For an in-depth introduction to these features, please visit our community post [here](https://community.ortussolutions.com/t/introducing-socketbox-a-new-websocket-library/10381/4).

Additionally, we've implemented several new features and improvements. We've also improved the system startup process by adding version and build date information to the MiniServer startup output ([BL-607](https://ortussolutions.atlassian.net/browse/BL-607)). Lastly, we've addressed session management by ensuring that application settings are readily accessible during the `onSessionEnd` event ([BL-610](https://ortussolutions.atlassian.net/browse/BL-610)). This release encapsulates our ongoing commitment to providing robust, cutting-edge solutions for developers and reaching stable release in the coming weeks.

## New Features

[BL-605](https://ortussolutions.atlassian.net/browse/BL-605) MiniServer WebSocket handler

## Improvement

[BL-607](https://ortussolutions.atlassian.net/browse/BL-607) Add version/build date to output of Miniserver startup

[BL-610](https://ortussolutions.atlassian.net/browse/BL-610) onSessionEnd needs application settings made available

[BL-611](https://ortussolutions.atlassian.net/browse/BL-611) Remove debugmode capture on miniserver, delegate to the core runtime.

## Bugs

[BL-608](https://ortussolutions.atlassian.net/browse/BL-608) Timeouts (connection, idle) for datasources needs to be in seconds and not in milliseconds to adhere to cfconfig

[BL-609](https://ortussolutions.atlassian.net/browse/BL-609) BoxLang resolvers do not allow class paths to have \`-\` in them.


# 1.0.0-Beta16

Welcome to Beta 16! This release focuses on web support functionality and contains a number of improvements and bug fixes for HTTP operations, including multi-part file uploads and error handling. It also provides enhancements to Java interoperability, dump template output, and metadata introspection.

Overall, this beta release brings further stability for CFML applications migrating to BoxLang!

## Release notes - BoxLang - 1.0.0-Beta16

#### New Feature

[BL-603](https://ortussolutions.atlassian.net/browse/BL-603) Implement timeout for HTTP requests

[BL-604](https://ortussolutions.atlassian.net/browse/BL-604) Multi-part request support in HTTP

#### Improvement

[BL-586](https://ortussolutions.atlassian.net/browse/BL-586) Add text-based toString() method for Queries (used in console dumps)

[BL-589](https://ortussolutions.atlassian.net/browse/BL-589) for in Java transformer not mapping source line numbers for start of loop

[BL-590](https://ortussolutions.atlassian.net/browse/BL-590) Make include case insensitive

[BL-596](https://ortussolutions.atlassian.net/browse/BL-596) Enhance metadata visitor to process extends

[BL-597](https://ortussolutions.atlassian.net/browse/BL-597) add fieldNames key to form scope

[BL-599](https://ortussolutions.atlassian.net/browse/BL-599) Auto casting for URI and URL classes to string

[BL-600](https://ortussolutions.atlassian.net/browse/BL-600) Handle bad gateways in HTTP component

[BL-601](https://ortussolutions.atlassian.net/browse/BL-601) Allow for multiple form fields with the same name in HTTP component

[BL-602](https://ortussolutions.atlassian.net/browse/BL-602) autocast InetSocketAddress to string

#### Bug

[BL-584](https://ortussolutions.atlassian.net/browse/BL-584) Fix for overeager escaping of quantifier sequences in REFind

[BL-585](https://ortussolutions.atlassian.net/browse/BL-585) High order closures creating incorrect AST when parsing

[BL-587](https://ortussolutions.atlassian.net/browse/BL-587) Update DateTime Parsing to handle the Common Javascript Date.toString format

[BL-588](https://ortussolutions.atlassian.net/browse/BL-588) Module settings no longer overriding after deep merge function added

[BL-591](https://ortussolutions.atlassian.net/browse/BL-591) Java interop doesn't find method by argument types when passing null

[BL-592](https://ortussolutions.atlassian.net/browse/BL-592) Can't assign to List due to incorrect validation in referencer

[BL-593](https://ortussolutions.atlassian.net/browse/BL-593) content-type isn't always getting defaulted in some requests

[BL-594](https://ortussolutions.atlassian.net/browse/BL-594) for/in loop over struct should get String keys instead of BL Key instances

[BL-595](https://ortussolutions.atlassian.net/browse/BL-595) showUDFs not cascading down in dump levels

[BL-598](https://ortussolutions.atlassian.net/browse/BL-598) using cfcookie should update cookie scope

[BL-606](https://ortussolutions.atlassian.net/browse/BL-606) Fix argument order for FileUpload


# 1.0.0-Beta15

September 20, 2024

Welcome to Beta 15! This release brings several significant enhancements aimed at improving the efficiency and functionality of the CLI environment and continued bug fixing to bring our CFML compatibility to several client applications and Ortus Libraries. Key among these is the introduction of the `bx-web-support` module, which allows the CLI to interface with web server capabilities, making it an excellent tool for testing and feature auditing. Additionally, the merge capabilities within module settings have been refined to support deep merges from the configuration file, ensuring greater flexibility and control.

Moreover, running scripts or classes via CLI execution now supports the automatic detection and execution of `Application.bx|cfc`, streamlining the process for developers. The new `ToString` dump template enhances debugging by enabling a concise display format for lists of Java objects, simplifying the analysis and debugging process.

Overall, this beta release brings further stability for CFML applications migrating to BoxLang!

## New Features

### [BL-544](https://ortussolutions.atlassian.net/browse/BL-544) Look and execute for Application.bx|cfc when running scripts or classes via CLI execution

We have always wanted even further CLI enhancements for applications built with BoxLang. Now you get it! BoxLang will look for an `Application.bx|cfc` whenever it executes a template or class and follow the process of application startup, settings, ORM, etc. The full life-cycle of an application but at the CLI level. This will allow you to completely test your web applications with no web server and even build CLI applications with easy application constructs!

### [BL-559](https://ortussolutions.atlassian.net/browse/BL-559) New bx-web-support module to support the CLI with web server capabilities. Great for testing, mocking and feature audits.

We have released the `bx-web-support` module which will give you mocking, testing and auditing capabilities for CLI testing and runners. This means that your CLI applications will look and feel like a real web application with a real web server, but using our mock approaches.

This module is still in it's alpha stages so expect much more development on it.

### [BL-574](https://ortussolutions.atlassian.net/browse/BL-574) Module settings should have a deep merge from the configuration file

All module settings in your `boxlang.json` can now be deeply merged automatically by BoxLang.

### [BL-580](https://ortussolutions.atlassian.net/browse/BL-580) Add a new ToString dump template that will take a list of java objects to display them in short hand format

We will be easing the visibility of certain human readable Java classes in our dump templates.

### [BL-581](https://ortussolutions.atlassian.net/browse/BL-581) Handle single values in arrayAppend merge=true

A nice feature to support further merging techniques with arrays.

## Improvements

[BL-503](https://ortussolutions.atlassian.net/browse/BL-503) dump improvement of UI when using expand/collapse

[BL-545](https://ortussolutions.atlassian.net/browse/BL-545) Show errors in class pseudo constructor in tag context

[BL-555](https://ortussolutions.atlassian.net/browse/BL-555) List utils need to trim all values when converting to arrays

[BL-558](https://ortussolutions.atlassian.net/browse/BL-558) LocalDateTime not showing in dumps as a date/time string, but as a Java Object

[BL-567](https://ortussolutions.atlassian.net/browse/BL-567) Update date/time and instant dump templates to be less verbose and more functional

[BL-569](https://ortussolutions.atlassian.net/browse/BL-569) Allow CF tag islands and template islands to be nested more than one level deep.

[BL-570](https://ortussolutions.atlassian.net/browse/BL-570) Merge CF lexer and grammar for faster parsing and more accurate lexing

[BL-571](https://ortussolutions.atlassian.net/browse/BL-571) Make tag expression parsing smarter

[BL-576](https://ortussolutions.atlassian.net/browse/BL-576) expandPath() must ignore invalid paths, just returning the input

[BL-579](https://ortussolutions.atlassian.net/browse/BL-579) More IO BIFs need to ignore invalid paths

## Bugs

[BL-434](https://ortussolutions.atlassian.net/browse/BL-434) script block parsing can be tricked by comments

[BL-546](https://ortussolutions.atlassian.net/browse/BL-546) Lucee allows properties to be anywhere in the pseduoconstructor of a class, not just at the top

[BL-547](https://ortussolutions.atlassian.net/browse/BL-547) flush component only flushes up one buffer, not all the way

[BL-550](https://ortussolutions.atlassian.net/browse/BL-550) Boxlang doesn't parse milliseconds in datetime string

[BL-551](https://ortussolutions.atlassian.net/browse/BL-551) Date "string" doesn't have date time member functions available

[BL-552](https://ortussolutions.atlassian.net/browse/BL-552) Querynew failing with more than one column defined

[BL-553](https://ortussolutions.atlassian.net/browse/BL-553) Regular Expression Syntax not supported

[BL-557](https://ortussolutions.atlassian.net/browse/BL-557) Metadata visitor doesn't support struct annotations with unquoted keys

[BL-561](https://ortussolutions.atlassian.net/browse/BL-561) Hyper module failing

[BL-562](https://ortussolutions.atlassian.net/browse/BL-562) bx-compat cfloop requires "index" when it shouldn't

[BL-563](https://ortussolutions.atlassian.net/browse/BL-563) transaction shouldn't require global DSN

[BL-564](https://ortussolutions.atlassian.net/browse/BL-564) cfproperty tag lucee allows non quoted properties

[BL-565](https://ortussolutions.atlassian.net/browse/BL-565) Class name sensitivity based on provided rather than class found

[BL-566](https://ortussolutions.atlassian.net/browse/BL-566) No reading dump templates due to pathing incorrectly in debug mode

[BL-568](https://ortussolutions.atlassian.net/browse/BL-568) Static support not compatible with CFML

[BL-572](https://ortussolutions.atlassian.net/browse/BL-572) javacast not actually casting as expected

[BL-573](https://ortussolutions.atlassian.net/browse/BL-573) functions in variables scope vs values in variables scope

[BL-575](https://ortussolutions.atlassian.net/browse/BL-575) bx-compat unquoted hashed expressions cause compiler error

[BL-577](https://ortussolutions.atlassian.net/browse/BL-577) serializeJSON errors when serializing a function

[BL-578](https://ortussolutions.atlassian.net/browse/BL-578) Sentinel loop with missing expressions fails

[BL-582](https://ortussolutions.atlassian.net/browse/BL-582) mid() It does not remove characters if the count is more than the length

[BL-583](https://ortussolutions.atlassian.net/browse/BL-583) Cannot invoke "ortus.boxlang.runtime.types.IStruct.putAll(java.util.Map)" because "recipient" is null


# 1.0.0-Beta14

September 13, 2024

In this release, we are excited to introduce several new features and enhancements aimed at improving functionality and user experience. These updates include the creation of Unmodifiable query types, new server keys to aid on CLI tooling, and methods to identify runtime initiation modes.

Additionally, we've added an event announcement for dump rendering to enable better integration with external listeners. Read on to learn more about these features and how they can benefit your workflow.

Code Strong!

## New Features

### [BL-542](https://ortussolutions.atlassian.net/browse/BL-542) BoxRunner cli options are now prefixed with \`--bx-{option}\`

This is a breaking change in our betas. All the CLI options for the `BoxRunner` now use the `--bx-` prefix. We are doing this to avoid any issues going forward when building CLI tooling. Pleaes checkout the [Running Boxlang](/getting-started/running-boxlang) section for all the docs on this.

### [BL-93](https://ortussolutions.atlassian.net/browse/BL-93) Create Unmodifiable query type

We have now introduced the Unmodifiable query type. Any query in BoxLang can become Unmodifiable by just calling the `toUnmodifiable()` method on it. This will lock the query into read-only mode. Great for multi-threaded operations or just data safety. You can also unlock Unmodifiable types via the `toMutable()` method.

```cfscript
// Just call the toUnmodifiable() to lock the type
myData = myDataService.queryData().toUnmodifiable()

// You can also unlock it via the toMutable() method
unlockedData = myData.toMutable()
```

### [BL-529](https://ortussolutions.atlassian.net/browse/BL-529) Announce the onBXDump whenever a dump is about to be rendered, to allow for external listeners to receive the dump

We have added a new global listener for the language: `onBxDump` which allows you to listen to any call to our dump component. This will allow developers to tap into the dumping facilities and intercept the dump calls. We are doing this in order to bring real-time dump facilities to VSCode.

```cfscript
function onBxDump( data ){
  .. listen to the dump call
}
```

All the arguments from the `dump` bif/component will be passed through.

### [BL-538](https://ortussolutions.atlassian.net/browse/BL-538) New runtime inCLIMode() method to tell you if the runtime was started via the runtime or something else

This is a new method in the `BoxRuntime` which allows developers or module authors to know if your runtime is in CLI mode or not. The `server.boxlang` also contains much more information about the modes you are in:

* `server.boxlang.cliMode` - True or false if you are in CLI mode
* `server.boxlang.jarMode` - True or false if running in JAR mode
* `server.boxlang.runtimeHome` - The runtime home seeded in the runtime

### [BL-539](https://ortussolutions.atlassian.net/browse/BL-539) New server.cli key to provide you with all the CLI options used to run the runtime

There is a new `server.cli` structure that will assist CLI developers. It contains the following data:

* `server.cli.executionPath` - From what directory was the runtime command called from
* `server.cli.command` - The full raw commandline string used by the OS to call the binary + your command
* `server.cli.args` - The raw array of arguments the command was called with
* `server.cli.parsed.options` - A struct of name-value pairs of all the options detected in the CLI arguments.
* `server.cli.parsed.positionals` - An array of positional arguments sent to the CLI

BoxLang will detect and parse the following conditions into the `options` struct:

* `--{name}` - Will crete a key called `{name}` with a value of `true`
* `--!{name}` - Will crete a key called `{name}` with a value of `false`
* `--no-{name}` - Will crete a key called `{name}` with a value of `false`
* `-{character}` - Shorthands using a single character. The value will be `true` and the key will be the character used. Example: `-p`
* `-{characters}` - You can use multi-shorthand characters and each of them will be keys in the struct with a value of `true`. Example: `-abc` will create `a=true, b=true, c=true`
* `--{name}=value` - Will create a key called `{name}` with the value from the right side of the equals sign.
* `--{name}="value"` - Will create a key called `{name}` with the value from the right side of the equals sign and removing the quotes.
* `--{name}='value'` - Will create a key called `{name}` with the value from the right side of the equals sign and removing the single quotes

### [BL-540](https://ortussolutions.atlassian.net/browse/BL-540) Refactor the CLIOptions to it's own class and add a simple argument parser

In preparation to the inclusion of CommandBox commands into BoxLang we have also added our CLI utility to assist with argument parsing and detection. We have also encapsulated our CLI tooling in preparation for more in the next betas.

## Improvements

[BL-228](https://ortussolutions.atlassian.net/browse/BL-228) Consolidate/Rename "LS" Bifs and Move US-Centric ones to Compat

[BL-409](https://ortussolutions.atlassian.net/browse/BL-409) Member method cleanup

[BL-410](https://ortussolutions.atlassian.net/browse/BL-410) Improve REPL output of native Java arrays

[BL-541](https://ortussolutions.atlassian.net/browse/BL-541) Add "decimal" as a cast type

## Bugs

[BL-496](https://ortussolutions.atlassian.net/browse/BL-496) replace and replaceNoCase functions do not accept a callback

[BL-519](https://ortussolutions.atlassian.net/browse/BL-519) Query dereferencing is not working correctly: Column '1' does not exist in query

[BL-520](https://ortussolutions.atlassian.net/browse/BL-520) Run Class via URL

[BL-523](https://ortussolutions.atlassian.net/browse/BL-523) A class which uses inheritance, the metadata includes the inherited functions in itself and parent.

[BL-524](https://ortussolutions.atlassian.net/browse/BL-524) reFindNoCase( "^(f|x)?test$", arguments.methodName ) fails with Cannot invoke "String.length()" because the return value of "java.util.regex.Matcher.group(int)" is null

[BL-525](https://ortussolutions.atlassian.net/browse/BL-525) lsParseDateTime errors when given locale and mask

[BL-526](https://ortussolutions.atlassian.net/browse/BL-526) dateformat incorrectly parsing date with leading 0's?

[BL-527](https://ortussolutions.atlassian.net/browse/BL-527) onMissingMethod is not firing if the execution of the method is from within the class

[BL-528](https://ortussolutions.atlassian.net/browse/BL-528) query dumps assume the value is simple and can explode with encodeForHTML() can't do complex objects

[BL-530](https://ortussolutions.atlassian.net/browse/BL-530) Improve tracking of class in function box context

[BL-531](https://ortussolutions.atlassian.net/browse/BL-531) Difference of behavior with cfdirectory recurse = true not including path

[BL-532](https://ortussolutions.atlassian.net/browse/BL-532) super long strings cause compilation errors due to limitations in Java source code

[BL-533](https://ortussolutions.atlassian.net/browse/BL-533) Errors in miniserver when flushing large amounts of output to buffer

[BL-534](https://ortussolutions.atlassian.net/browse/BL-534) Missing !== operator

[BL-535](https://ortussolutions.atlassian.net/browse/BL-535) query cell assign erroring

[BL-537](https://ortussolutions.atlassian.net/browse/BL-537) Add onBifInvocation Interception Announcement to BIF invoke method


# 1.0.0-Beta13

September 6, 2024

This release introduces several new features aimed at enhancing the usability and functionality of BoxLang. We have closed a tremendous amounts of bugs on this release in order to bring more compatibility and stability to BoxLang. We have also started to introduce performance enhancements and more innovations as we progress towards final release.

Enjoy!

## New Features

### [BL-142](https://ortussolutions.atlassian.net/browse/BL-142) Writedump output support

We have finalized the `console` output for the dump component, but we have also added the following ticket:

[BL-508](https://ortussolutions.atlassian.net/browse/BL-508) New dump event to listen when an non-core output is detected so modules can handle it. `onMissingDumpOutput`

Which will allow module developers to collaborate their own output destinations for any dump in the language. This is something we have wanted for years and it's now a possibility. Just listen to the `onMissingDumpOutput` interception point, you get all the arguments to the BIF or component and you decide where things will go. VScode Dump Panel, here we come.

The `console` output has also been enhanced where everything will be pretty printed, including labels.

### [BL-489](https://ortussolutions.atlassian.net/browse/BL-489) Ability to mark a @BoxBif as excluded from documentation

This is more of an internal documentation process for the team.

### [BL-504](https://ortussolutions.atlassian.net/browse/BL-504) New dump template for Java instants

Java Instants will now be dumped nicely with an internal representation and a human readable representation.

### [BL-507](https://ortussolutions.atlassian.net/browse/BL-507) dump showUDFs

All the arguments for dumps are now available including this one for controlling the dumping of UDFs on classes.

## Improvements

[BL-497](https://ortussolutions.atlassian.net/browse/BL-497) Simplify BoxLang class dumps

[BL-499](https://ortussolutions.atlassian.net/browse/BL-499) Add output and format to dump

[BL-501](https://ortussolutions.atlassian.net/browse/BL-501) Some BIFs not fully supporting BigDecimal values

[BL-517](https://ortussolutions.atlassian.net/browse/BL-517) access e.cause as shortcut for e.getCause()

[BL-518](https://ortussolutions.atlassian.net/browse/BL-518) When creating an abstract class a new \`AbstractClassException\` is thrown. Great for testing frameworks

## Bugs

[BL-223](https://ortussolutions.atlassian.net/browse/BL-223) queryaddcolumn ignores the datatype

[BL-471](https://ortussolutions.atlassian.net/browse/BL-471) Issue with #dateTimeFormat(now(),'mm-dd-yyyy')# function returning incorrect results

[BL-492](https://ortussolutions.atlassian.net/browse/BL-492) structnew( "linked" ) doesn't work

[BL-493](https://ortussolutions.atlassian.net/browse/BL-493) argumentCollection doesn't work with implicit constructor

[BL-494](https://ortussolutions.atlassian.net/browse/BL-494) directory component must always return query

[BL-498](https://ortussolutions.atlassian.net/browse/BL-498) BoxNewTransformer using hard-coded context name

[BL-500](https://ortussolutions.atlassian.net/browse/BL-500) toNumeric() not accepting radix values of 2-36

[BL-502](https://ortussolutions.atlassian.net/browse/BL-502) cannot cast \[x to object] on generic caster when using \`QuerySetCell()\`

[BL-505](https://ortussolutions.atlassian.net/browse/BL-505) Issue with \`Duplicate()\` Function Causing Null Pointer Exception in BoxLang

[BL-506](https://ortussolutions.atlassian.net/browse/BL-506) final keyword not working on this scope

[BL-509](https://ortussolutions.atlassian.net/browse/BL-509) directoryList() filters are not working as closures/lambdas as they are hardcoded as strings

[BL-510](https://ortussolutions.atlassian.net/browse/BL-510) Cannot invoke "ortus.boxlang.runtime.types.Query.isEmpty()" because "this.query" is null

[BL-511](https://ortussolutions.atlassian.net/browse/BL-511) Multiple pipe-delimited glob patterns are not working as directoryList filters

[BL-512](https://ortussolutions.atlassian.net/browse/BL-512) DuplicationUtil not doing deep clones of structs according to all types

[BL-513](https://ortussolutions.atlassian.net/browse/BL-513) Throwing custom type exceptions just shows \`custom\` as the type instead of the actual type in the throw

[BL-514](https://ortussolutions.atlassian.net/browse/BL-514) remote access not treated as public but as private for functions

[BL-515](https://ortussolutions.atlassian.net/browse/BL-515) Interfaces don't support multiple inheritance

[BL-516](https://ortussolutions.atlassian.net/browse/BL-516) CFC source type not detected correctly for abstract or final classes

[BL-521](https://ortussolutions.atlassian.net/browse/BL-521) Metadata with : in them in cfml mode not treated correctly

[BL-522](https://ortussolutions.atlassian.net/browse/BL-522) xml entity parsing issue when calling \`toString()\` on Java objects


# 1.0.0-Beta12

This update contains 9 features and improvements and 8 bug fixes.

### New Features

* [BL-438](https://ortussolutions.atlassian.net/browse/BL-438) - Zip Components, Utility and incorporating BIFS
* [BL-487](https://ortussolutions.atlassian.net/browse/BL-487) - Implement `pagePoolClear()`
* [BL-491](https://ortussolutions.atlassian.net/browse/BL-491) - Add the ability to configure the CF transpiler
* [BL-490](https://ortussolutions.atlassian.net/browse/BL-490) - Transpiler doesn't handle attributeCollection
* [BL-438](https://ortussolutions.atlassian.net/browse/BL-438) - Zip Components, Utility and incorporating BIFS

### Improvements

* [BL-486](https://ortussolutions.atlassian.net/browse/BL-486) - Compiler thread safety
* [BL-485](https://ortussolutions.atlassian.net/browse/BL-485) - Implements SystemCacheClear()
* [BL-483](https://ortussolutions.atlassian.net/browse/BL-483) - Allow "object" passed to throw to be a struct representation of an exception
* [BL-480](https://ortussolutions.atlassian.net/browse/BL-480) - Added all missing boxlang types to `BoxLangType` class
* [BL-479](https://ortussolutions.atlassian.net/browse/BL-479) - Address parser performance by limiting operator reserved words
* [BL-478](https://ortussolutions.atlassian.net/browse/BL-478) - Change template parsers to use SLL prediction mode
* [BL-477](https://ortussolutions.atlassian.net/browse/BL-477) - Improve parsing performance by only calculating lines of code on error
* [BL-474](https://ortussolutions.atlassian.net/browse/BL-474) - Add ValueRequiresOneOf Validator

### Bugs

* [BL-484](https://ortussolutions.atlassian.net/browse/BL-484) - Lock expects timeout to be minimum of 1
* [BL-481](https://ortussolutions.atlassian.net/browse/BL-481) - numeric literals with leading zeros are confused with octal values in java source
* [BL-482](https://ortussolutions.atlassian.net/browse/BL-482) - getApplicationMetadata() fails before application listener is defined
* [BL-476](https://ortussolutions.atlassian.net/browse/BL-476) - AST string values incorrectly unescaped outside of cfoutput
* [BL-475](https://ortussolutions.atlassian.net/browse/BL-475) - Pretty printer incorrect for default case ending tag


# 1.0.0-Beta11

August 23, 2024

We have really kicked into gear with this release, tackling a whopping 26 tickets and delivering some of our most aggressive features to date. This update signifies a significant leap forward towards a stable release in the Fall. Thank you for your continued support and stay tuned for more exciting developments!

## New Features

### [BL-236](https://ortussolutions.atlassian.net/browse/BL-236) Phase I : Performance improvements for grammar and parser validation

We have been working with an amazing ANTLR expert: Jim Idle, and we have been able now after several months of hard work to merge in a complete update to our parsers. **This has a massive performance increase between 5-10 times more performant than before.** However, we are still not those, we have three more performance phases coming up!

### [BL-91](https://ortussolutions.atlassian.net/browse/BL-91) Support numeric literal separators in source code

We’ve added a small, but useful syntax to our BoxLang parser that comes from multiple other languages. Numeric placeholders allow you to place underscore characters (`_`) inside of a numeric literal for readability. Take a number like this

```ini
n = 1000000000
```

That’s 1 billion. Or was it 1 million? Or maybe it was 100 million… *pauses to re-count*.\
With numeric place holders, your code can look like this:

```ini
n = 1_000_000_000
```

Ahh, so it *was* 1 billion! There’s no rules on where you can place the underscores, so long as they are INSIDE the number and not leading or trailing. Heck, this is valid (though pointless):

```ini
n = 1_0_0_0_0_0_0_0_0_0
```

You can also place numeric separators in decimals

```ini
n = 3.141_592_653_59
```

and in the exponent of scientific notation

```undefined
1e2_345
```

These underscores are simply thrown away at compile time. They are not represented in the bytecode and will not appear anywhere in your running app. They are purely for readability in your source code.

### [BL-457](https://ortussolutions.atlassian.net/browse/BL-457) Add static assignment modifier

You can now use the `static` assignment modifier in your code:

```java
static foo = "bar"
```

which is sugar for

```java
static.foo = "bar"
```

and validate at runtime there is actually a static scope, or throw an exception.

### [BL-458](https://ortussolutions.atlassian.net/browse/BL-458) Add final modifier to classes

You can now use the `final` modifier in your classes

```java
final class {}
```

which is sugar for:

```java
class final {}
```

This means that your classes will not be able to be inherited from.

### [BL-459](https://ortussolutions.atlassian.net/browse/BL-459) final modifier for UDFs

Your UDFs can now also be declared as `final`

```java
final function foo() {
}
```

which will set the function as `final` into the scope it gets registered into. Any additional function declarations with the same OR ATTEMPTS TO SET A VARIABLE OF THAT NAME will result in an **error**.

```java
final function foo() {}
foo = "brad" // exception because foo is final
```

### [BL-460](https://ortussolutions.atlassian.net/browse/BL-460) Add final assignment modifier for variables

You can now add `final` assignment modifers to variables in your code:

```java
final foo = "bar"
```

this, of course, can be used with other modifiers

```java
final static foo = "bar"
final var foo = "baz"
```

The only 2 modifiers that can’t be used together are `var` and `static` since they represent different scopes.

When a variable is declared as `final`, the scope it is being set into will track a list of keys that are designated as `final`, and will prevent those keys from being modified in the future.

This is ONLY a feature of scopes. Structs and other struct-like container will not have a final concept.

The following example

```java
final lockDown = [ 1, 2, 3 ].toUnmodifiable()
```

cannot be mutated OR re-assigned.

***

You can see the Set of final keys for a scope via the meta object

```
variables.$bx.meta.finalKeySet
```

You can also remove keys from the set to make a variable no longer final.

```java
final foo = "bar"
variables.$bx.meta.finalKeySet.clear() // Nothing is final in this scope now
foo = "baz" // no error

```

### [BL-469](https://ortussolutions.atlassian.net/browse/BL-469) DynamicInterop now filters non-callable methods when invoking and matching thus accelerating lookups considerably

This is a major update to our dynamic invocation with Java interop. We know only look at callable methods, where as before we looked at every single method on Java classes. This is a significant boost in performance when doing invocations and well, it also fixes a bug on ambiguity between same named methods with different visibility scopes. Relax and ride the lightning :zap:

### [BL-438](https://ortussolutions.atlassian.net/browse/BL-438) Zip Utility & compress(), extract(), isZipFile() bifs

BoxLang now speaks Zip language. We have added `zip` and `gzip` capabilities to the core. This will allow us to leverage compression and extraction for modular activites, jar installations, logging, and much more. We have also created the following BIFS available to you:

* `compress( format, source, destination, [includeBaseFolder=true], overwrite=false )` - Compress a source to a destination using available compression formats.
* `extract( format, source, destination, [overwrite=false], [recurse=true], [filter], [entryPaths] )` - Extract a zip/gzip archive to a destination with nice options.
* `isZipFile( filepath )` : Determines if the passed file can be treated as a zip archive.

We support the following formats:

* `zip`
* `gzip`

More formats will be available for our +/++ subscribers.

Please note also that the `filter` arguments can be the following:

* A valid regular expression string: `".*\.txt"`
* A BoxLang closure or lambda `(name) => name.endsWith(".txt")`
  * Receives the full path of the entry
* A Java Predicate: `(entry) -> entry.getName().endsWith(".txt")`
  * Receives the `ZipEntry` object

In our next betas we will have a the `Zip` component which will allow you to do the following:

* Compress Files
* Extract Files
* List File Entries
* Delete File Entries
* Read File Entries
* Read Binary File Entries
* Much More.

### [BL-447](https://ortussolutions.atlassian.net/browse/BL-447) java.math.BigInteger caster

We had a `BigDecimal` caster, now we have a `BigInteger` caster. Not only that, we can correctly coerce Java interop calls for BigDecimal and BigInteger.

## Improvements

[BL-433](https://ortussolutions.atlassian.net/browse/BL-433) Allow the incorrect foo..bar syntax that Adobe allows for

[BL-446](https://ortussolutions.atlassian.net/browse/BL-446) Cache sets() and getOrSets() does not accept duration in seconds alongside Duration objects.

[BL-455](https://ortussolutions.atlassian.net/browse/BL-455) Enhance ClassMetadataVisitor

[BL-468](https://ortussolutions.atlassian.net/browse/BL-468) Enhance feature audit to track QoQ separate

[BL-456](https://ortussolutions.atlassian.net/browse/BL-456) Validate var outside of a function

[BL-463](https://ortussolutions.atlassian.net/browse/BL-463) Support Adob'e loose comma parsing in their generic tag-in-script syntax

[BL-465](https://ortussolutions.atlassian.net/browse/BL-465) Enhance errors for identifiers starting with numbers

[BL-470](https://ortussolutions.atlassian.net/browse/BL-470) File And Directory BIFs to auto-expand received paths

[BL-431](https://ortussolutions.atlassian.net/browse/BL-431) Support variable starting with number

## Bugs

[BL-461](https://ortussolutions.atlassian.net/browse/BL-461) Compatible encryption with lucee/acf

[BL-462](https://ortussolutions.atlassian.net/browse/BL-462) replace() and replaceNoCase() should accept "one" not "once" for the scope

[BL-464](https://ortussolutions.atlassian.net/browse/BL-464) tag comments not parsing inside output tag in template parsers

[BL-466](https://ortussolutions.atlassian.net/browse/BL-466) parsing fails with extra whitespace in closing output tag

[BL-467](https://ortussolutions.atlassian.net/browse/BL-467) \<cfset and \<bx:set fail if not followed by a space

[BL-472](https://ortussolutions.atlassian.net/browse/BL-472) Debugger breakpoints not working regression

[BL-473](https://ortussolutions.atlassian.net/browse/BL-473) BoxLang Error is not readable

[BL-454](https://ortussolutions.atlassian.net/browse/BL-454) Tag island Templating outputs in unexpected order


# 1.0.0-Beta10

August 16, 2024

BoxLang Betas are released weekly. This is our tenth marker and we are incredibly excited to bring you a very big release. This gives us a huge push forwards towards compatibility with other engines and many more new features we have always wanted in our language. Enjoy!

## Release notes - BoxLang - 1.0.0-Beta10

## New Features

### [BL-435](https://ortussolutions.atlassian.net/browse/BL-435) transpile queryGetRow() to queryRowData()

Ths is a compatibility feature for CFML engines so they can use the `queryGetRow()` BIF which internally funnels to the [`queryRowData`](/boxlang-language/reference/built-in-functions/query/queryrowdata)`()` method.

### [BL-436](https://ortussolutions.atlassian.net/browse/BL-436) Ini files support

CFML engines always had half baked support for working with INI files. We now have full support and a fluent way to interact with `ini` files. This is really important for those building IoT solutions or interacting with micro processor devices. To get started use the boxlang installer `install-bx-module bx-ini` or if using CommandBox: `install bx-ini`

Here is a typical ini file example:

```ini
[General]
appName=MyApplication
version=1.2.3
author=John Doe
boxlang=rocks

[Database]
host=localhost
port=5432
username=dbuser
password=dbpass
dbname=mydatabase

[Logging]
logLevel=DEBUG
logFile=/var/log/myapp.log
maxFileSize=10MB

[Features]
enableFeatureX=true
enableFeatureY=false
maxConnections=100
```

Here are the contributed functions in this module:

* `getIniFile( file )` : Reads an ini file and returns the IniFile object. If the file does not exist, it will create it.
* `getProfileSection( iniFile, section )` : Gets a section from the ini file as a struct
* `getProfileSections( iniFile )` : Gets all the sections from the ini file as a struct of structs
* `getProfileString( iniFile, section, entry )` : Gets an entry from a section in the ini file, if it does not exist, it will return an empty string
* `setProfileString( iniFile, section, entry, value )` : Sets an entry in a section in the ini file, if the section does not exist, it will create it
* `removeProfileSection( iniFile, section )` : Removes a section from the ini file
* `removeProfileString( iniFile, section, entry )` : Removes an entry from a section in the ini file

The `IniFile` object is a fluent object that allows you to work with ini files in a very easy way. Here is an example of how to use it:

```groovy
// Get the ini file
var iniFile = getIniFile( "test.ini" );
iniFile.createSection( "mySettings" );
// Set a string
iniFile.setEntry( "section1", "entry1", "value1" );
// Get a string
var value = iniFile.getEntry( "section1", "entry1" );
// Remove a string
iniFile.removeEntry( "section1", "entry1" );
// Remove a section
iniFile.removeSection( "section1" );
```

### [BL-437](https://ortussolutions.atlassian.net/browse/BL-437) JSStringFormat BIF

This BIF is now complete to provide JavaScript escaping when using BoxLang as the template processor:

```javascript
<script>
let info = "#JSStringFormat( "An example string value with ""quoted"" 'text'" )#"
</script>
```

### [BL-439](https://ortussolutions.atlassian.net/browse/BL-439) xml component

We have now finalized XML support in BoxLang with a beautiful `xml` component:

```xml
<bx:xml variable="myVar">
  <root>
    <foo attr="brad" />
    <foo attr="luis" />
    <foo attr="jon" />
  <root>
</bx:xml>
```

### [BL-442](https://ortussolutions.atlassian.net/browse/BL-442) getVariable() & [BL-443](https://ortussolutions.atlassian.net/browse/BL-443) setVariable()

These two functions now exist in the `compat` module. It allows you to set and get variables in the `variables` scope. This can also be used to retrieve dynamic variable names or set dynamic variable names:

```gradle
setVariable( prepVar(), "hello" )

println( getVariable( getVar() ) )
```

### [BL-444](https://ortussolutions.atlassian.net/browse/BL-444) Add getClientVariablesList() to compat

Legacy `client` scope support added to the compat module

### [BL-448](https://ortussolutions.atlassian.net/browse/BL-448) New getDescendantsOfType() AST method with predicate

This is an internal method of our contexts to allow us to retrieve things easily with predicates.

### [BL-449](https://ortussolutions.atlassian.net/browse/BL-449) Implement single quote escapes in queries and preserveSingleQuotes

We thought this was going to be an easy one. `preserveSingleQuotes()` is now built for the core language to assist when building dynamic SQL and escaping quotes smartly.

### [BL-450](https://ortussolutions.atlassian.net/browse/BL-450) Allow .cfm and .cfs files from the boxlang CLI runner

Our BoxLang runner now allows for the CLI execution of `cfm` and `cfs` files directly along side BoxLang templates.

```bash
boxlang task.cfm
boxlang script.cfs
```

## [BL-440](https://ortussolutions.atlassian.net/browse/BL-440) Add isNumericDate BIF

This BIF is now in the core thanks to a client migration.

### [BL-441](https://ortussolutions.atlassian.net/browse/BL-441) Add getHTTPTimeString BIF to web-support

Our web support package gets a new BIF thanks to a client migration

### [BL-143](https://ortussolutions.atlassian.net/browse/BL-143) Writedump label support

WriteDump in BoxLang now get beautiful labels!

<div align="left"><figure><img src="/files/XszfwHgl45o01MbvEs5r" alt="" width="291"><figcaption></figcaption></figure></div>

### [BL-447](https://ortussolutions.atlassian.net/browse/BL-447) java.math.BigInteger caster

We have a new caster for BigInteger and BigDecimal to help us with precise mathematics in BoxLang.

## Improvements

### [BL-425](https://ortussolutions.atlassian.net/browse/BL-425) When doing class serialization make sure to identify which properties have \`serialize=false\` on them

Our serializer to binary for classes now respects the `serialize` annotation on properties.

```cfscript
class{
    // serializable
    property name;
    // not serializable
    property boolean isLoggedIn deafult=false serializable=false

}
```

[BL-426](https://ortussolutions.atlassian.net/browse/BL-426) content component can have body

[BL-429](https://ortussolutions.atlassian.net/browse/BL-429) Enhance error messages for parsing invalid tag code

## Bugs

[BL-427](https://ortussolutions.atlassian.net/browse/BL-427) MalformedInputException: Input length = 1 when parsing CFC

[BL-428](https://ortussolutions.atlassian.net/browse/BL-428) component detection can be tricked if there is a tag comment line starting with the word "component"

[BL-432](https://ortussolutions.atlassian.net/browse/BL-432) Regression: Can't run files via BoxRunner due to new action command logic

[BL-451](https://ortussolutions.atlassian.net/browse/BL-451) Sometimes trying to shutdown runtime throws NPE if it was never started fully

[BL-452](https://ortussolutions.atlassian.net/browse/BL-452) pretty print visitor outputting extra " on tag catch block

[BL-453](https://ortussolutions.atlassian.net/browse/BL-453) pretty print visitor doesn't handle array notation invocation


# 1.0.0-Beta9

August 9, 2024

BoxLang Betas are released weekly. This is our ninth marker and we are incredibly excited as we are coming close to our stable release. We have some great news in this release!

## New Features

### [BL-105](https://ortussolutions.atlassian.net/browse/BL-105) PDF Module

PDFs have landed for BoxLang. The full implementation for creating PDF documents is now complete and available via our `bx-pdf` module. This module contributes the following Components to the language:

* `document` - the wrapping component for creating PDF documents
  * The following attributes are available to the `document` component
    * `format` - The format of the document to generate. This attribute is unused and will be removed in a future release as only PDF generation is supported. Any other format requested will throw an error.
    * `encryption` - The encryption level to use for the document. Default is none. Possible values are 128-bit, 40-bit, none
    * `localUrl` - If true, the document will be generated with local URLs. Default is false
    * `variable` - The name of the variable to store the generated PDF binary
    * `backgroundVisible` - If true, the background will be visible. Default is true
    * `bookmark` - If true, bookmarks will be generated. Default is true
    * `htmlBookmark` - If true, it is possible to convert outlines to a list of named anchors (`<a name="anchor_id">label</a>`) or a headings structure ( `<h1>... <h6>` ). Transforming of HTML hyperlinks to PDF hyperlinks (if not explicitly disabled Hyperlink jumps within the same document are supported as well
    * `orientation` - The orientation of the document. Default is portrait. Possible values are portrait, landscape
    * `scale` - The percentage to scale the document. Must be less than 100
    * `marginBottom` - The bottom margin of the document
    * `marginLeft` - The left margin of the document
    * `marginRight` - The right margin of the document
    * `marginTop` - The top margin of the document
    * `pageWidth` - The width of the page in inches
    * `pageHeight` - The height of the page in inches
    * `fontEmbed` - If true, fonts will be embedded in the document. Default is true
    * `fontDirectory` - The directory where fonts are located
    * `openpassword` - The password to open protected documents
    * `ownerPassword` - The password to access restricted permissions
    * `pageType` - The type of page to generate. Default is A4.
    * `pdfa` - If true, the document will be generated as a PDF/A document. Default is false
    * `filename` - The filename to write the PDF to. If not provided and a `variable` argument is not provided, the PDF will be written to the browser ( Web-context only )
    * `overwrite` - If true, the file will be overwritten if it exists. Default is false
    * `saveAsName` - The name to save the PDF as in the browser
    * `src` - A full URL or path relative to the web root of the source
    * `srcfile` - The absolute path to a source file
    * `mimeType` - The mime type of the source. Default is text/html. Possible values are text/html, text/plain, application/xml, image/jpeg, image/png, image/bmp, image/gif
    * `unit` - The unit of measurement to use. Default is inches. Possible values are in, cm
  * The following attributes are not currently implemented and will throw an error if used
    * `permissions` - Granular permissability is not yet supported
    * `permissionspassword` - Granular permissability is not yet supported
    * `userPassword` - Granular permissability is not yet supported
    * `authPassword` - Granular permissability is not yet supported
    * `authUser` - Granular permissability is not yet supported
    * `userAgent` - HTTP user agent identifier
    * `proxyHost` - IP address or server name for proxy host
    * `proxyPassword` - password for the proxy host
    * `proxyPort` - port of the proxy host
    * `proxyUser` - user name for the proxy host
    * `tagged` - yes|no ACF OpenOffice integration not supported
    * `formfields` - yes|no Form field attributes are not implemented in standard module
    * `formsType` - FDF|PDF|HTML|XML Form field attributes are not implemented in standard module
* `documentitem` - specifies header, footer, and pagebreaks within a document body or `documentsection`
  * The following attributes are available to the `documentitem` component
    * `type` A string which dictates the type of item. Accepted values are `pagebreak`|`header`|`footer`
    * `evalAtPrint` This attribute is deprecated as all content is evaluated when the body of the tag is processed
* `documentsection` - Divides a PDF document into sections. Used in conjunction with a `documentitem` component, each section can have unique headers, footers, and page numbers. A page break will always precede a section
  * The following attributes are available to the `documentsection` component
    * `marginBottom` - The bottom margin of the section in the unit specified in the `document` component.
    * `marginLeft` - The left margin of the section in the unit specified in the `document` component.
    * `marginRight` - The right margin of the section in the unit specified in the `document` component.
    * `marginTop` - The top margin of the section in the unit specified in the `document` component.
    * `mimeType` - The mime type of the content. If the content is a file, the mime type is determined by the file extension. If the content is a URL, the mime type is determined by the HTTP response.
    * `name` - The name of the section. This is used as a bookmark for the section.
    * `srcfile` - The absolute path of the file to include in the section.
    * `src` - The URL or path relative to the web root of the content to include in the section.
  * The following attributes are not currently implemented and will throw an error if used
    * `userAgent` - The HTTP user agent identifier to use when fetching the content from a URL.
    * `authPassword` - The authentication password to use when fetching the content from a URL.
    * `authUser` - The authentication user name to use when fetching the content from a URL.

#### Examples

Simple example using tag-based syntax to generate a physical file:

```xml
<bx:set testImage = "https://ortus-public.s3.amazonaws.com/logos/ortus-medium.jpg"/>
<bx:document format="pdf" filename="/path/to/mydocument.pdf">
    <!--- Header for all sections --->
    <bx:documentitem type="header">
        <h1>This is my Header</h1>
    </bx:documentitem>
    <!--- Footer for all sections --->
    <bx:documentitem type="footer">
        <h1>This is My Footer</h1>
        <bx:output><p>Page #bxdocument.currentpagenumber# of #bxdocument.totalpages#</p></bx:output>
    </bx:documentitem>
    <!--- Document section, which will be bookmarked as "Section 1" --->
    <bx:documentsection name="Section 1">
        <h1>Section 1</h1>
    </bx:documentsection>
    <!--- Document section, which will be bookmarked as "Section 2" --->
    <bx:documentsection name="Section 2">
        <h1>Section 2</h1>
    </bx:documentsection>
    <!--- Document section, which contains an image --->
    <bx:documentsection src="#testImage#">
</bx:document>
```

Example using script syntax to create a variable containing the binary contents of the PDF, which is then written to a file

```java
document format="pdf" variable="myPDF"{
    documentsection name="Section 1"{
        writeOutput("<h1>Section 1</h1>");
        include "/path/to/section1.bxm";
    }
    documentsection name="Section 2"{
        writeOutput("<h1>Section 2</h1>");
        include "/path/to/section2.bxm";
    }
}

fileWrite( "/path/to/mydocument.pdf", myPDF );
```

### [BL-110](https://ortussolutions.atlassian.net/browse/BL-110) objectLoad() and objectSave() implemented and renamed to objectSerialize() and objectDeserialize()

This is a really step forward for BoxLang in providing the ability to serialize and deserialize any BoxLang type and any BoxLang class to binary recursively n-levels deep. We have introduced two BIFS to accomplish this:

* `objectSerialize( object, [filepath] ) : binary`
* `objectDeserialize( input ) : object`

You can pass ANY `object` to the serialize function and it will recursively try to serialize the object to binary data. You can then store that in a database, cluster, cache, or a file using the `filepath` argument. To deserialize you can use the `objectDeserialize()` function and you can pass in the direct binary or a file path location for the binary.

**The only requirement is that the `object` be a BoxLang type or any Java type that implements serializable.**

Also note that for CFML compatibility, the compat module will expose them as `objectLoad()` and `objectSave()`.

### [BL-420](https://ortussolutions.atlassian.net/browse/BL-420) Exit REPL with quit or exit

You can now exit the BoxLang REPL by typing `quit` or `exit`.

```bash
> quit

> exit
```

### [BL-422](https://ortussolutions.atlassian.net/browse/BL-422) Ability to serialize BoxLang classes to binary and deserialize them back using it's state

This was related to BL-110 but specifically to BoxLang classes. This allows us now to be able to take the state of any BoxLang class and be able to serialize it to binary. You can then deserialize the binary and inflate it back to a BoxLang object graph again.

### [BL-423](https://ortussolutions.atlassian.net/browse/BL-423) New experimental features block on the \`boxlang.json\`

The `boxlang.json` get's a new top level configuration key: `experimental` which will be a feature flags approach to turn on/off experimental features in BoxLang.

```json
"experimental" : {
    "flag1" : true|false
}
```

### [BL-424](https://ortussolutions.atlassian.net/browse/BL-424) BoxRunner action commands now for: compile, cftranspile, featureAudit

We have consolidated our CLI tooling to all funnel through the `boxlang` binary script or `boxlang.bat` for windows. You can now execute our CLI tools via action commands which is based on the following keys:

* `compile` - Executes the BoxLang compiler tool
* `cftranspile` - Executes the CF to BoxLang transpile tool
* `featureAudit` - Executes the feature audit tool

```bash
boxlang compile <options>
boxlang cftranspile <options>
boxlang featureAudit <options>
```

## Improvements

### [BL-414](https://ortussolutions.atlassian.net/browse/BL-414) Renaming of Box Cache functions to standardized `cache{function}()`

The BoxLang Cache BIFs have been renamed to be standardized to the following:

* `cache( [provider:default] )`
* `cacheFilter()`
* `cacheNames()`
* `cacheProviders()`
* `cacheService()`

### [BL-415](https://ortussolutions.atlassian.net/browse/BL-415) Increase precision of math operations by using `BigDecimal`

This introduces `BigDecimal` usage all over BoxLang for two main use cases:

* Being able to store and process very large numbers that wouldn't fit inside a `Long` or a `Double` like `111111111111111111111111111 + 222222222222222222222222222`
* Being able to retain precision for decimals-- even small ones. For ex: `(0.1 + 0.2).toString()` outputs `0.30000000000000004` in Lucee 5 and ACF 2023. But in Lucee 6 and BoxLang, it correctly returns `.3` without any special work

Not ALL numbers are a `BigDecimal`-- just the ones that need to be:

* integer literals in your source code less than 11 chars will be a java `Integer`
* integer literals in your source code less than 20 chars will be a java `Long`
* All other integer literals in your source will be a java `BigDecimal`
* All decimal literals in your source will be a java `BigDecimal`

Furthermore, we have added a new `NumberCaster` which we should be using as our primary caster that returns an instance implementing the `Number` interface in Java

* any recognizable classes like int, long, double, big decimal, etc are just returned directly
* Any strings which contain integers (no decimal or sci notation) follow the same rules above (integer for small ones, long for bigger ones, big decimal for really big ones)
* Any strings with a decimal or sci notation will be made a BigDecimal

Basically, we return the "Smallest" data type we can without losing any precision. (An Integer is about 24 Bytes and a BigDecimal is about 64 Bytes so it seemed worth optimizing a bit)

### [BL-421](https://ortussolutions.atlassian.net/browse/BL-421) Finalize `FileUpload`, `FileUploadAll` BIFs and File Component upload actions in Web Support

The web runtimes now have file uploading capabiltiies finalized.

## Bugs

[BL-405](https://ortussolutions.atlassian.net/browse/BL-405) BigIntegers cause error: integer number too large

[BL-419](https://ortussolutions.atlassian.net/browse/BL-419) Not all unquoted tag attribute values are parsing


# 1.0.0-Beta8

August 2, 2024

BoxLang Betas are released weekly. This is our eigth beta marker and we are excited to report that we are 100% tag compatible with Adobe/Lucee and 99% BIF compatible. We can estimate that in the next 2 betas we will be 100% compatible with both Adobe/Lucee CFML engines when running BoxLang in compatibility mode.

{% hint style="danger" %}
Please note that this is our core competency definition. You can see our lists here:

* BIFS: <https://docs.google.com/spreadsheets/d/1SVr9NTYU51n9VyPrKVUjfF3EeEkEnkZOkrNmj1TE120/edit?pli=1&gid=0#gid=0&fvid=1144231850>
* Tags/Components\
  <https://docs.google.com/spreadsheets/d/1XkCQ8CPXslQWGCr8LHaQcDHZOMiwxST2nzX63_CSzvI/edit?gid=0#gid=0>
  {% endhint %}

## New Features

### [BL-394](https://ortussolutions.atlassian.net/browse/BL-394) contractPath() BIF

This allows you to get a relative path or mapping path from a fully expanded path in your system. This is useful, to understand where a full absolute path comes from:

```java
expandedPath = expandPath( "/brad" );  // /absolute/path/to/brad
contractPath( expandedPath ); // /brad
```

### [BL-395](https://ortussolutions.atlassian.net/browse/BL-395) Add loop times=n

We have added a new construct for looping by using the keyword `times` in your `loop` statements:

```groovy
loop times=5 {
    result &= "*";
}
```

You can also use `times` and the `index`

```groovy
loop times=5 index="i" {
    result &= i;
}
```

Or the `item` alias can be used as well as the `index`

```groovy
loop times=5 item="i" {
    result &= i;
}
```

### [BL-396](https://ortussolutions.atlassian.net/browse/BL-396) Implement GetBaseTagList() and getBaseTagData()

These two methods are to bring us closer to finalizing the creation of custom templating language constructs.

* `getBaseTagList( [caller] )` : Gets a comma-delimited list of uppercase ancestor tag names, as a string. The first list element is the current tag. If the current tag is nested, the next element is the parent tag. If the function is called for a top-level tag, it returns an empty string.
* `getBaseTagData( tagName, [level=1] )` : Used within a custom tag. Finds calling (ancestor) tag by name and accesses its data.

### [BL-397](https://ortussolutions.atlassian.net/browse/BL-397) Improve parser error messages for unpopped parser modes

For code like

```
<--- I never end
```

or

```
foo = "trumcated...
```

instead of our default “unpopped modes”, detect what specific mode is on the stack (comment\_mode, quotesMode, etc), find the start token (comment\_start, OPEN\_QUOTE, etc) and report the line number that the unclosed construct started, which could be hundreds of lines from the end of the file when parsing finally stopped.

### [BL-408](https://ortussolutions.atlassian.net/browse/BL-408) Transaction events

The BoxLang JDBC Transactions framework is now complete and incredibly robust. More than the other CFML engines or even Spring-based transaction demarcations. It is fully documented here:\
<https://boxlang.ortusbooks.com/boxlang-framework/transactions>

We have also added several events that you can listen to during the transaction processes:

* `onTransactionBegin`
* `onTransactionEnd`
* `onTransactionCommit`
* `onTransactionRollback`
* `onTransactionSetSavepoint`
* `onTransactionAcquire*`
* `onTransactionRelease*`

Note that all these events (with the exception of `onTransactionAcquire` and `onTransactionRelease`) have the potential to be acting upon a no-op transaction, with a null `connection` parameter since no connection was ever obtained.

## Improvements

[BL-402](https://ortussolutions.atlassian.net/browse/BL-402) Allow for circular references in structs and arrays

[BL-406](https://ortussolutions.atlassian.net/browse/BL-406) Java 21 update to URL creation as new URL is deprecated

[BL-407](https://ortussolutions.atlassian.net/browse/BL-407) add getMimeType method in FileSystemUtil to make it easier to get mime types of remote files ( e.g. PDF creation )

## Bugs

[BL-398](https://ortussolutions.atlassian.net/browse/BL-398) \<bx:loop query="query"> doesn't iterate over each item in the query, stays on the first item

[BL-404](https://ortussolutions.atlassian.net/browse/BL-404) session scope can be null in onSessionEnd, causing errors

## Tasks

[BL-372](https://ortussolutions.atlassian.net/browse/BL-372) Create tests for all valid and invalid dot and array access expressions


# 1.0.0-Beta7

July 26, 2024

**BoxLang Betas are released weekly.**

**This is our seventh beta marker and we are incredibly excited of this beta marker since it now fully supports ColdBox for operation.**

## Improvements

### [BL-376](https://ortussolutions.atlassian.net/browse/BL-376) web support error template only shows details of exceptions if IN debug mode else secure by default

If you are using the MiniServer or CommandBox, then if an exception occurs, only in **DEBUG MODE**, will you get the exception stacktrace, details and more. This makes it secure by default of not exposing any potential data for exceptions.

## [BL-392](https://ortussolutions.atlassian.net/browse/BL-392) Consolidate the runtime into services without the need of `getInstance()`

A simple internal improvement to improve locking and instance usage.

## New Features

## [BL-374](https://ortussolutions.atlassian.net/browse/BL-374) threadNew()

This is a new BIF for BoxLang. We have a way to create threads using the `thread{}` component in both script and template, and we have `threadJoin(), threadTerminate()` but we never had a way to create threads functionally.

#### Signature

```java
threadNew( lambda/closure, [attributes={}], [threadName], [priority=normal] )
```

#### Examples

```java
threadNew( () => {
    printLn( "thread is done!" );
    sleep( 1000 );
    result = "done";
} );

threadNew( () => calculateOrder( invoice ), {invoice:myData}, "order-builder", "high" )
```

Please note that the `attributes` is a struct of data that we will bind into the thread's `local` scope.

### [BL-388](https://ortussolutions.atlassian.net/browse/BL-388) Stream type and collector member methods

Java streams are now a native BoxLang type, which for now we don’t try to coerce, but simply match any existing instance or subclass of `java.lang.Stream`. This means we can now add member methods to ANY stream from BoxLang source code and make Streams also dynamic:

* `.toBXArray()`
* `.toBXStruct( [String type] )`
* `.toBXQuery( [Query query] )`
* `.toBXList( [String delimiter] )`

#### Examples

Collect stream of objects into BoxLang array

```java
foods = [ 'apples', 'bananas', 'pizza', 'tacos' ];
result = foods.stream().parallel().toBXArray();

import java.util.stream.IntStream;
result = IntStream.range(1, 6).toBXArray();
```

Collect stream of Map entries into a struct

```java
foods = { 'apples' : 'healthy', 'bananas' : 'healthy', 'pizza' : 'junk', 'tacos' : 'junk' };
result = foods.entrySet()
    .stream()
    .filter( e -> e.getValue() == 'healthy' )
    .toBXStruct();


data = [ 'd' : '', 'c' : '', 'b' : '', 'a' : '' ];
result = data.entrySet().stream().toBXStruct( "sorted" );
```

Collect an array of structs into an existing query object

```java
qry = queryNew( "name,title", "varchar,varchar" );

[
  	{ name: "Brad", title: "Developer" },
  	{ name: "Luis", title: "CEO" },
  	{ name: "Jorge", title: "PM" }
].stream().toBXQuery( qry );
```

Collect a stream of objects into a list

```java
foods = [ 'apples', 'bananas', 'pizza', true ];
foods.stream().toBXList();

[ "www", "google", "com" ].stream().toBXList( "." )
```

### [BL-390](https://ortussolutions.atlassian.net/browse/BL-390) orThrow( type, message ) for attempts

Attempts now allow you to do a custom exception type and message. Check out the [attempt](/boxlang-language/syntax/attempts) docs.

### [BL-391](https://ortussolutions.atlassian.net/browse/BL-391) ifSuccessful() alias to ifPresent() on attempts

Attempts now allow you to have an alias to `ifPresent()` that's fluent: `ifSuccessful()`. Check out the [attempt](/boxlang-language/syntax/attempts) docs.

## Bugs

[BL-373](https://ortussolutions.atlassian.net/browse/BL-373) Parser detection for unparsed tokens only works if there are 2 or more tokens left

[BL-377](https://ortussolutions.atlassian.net/browse/BL-377) Declaring UDFs in function context doesn't always work

[BL-378](https://ortussolutions.atlassian.net/browse/BL-378) CFConfig datasources aren't importing due to lack of support for the 'dbdriver' key

[BL-379](https://ortussolutions.atlassian.net/browse/BL-379) Runtime can deadlock due to syncronized methods

[BL-380](https://ortussolutions.atlassian.net/browse/BL-380) NPE calling isNumeric()

[BL-381](https://ortussolutions.atlassian.net/browse/BL-381) JSONSerialize() errors when useSecureJSONPrefix not a boolean

[BL-385](https://ortussolutions.atlassian.net/browse/BL-385) Cannot call getWriter(), getOutputStream() already called

[BL-386](https://ortussolutions.atlassian.net/browse/BL-386) empty url vars coming through as null

## Tasks

[BL-372](https://ortussolutions.atlassian.net/browse/BL-372) Create tests for al valid and invalid dot and array access expressions


# 1.0.0-Beta6

July 19, 2024

BoxLang Betas are released weekly. This is our fifth beta marker. Here are the release notes.

## New Features

### [BL-157](https://ortussolutions.atlassian.net/browse/BL-157) Implement nested transactions

We are excited to bring the completion of nested transactions into BoxLang, something we have wanted in an open-source engine for years.

```cfscript
transaction{
  queryExecute( "INSERT INTO developers ( id, name, role ) VALUES ( 22, 'Brad Wood', 'Developer' )", {} );
    
    transaction{
      queryExecute( "INSERT INTO developers ( id, name, role ) VALUES ( 33, 'Jon Clausen', 'Developer' )", {} );
	 transactionRollback();
    }
    
}
```

Here, the `INSERT` in the child transaction is rolled back, but the parent transaction's `INSERT` statement persists.

General behavior:

* A rollback on the parent transaction will roll back the child transaction.
* A rollback on the child will **NOT** roll back the parent.
* Child transaction savepoints use a prefix so they don't collide with the parent transaction.
* Logging has been added, so you can easily see the transaction lifecycle as a transaction is created, savepoints are created, transactions rollback, etc.
* You can't change any transaction properties on a nested transaction. i.e., once the parent transaction begins, you can't begin a child transaction and change the isolation level.

Transaction events will come in the next beta.

### [BL-348](https://ortussolutions.atlassian.net/browse/BL-348) queryReverse() finalized

This BIF is now complete so you can easily reverse query data.

### [BL-349](https://ortussolutions.atlassian.net/browse/BL-349) Allow servlet to expand paths so CommandBox web aliases or ModCFML web dirs can be used and new `OnMissingMapping` event.

Adobe CFML Engines do this today via their “magic” connector. Lucee has never supported it. The expanded path should work like so now:

* if it doesn’t start with a `/` (and isn’t absolute), then make it relative to the base path
* look for a BoxLang mapping (not including “/” )
* Check if it’s an absolute path already, like C:/foo/bar
* Then announce an `ON_MISSING_MAPPING` interception point
* if no interceptor provided a value, then resolve via the root `/` mapping

The servlet runtime will have a listener for `ON_MISSING_MAPPING` that attempts to use `servetContext.getRealPath()` to try and resolve the path. This will allow any aliases in the resource manager to kick in.

If the servlet has an alias called `/foo` and you expand the path `/foo/existingFile.txt`, it will see it, but if you expand the path `/foo/notExistingFile.txt` then it will not “see” the mapping. We can solve that by taking off segments to see if any part of the path is found, but there is a performance hit to that, and I’m not sure if it’s necessary or not.

### [BL-350](https://ortussolutions.atlassian.net/browse/BL-350) Allow static functional access to BIFs

We have introduced static access to headless BIFS in BoxLang so you can use them as method references anywhere a BIF can be received, EVEN in Java classes that implement similar BIFS.

```java
// Syntax
::BIF

// Examples
::UCase
::hash
```

This expression represents a first-class BoxLang function that can be invoked directly.

```cfscript
(::reverse)( "darb" ); // brad
```

You can also store the BIF static access into variables.

```cfscript
foo = ::ucase
foo( "test" ) // TEST
```

You can also leverage it as a high-order function combination from methods or classes that expect function references.

```cfscript
["brad","luis","jon"].map( ::ucase ); // [ "BRAD","LUIS","JON" ]

[1.2, 2.3, 3.4].map( ::ceiling );    // [2,3,4]

["brad","luis","jon"].map( ::hash ); // ["884354eb56db3323cbce63a5e177ecac", "502ff82f7f1f8218dd41201fe4353687", "006cb570acdab0e0bfc8e3dcb7bb4edf" ]
```

### [BL-351](https://ortussolutions.atlassian.net/browse/BL-351) Allow Functional binding to member functions

In order to explain this new functionality in BoxLang, here is a Java snippet:

```java
List.of("apple", "banana", "cherry").stream().forEach(String::toUpperCase);
```

This syntax is a shortcut for writing out the following Java lambda:

```java
List.of("apple", "banana", "cherry").stream().forEach(str -> str.toUpperCase());
```

(Other JVM languages like Clojure have similar syntax) The `String::toUpperCase` binds to the instance method `toUpperCase`, but in a way that it will be called on each string instance in the stream. So for each iteration, it will call the `toUpperCase` method on that instance. Nothing like this ever existed in CFML engines. However, in BoxLang, it does now. BoxLang allows you to do the following:

* BoxLang-type member methods
* Class member methods
* Java member methods
* Any object member/field

Since member methods in BoxLang aren’t necessarily bound to a class and we’re a dynamic language, we have simplified the syntax to this:

```
.methodName
```

This is a function expression that accepts a **single** argument and calls the method name specified on the incoming instance, returning the result of the member call. it is a shortcut for

```
i -> i.methodName()
```

So our Java example becomes like this in BoxLang

```java
["apple", "banana", "cherry"].stream().forEach( .toUpperCase );
```

When not using (), check if there is a field of that name that is not a function, and if so, return that field value. So, the following example would fetch the name key in the struct.

```cfscript
nameGetter = .name
data = { name : "brad", hair : "red" }
nameGetter( data ) // brad
```

If the syntax `.foo()` is used or there is no field of that name, then it will be assumed we’re invoking a method. It can be directly invoked:

```cfscript
(.reverse)( "darb" ); // brad
```

It can be placed into a variable and invoked later:

```cfscript
foo = .ucase;
foo( "test" );  // TEST
```

And it can be passed to higher-order functions. (This is the main use case)

```cfscript
["brad","luis","jon"].map( .toUpperCase ); // ["BRAD","LUIS","JON"]

[1.2, 2.3, 3.4].map( .ceiling ); // [2,3,4]

[
  { myFunc : ()->"eric" },
  { myFunc : ()->"gavin" }
].map( .myFunc ) // [ "eric", "gavin" ]
```

Additionally, we have added support for multiple-arguments as well:

```cfscript
.methodName( arg1, arg2 )
```

Example:

```cfscript
["brad","luis","jon"].map( .left(1) ); // [ "b", "l", "j" ]
```

The arguments will not be evaluated until the function is invoked, and the argument expressions will be re-evaluated for every invocation.

```cfscript
pendingOrders.each( .submit( generateNextOrderNumber() ) ) // Fresh order number for each submission
```

The argument evaluation will have lexical binding to the declaring context.

```cfscript
local.suffix = " Sr."
["brad","luis","jon"].map( .concat( suffix ) ); // [ "brad Sr.", "luis Sr.", "jon Sr." "]
```

or

```cfscript
children.each( .setParent( this ) )
```

Bound member methods can also use named params (unless they are Java methods, of course)

```
foo = .left( count=2 );
foo( "test" ); // "te"
```

This brings a whole new dimension of dynamic goodness for not only BoxLang functions but also for Java functions. Welcome to a new era!

### [BL-352](https://ortussolutions.atlassian.net/browse/BL-352) arrayRange() BIF to create arrays with a specific range of values

This is one of our very first steps in supporting range types. You know have the capability to generate arrays with a specific boxed range using `arrayRange( from, to )`. You can use a `from` and `to` numeric index, and it will build the array with that many elements with the range as its value. However, you can also use range notation: `{from}..{to}`

```cfscript
// an array from 1 to 100
a = arrayRange( "1..100" )
a = arrayRange( 1, 100 )

// a negative indexed array
a = arrayRange( "-10..10" )
a = arrayRange( -10, 10 )
```

### [BL-353](https://ortussolutions.atlassian.net/browse/BL-353) threadTerminate() finalized

We have now finalized a `threadTerminate( name )` BIF.

### [BL-354](https://ortussolutions.atlassian.net/browse/BL-354) threadJoin() BIF Finalized

We have now finalized a `threadJoin( [name], timeout )` BIF. We have expanded this BIF and if you don't pass a thread name or a list of names, it will join all active threads.

### [BL-355](https://ortussolutions.atlassian.net/browse/BL-355) queryInsertAt() BIF finalized

This is now finalized.

### [BL-356](https://ortussolutions.atlassian.net/browse/BL-356) QueryRowSwap() bif finalized

This is now finalized.

### [BL-358](https://ortussolutions.atlassian.net/browse/BL-358) runAsync() completed but based on the powerful new BoxFuture -> CompletableFuture

This is a big ticket. Welcome to the future with `BoxFuture.` We have completed the ability to do asynchronous pipelines and parallel computations in BoxLang. We have introduced a new type called `BoxFuture,` which extends a Java Completable Future. The return of a `runAsync()` is a BoxFuture, and you can create pipelines to process the computations. You can access all the methods in a Completable future and many more. This will be documented in our [Async Programming](/boxlang-framework/asynchronous-programming) guide.

#### Futures

You have a new BIF: `futureNew( [value], [executor] )` that can create new box futures. By default it will create incomplete and empty futures. However, you can pass different values to the future. Check out the API Docs: <https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-beta6/ortus/boxlang/runtime/async/BoxFuture.html>

* `value` : If passed, the value to set on the BoxFuture object as completed, or it can be a lambda/closure that will provide the value, and it will be executed asynchronously, or it can be a native Java CompletableFuture
* `executor` : If passed, it will use this executor to execute the future. Otherwise, it defaults to the fork/join pool in Java.

```cfscript
// incomplete future
f = futureNew()

// completed future with a value
f = futureNew( myValue )

// a future that executes an asynchronous lambda/closure and the value will be the result
f = futureNew( () -> orderService.calculate() )

// A future with an executable and a virtual thread executor
f = futureNew(
    () -> processTasks(),
    executorNew( "virtual", "virtual" )
)
```

{% embed url="<https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-beta6/ortus/boxlang/runtime/async/BoxFuture.html>" %}

#### runAsync( callback, \[executor ] )

You can pass a closure or lambda to `runAsync()` to execute it asynchronously. The seconds parameter is an `executor` which runs the threads. It runs in the fork/join pool by default, but you can also pass your own executors. The return is a BoxFuture, which you can then do asynchronous pipelines.

```cfscript
calculation = runAsync( () -> calculateNumber() )
    .then( result -> result * 2 )
    .then( result -> result + 5 )
    .onError( exception -> { manage exception } )
    .get()
    

// Use a custom executor
runAsync( () -> "Hello", executorNew( "single", "single" ) )
    .then( ::println )
    .join()
    
// Process an incoming order
runAsync( () => orderService.getOrder() )
    .then( order => enrichOrder( order ) )
    .then( order => performPayment( order ) )
    .thenAsync( 
        order => dispatchOrder( order ), 
        executorNew( "cpuIntensive", "fixed", 150 )
     )
    .then( order => sendConfirmation( order ) );
 
// Combine Futures
var bmi = runAsync( () => weightService.getWeight( rc.person ) )
    .thenCombine(
	runAsync( 
	    () => heightService.getHeight( rc.person ) ),
            ( weight, height ) => {
            var heightInMeters = arguments.height/100;
            return arguments.weight / (heightInMeters * heightInMeters );
            })
        .get();   
```

### [BL-359](https://ortussolutions.atlassian.net/browse/BL-359) BIF Collection for managing and interacting with async service executors: list, get, has, new, shutdown

You now have the full capability to register, create, and manage custom executors in BoxLang. The `AsyncService` manages all executors in BoxLang.

Here are the new functions dealing with executors:

* `executorGet( name )`: Get a registered executor
* `executorHas( name ):` Checks if an executor has been registered or not
* `executorList()` : Lists all registered executors
* `executorNew( name, type, [maxThreads:20] ):` Creates and registers an executor by type and max threads if applicable.
* `executorShutdown( name )`: Shuts down an executor
* `executorStatus( [name] )`: Get a struct of executor metadata and stats by name or all.

The available executor types are:

* `cached` - Creates a cached thread pool executor.
* `fixed` - Creates a fixed thread pool executor.
* `fork_join` - Creates a fork-join pool executor.
* `scheduled` - Creates a scheduled thread pool executor.
* `single` - Creates a single thread executor.
* `virtual` - Creates a virtual thread executor.
* `work_stealing` - Creates a work-stealing thread pool executor.

### [BL-360](https://ortussolutions.atlassian.net/browse/BL-360) Configuration now supports executor registration for global usage

You can now register your executors globally in BoxLang in the `boxlang.json`

```json
// Global Executors for the runtime
// These are managed by the AsyncService and registered upon startup
// The name of the executor is the key and the value is a struct of executor settings
// Types are: cached, fixed, fork_join, scheduled, single, virtual, work_stealing
// The `threads` property is the number of threads to use in the executor. The default is 20
// Some executors do not take in a `threads` property
"executors": {
	"boxlang-tasks": {
		"type": "scheduled",
		"threads": 20
	},
	"cacheservice-tasks": {
		"type": "scheduled",
		"threads": 20
	}
},
```

### [BL-124](https://ortussolutions.atlassian.net/browse/BL-124) Implement primary/foreign key columns in dbInfo

DBInfo now returns primary and foreign key columns when you need them.

### [BL-255](https://ortussolutions.atlassian.net/browse/BL-255) Implement QueryMeta class for $.bx.meta or $.bx.getMeta() debugging support

Metaprogramming on queries is now available with much more information like caching, execution status, records, etc.

## Improvements

### [BL-357](https://ortussolutions.atlassian.net/browse/BL-357) "Fix" return types of BIFs that return "true" for no real reason

One of the odd things about CFML is the following:

```cfscript
myArr.append( "foo" ) // returns myArr
arrayAppend( myArr ) // returns true??
```

In BoxLang, the following BIFS returns the instance it was called with instead of a boolean. However, if you are in compat mode in a CFML file, you will get the old behavior.

* `arrayAppend()`
* `arrayClear()`
* `arrayDeleteAt()`
* `arrayInsertAt()`
* `arrayResize()`
* `arraySet()`
* `arraySwap()`
* `StructClear()`
* `StructKeyTranslate()`
* `StructInsert()`
* `structAppend()`
* `QuerySetRow()`
* `QueryDeleteRow()`
* `QuerySort()`
* `ArrayPrepend()`

The following BIFs return something other than the original data structure, but they have a good reason for doing so, so they remain as is:

* queryAddColumn() -- returns index of the column removed
* queryAddRow() -- returns the row number added

The following BIF returns the query in Adobe, which we’ll match. Lucee returns the array of removed data, but we’re ignoring that since we agree with Adobe’s behavior.

* QueryDeleteColumn()

### [BL-366](https://ortussolutions.atlassian.net/browse/BL-366) Provide Java FI typing on all higher-order BIFs

### [BL-371](https://ortussolutions.atlassian.net/browse/BL-371) make name un-required in the application component

### [BL-346](https://ortussolutions.atlassian.net/browse/BL-346) DynamicObject equals() hashCode() to allow for dynamic checking

## Bugs

[BL-364](https://ortussolutions.atlassian.net/browse/BL-364) Overridden getter in parent class not being used

[BL-370](https://ortussolutions.atlassian.net/browse/BL-370) List and Delmiter Args are not correct in `ListReduce` callback

[BL-365](https://ortussolutions.atlassian.net/browse/BL-365) The throwable Dump table is not styled


# 1.0.0-Beta5

July 12, 2024

BoxLang Betas are released weekly. This is our fifth beta marker. Here are the release notes.

## New Features

### [BL-319](https://ortussolutions.atlassian.net/browse/BL-319) Ability to call on \`navigate( String... paths)\` on the \`Configuration\` to create data navigators

The entire `boxlang.json` has now been updated to match the [CFConfig](https://cfconfig.ortusbooks.com/) project as much as it can. This ticket introduces a new method on the `Configuration` object that the core team and module developers can use to navigate the configuration structures fluently. The `navigate()` method produces a BoxLang [DataNavigator](https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-beta5/ortus/boxlang/runtime/util/DataNavigator.Navigator.html) object, which allows you to navigate in, get keys, cast them, do defaults, and so much more.

```java
Configuration
    .navigate( "modules" )
    .ifPresent( "security", value -> this.name = Key.of( value ) );
```

Check out our data [navigator](/boxlang-language/syntax/data-navigators) docs for further information.

### [BL-320](https://ortussolutions.atlassian.net/browse/BL-320) Store the original last configuration seeded into the runtime as \`originalConfig\`

The configuration object also stores the original configuration struct from the last loaded boxlang.json. You can navigate it or retrieve it from anywhere within the BoxLang code. This is great for module developers, so they can have any setting they can retrieve later.

```cfscript
var renderInHtml = Configuration
    .navigate( "originalConfig", "modules", "pdf" )
    .getAsBoolean( "htmlREnder", false )
```

### [BL-322](https://ortussolutions.atlassian.net/browse/BL-322) New StringBind() bif and member function to bind a string with placeholder replacements using the \`${key}\`

We use this methodology everywhere in BoxLang core, so we now expose it as a BIF and member method for strings. The `stringBind()` allows you to pass in a string template, and bind it with a map of variables for you as long as it adheres to the binding pattern of: `${key:defaultValue}`

You can use it for mail merging, data merging, string templates, and so much more.

```cfscript
function renderMail(){
    myTemplate = """
    Hello ${name},
    
    I hope you have an awesome ${action} using BoxLang v${version:snapshot}
    """
    
    return stringBind( myTemplate, { 
        name : "Luis Majano",
        action : "Day"
    } );
}

function renderMail(){
    return """
    Hello ${name},
    
    I hope you have an awesome ${action} using BoxLang v${version:snapshot}
    """.bind( { 
        name : "Luis Majano",
        action : "Day"
    } );
}
```

### [BL-324](https://ortussolutions.atlassian.net/browse/BL-324) attempts now have an isNull() to explicitly determine if the value is null

We have just started talking about our Attempt class in BoxLang, a Java Optional on Steroids. It allows you to track values and act upon them depending on whether they exists or truthy/falsey. It provides many functional methods to produce fluent DSLs and is easier to work with any attempt at external resources or other things. The core will be moving towards returning attempts whenever it makes sense.

```cfscript
var userFound = attempt( userService.findBy( rc.id ) ).isNull()
```

Please see our docs on [Attempts](/boxlang-language/syntax/attempts) for further information.

### [BL-325](https://ortussolutions.atlassian.net/browse/BL-325) Allows Java methods to be referenced and passed around as a variable and invoked later like UDFs

### [BL-338](https://ortussolutions.atlassian.net/browse/BL-338) Allow Java functional interfaces and SAMs to be wrapped and used as functions

We’ve added more goodies to our BoxLang Java interop, this time around method references and high-order functions. BoxLang already allows you to grab a reference to a UDF or closure as a variable, pass it around, and invoke it.

```js
myInstance = new myClass();
myInstanceMethod = myInstance.myMethod;
myInstanceMethod();
```

BL also allows you to grab a reference to a **static** method from a Box class as well using the `::` notation.

```js
myStaticUDF = src.test.java.TestCases.phase3.StaticTest::sayHello;
myStaticUDF();
```

Now, in BoxLang, we’ve elevated Java methods, both instance and static also to be objects you can pass around, invoke, and send into a higher-order function (a function that accepts functions).

When you reference a method on a Java class without the parenthesis (just like our BL examples above), you will get a special Function instance that wraps up the Java method, allowing it to be treated as a function, passed into any argument which is typed as a function, and invoked headlessly.

Here, we capture the static value of the Java String class `valueOf()` method from and place it into a variable, where we invoke it.

```js
import java:java.lang.String;
javaStaticMethod = java.lang.String::valueOf;
result = javaStaticMethod( "test" ) // New string of "test"
```

This example captures the `toUpperCase` method from a String instance. Note the method is still bound to the original String instance and, when invoked, will be invoked against that original instance

```js
javaInstanceMethod = "my string".toUpperCase
result = javaInstanceMethod() // "MY STRING"
```

And finally, here we use a Java method to pass directly in place of a UDF or Closure to a higher order function.

```js
import java.util.Collections;
// Use the compare method from the Java reverse order comparator to sort a BL array
[ 1, 7, 3, 99, 0 ].sort( Collections.reverseOrder().compare  ) // [ 99, 7, 3, 1, 0 ]
```

We grab the `compare` method from Java’s reverse order comparator and pass it directly into the array sort method in BoxLang, reversing our array! Stay tuned, as more features are coming on Java interop.

### [BL-326](https://ortussolutions.atlassian.net/browse/BL-326) New Application global defaults in the boxlang.json

Our configuration is now solid leveraging cfconfig and we have now added several configuration items that will be used as defaults for all applications running under BoxLang. You will find this in the `boxlang.json`

```json
// The default timezone for the runtime; defaults to the JVM timezone if empty
// Please use the IANA timezone database values
"timezone": "",
// The default locale for the runtime; defaults to the JVM locale if empty
// Please use the IETF BCP 47 language tag values
"locale": "",
// If true, you can call implicit accessors/mutators on object properties. By default it is enabled
// You can turn it on here for all applications or in the Application.cfc
"invokeImplicitAccessor": true,
// Use Timespan syntax: "days, hours, minutes, seconds"
"applicationTimeout": "0,0,0,0",
// The request timeout for a request in seconds; 0 means no timeout
"requestTimeout": "0,0,0,0",
// The session timeout: 30 minutes
"sessionTimeout": "0,0,30,0",
// Where sessions will be stored by default.  This has to be a name of a registered cache
// or the keyword "memory" to indicate our auto-created cache.
// This will apply to ALL applications unless overridden in the Application.cfc
"sessionStorage": "memory",
// Set client cookies on applications
"setClientCookies" : true,
// Set domain cookies on applications
"setDomainCookies" : true,
// A collection of BoxLang mappings, the key is the prefix and the value is the directory
"mappings": {
	"/": "${user-dir}"
},
// A collection of BoxLang custom tag directories, they must be absolute paths
"customTagsDirectory": [
	"${boxlang-home}/customTags"
],
// A collection of directories we will class load all Java *.jar files from
"javaLibraryPaths": [
	"${boxlang-home}/lib"
],
// You can assign a global default datasource to be used in the language
"defaultDasource": "",
// The registered global datasources in the language
// The key is the name of the datasource and the value is a struct of the datasource settings
"datasources": {
	// "testDB": {
	// 	  "driver": "derby",
	//    "connectionString": "jdbc:derby:memory:testDB;create=true"
	// }
	// "testdatasource": {
	// 	  "driver": "derby",
	// 	  "host": "localhost",
	// 	  "port": 3306,
	// 	  "database": "test"
	// }
},
```

### [BL-330](https://ortussolutions.atlassian.net/browse/BL-330) new interception points when a session get's created and destroyed

We have introduced two new global interception points that modules can listen to:

<table><thead><tr><th width="241">Event</th><th width="126">Data</th><th>Description</th></tr></thead><tbody><tr><td><strong>onSessionCreated</strong></td><td>Session</td><td>When a new session is created and registered</td></tr><tr><td><strong>onSessionDestroyed</strong></td><td>Session</td><td>When a session is about to be destroyed</td></tr></tbody></table>

### [BL-339](https://ortussolutions.atlassian.net/browse/BL-339) All locations in the cache that returned optionals, now returns BoxLang Attempts

We have now moved internally from Optionals to Attemps in order to have consistency in our APIs. I am sure there are more things to do, but all cache interfaces and operations now rely on BoxLang Attempts.

```cfscript
return getBoxCache()
    .get( "maybeExists" )
    .orElse( "not found" );
```

### [BL-340](https://ortussolutions.atlassian.net/browse/BL-340) `getAsAttempt`() on the IStruct default methods for convenience

This is mostly for internal usage, where we can add native Java casting to struct operations to attempts.

### [BL-341](https://ortussolutions.atlassian.net/browse/BL-341) BoxCacheProviders now have a localized interceptor pool alongside the runtime pool

The BoxLang Cache now has a localized interception pool so it can also announce events locally and globally to the runtime. This allows you to have interceptors that can listen only at specific caches instead of all caches. We use this for example, to listen when sessions expire in applications:

```java
// Register the session cleanup interceptor
this.sessionsCache.getInterceptorPool()
    .register( data -> {
	    ICacheProvider targetCache = ( ICacheProvider ) data.get( "cache" );
	    String		key			= ( String ) data.get( "key" );

	    logger.debug( "Session cache interceptor [{}] cleared key [{}]", targetCache.getName(), key );

	    targetCache
	        .get( key )
	        .ifPresent( session -> ( ( Session ) session ).shutdown( this.startingListener ) );

	    return false;
    }, BoxEvent.BEFORE_CACHE_ELEMENT_REMOVED.key() );
```

Which brings about the next ticket:

[BL-342](https://ortussolutions.atlassian.net/browse/BL-342) Sessions are now monitored by cache interceptors to detect removals so as to shutdown the sessions before removal

### [BL-343](https://ortussolutions.atlassian.net/browse/BL-343) application, session, request timeouts in the boxlang.json are now string timespans

We have now added the capability to influence the application, request and session timeouts in configuration using the cfconfig standard of a string timespan:

```json
// Use Timespan syntax: "days, hours, minutes, seconds"
"applicationTimeout": "0,0,0,0",
// The request timeout for a request in seconds; 0 means no timeout
"requestTimeout": "0,0,0,0",
// The session timeout: 30 minutes
"sessionTimeout": "0,0,30,0",
```

### [BL-344](https://ortussolutions.atlassian.net/browse/BL-344) App Timeouts are now working

The default timeout for applications in BoxLang is `0`, which means they live forever. If you want to change it, then you will change it at the `boxlang.json` level or in the `Application.bx/cfc`

## Improvements

[BL-209](https://ortussolutions.atlassian.net/browse/BL-209) Combine config settings into a single struct

[BL-318](https://ortussolutions.atlassian.net/browse/BL-318) Allow optional attribute delimiters in ACF tag-in-script syntax

[BL-321](https://ortussolutions.atlassian.net/browse/BL-321) Refactor dump loading of CSS to use caching again

[BL-323](https://ortussolutions.atlassian.net/browse/BL-323) Refactor page pool to be per-mapping

[BL-329](https://ortussolutions.atlassian.net/browse/BL-329) **jsessionID** is the internal standard for boxlang sessions, move to this instead of cfid

[BL-332](https://ortussolutions.atlassian.net/browse/BL-332) `getOrSet`() in the cache should return the object not an optional

## Bugs Squashed

[BL-164](https://ortussolutions.atlassian.net/browse/BL-164) BL Compat module should coerce null values to empty string

[BL-252](https://ortussolutions.atlassian.net/browse/BL-252) MSSQL DROP TABLE throws 'The statement must be executed before any results can be obtained'

[BL-306](https://ortussolutions.atlassian.net/browse/BL-306) Adobe Compatibility: Missing support for new java() and new component()

[BL-308](https://ortussolutions.atlassian.net/browse/BL-308) cfinvoke does not support params as attribute-value pairs

[BL-316](https://ortussolutions.atlassian.net/browse/BL-316) If the global runtime \`javaLibraryPaths\` is already a jar/class location, then use it, else it breaks

[BL-317](https://ortussolutions.atlassian.net/browse/BL-317) allow "var" before CF catch variable in script

[BL-331](https://ortussolutions.atlassian.net/browse/BL-331) ResetSession on the scripting request context was invalidating the new session instead of the old session

[BL-333](https://ortussolutions.atlassian.net/browse/BL-333) Session creation if the default timeout is not a duration, it should treat it as seconds, not milliseconds

[BL-334](https://ortussolutions.atlassian.net/browse/BL-334) Session object was not serializable

[BL-335](https://ortussolutions.atlassian.net/browse/BL-335) Cache was evicting items without reaping

[BL-336](https://ortussolutions.atlassian.net/browse/BL-336) DateTime toString() not accounting for formatter being null

[BL-337](https://ortussolutions.atlassian.net/browse/BL-337) sessionRotate() not copying over old keys due to nullification of keys when invalidating the old session


# 1.0.0-Beta 4

BoxLang Betas are released weekly.  This is our fourth beta marker.  Here are the release notes.

Beta 4 is a small incremental release which includes improvements and bug fixes.

### Improvements

[BL-299](https://ortussolutions.atlassian.net/browse/BL-299), [BL-300](https://ortussolutions.atlassian.net/browse/BL-300), [BL-301](https://ortussolutions.atlassian.net/browse/BL-301), [BL-302](https://ortussolutions.atlassian.net/browse/BL-302) Query caching improvements and compatibility updates

[BL-315](https://ortussolutions.atlassian.net/browse/BL-315) Ensure request attributes are available to the web runtime scope

[BL-164](https://ortussolutions.atlassian.net/browse/BL-164) [bx-compat-cfml](https://forgebox.io/view/bx-compat-cfml) CFML compatibility module updates to ensure null query column values are returned as empty strings

### Bug Fixes

[BL-305](https://ortussolutions.atlassian.net/browse/BL-305) Fixes compilation issue with variables name `cfcatch`

[BL-309](https://ortussolutions.atlassian.net/browse/BL-309) CFML compatiblity for `CGI.QUERY_STRING` when not provided

[BL-314](https://ortussolutions.atlassian.net/browse/BL-314) Fix null `queryparam` functionality


# 1.0.0-Beta3

June 28, 2024

BoxLang Betas are released weekly. This is our third beta marker. Here are the release notes.

## New Features

### [BL-256](https://ortussolutions.atlassian.net/browse/BL-256) Implement query cache ability

Thanks to our enterprise cache engine and aggregator built into BoxLang, you can now use it to cache queries via its `options` configuration structure using `cfquery` or `queryExecute`. Here are the query caching properties you can use:

* `cache:boolean` - To turn on caching, this must be `true`. The default is `false`
* `cacheTimeout:timespan` - Optional timeout of the query in the cache. By default, is uses whatever the default timeout of items the cache has been configured with.
* `cacheLastAcccessTimeout:timespan` - Optional last access or idle timeout of the query in the cache. By default, is uses whatever the default timeout of items the cache has been configured with. This means that if this query is NOT used or requested in this timespan, it will be marked for eviction.
* `cacheProvider:string` - The name of the cache provider to store the queries. By default, we use the `DEFAULT` cache in BoxLang.

```cfscript
queryExecute(
    "SELECT * FROM developers WHERE role = ?",
    [ "Developer" ],
    { cache: true }
);
```

By default, queries will use [the default Boxlang CacheProvider](https://github.com/ortus-boxlang/BoxLang/blob/development/src/main/resources/config/boxlang.json), which has default timeouts and `lastAccessTimeout` values set.

To specify a custom caching provider, you can use the `cacheProvider` query option:

```cfscript
queryExecute(
    "SELECT * FROM developers WHERE role = ?",
    [ "Developer" ],
    { cache: true, cacheProvider : "redis" }
);
```

To specify custom cache entry timeouts, use `cacheTimeout` or `cacheLastAccessTimeout`:

```cfscript
queryExecute(
    "SELECT * FROM developers WHERE role = ?",
    [ "Developer" ],
    {
        cache: true,
        cacheTimeout : createTimespan( 0, 0, 0, 30 ),
        cacheLastAccessTimeout : createTimespan( 0, 0, 0, 30 )
    }
);
```

{% hint style="warning" %}
Note that the `bx-compat-cfml` module will take care of implementing [the historical `cachedWithin` and `cachedAfter` query options](https://cfdocs.org/cfquery).
{% endhint %}

#### Metadata

All query metadata will also have the cache information available to you as well. So you if get dump the query metadata you will see a ton of debugging information about the query:

```cfscript
writedump( myQuery.$bx.meta )
```

#### Interacting With The Cache

Please note that this leverages the BoxLang cache. This means you have full access to the cache provider and you can interrogate it for queries, clear all of them, or clear one of them. The default prefix used for all cached queries is: `BL_QUERY`

```cfscript
// Clear everything in the default cache
getBoxCache()
    .clearAll()

// Clear only the cached queries
getBoxCache()
    .clearAll( key-> key.getName().startsWith( "BL_QUERY" ) )

// Get a list of all cached queries
getBoxCache()
    .getKeys( key-> key.getName().startsWith( "BL_QUERY" ) )

// Get a stream of all the cached queries
getBoxCache()
    .getKeysStream( key-> key.getName().startsWith( "BL_QUERY" ) )
```

### [BL-261](https://ortussolutions.atlassian.net/browse/BL-261) coerce java SAMs from BoxLang function interfaces

This is another major milestone in the Java interop features of BoxLang. This allows us to coerce any BoxLang Lambda/Closure/UDF or even Classes to ANY, yes, ANY Java Functional Interface or Java SAM (Single Abstract Method Interface).

```cfscript
// Build your own Java comparators with BoxLang
Collections.sort(
    myArray or Java Array,
    (s1, s2) -> compareNoCase( s1, s2 )
)

// Create your own threads and completable futures
CompletableFuture.supplyAsync( () -> println( "Running in a thread" ) )

// Java predicates
arrayOfNumbers = [1,22,3,34,34,556]
arrayOfNumbers.stream()
    .filter( n -> n % 2 == 0 )
    .toList()
```

### [BL-281](https://ortussolutions.atlassian.net/browse/BL-281) AsyncService support for Virtual Thread Executors (create/manage)

Virtual Threads are now available to BoxLang via executors. You can choose the new `VIRTUAL` executor for schedulers or when creating schedulers via our AsyncService. This will treat all tasks and schedules to use virtual threads.

```cfscript
// Create, register and return
getBoxRuntime().getAsyncService()
    .newVirtualExecutor( "MyVirtualExecutor" )
```

More entry points to access this executor will be provided in the coming betas, alongside our very own `runAsync()` and the ability to create virtual threads as well.

### [BL-284](https://ortussolutions.atlassian.net/browse/BL-284) Bifs for module info: getModuleList() getModuleInfo( module )

As more modules are being developed for BoxLang, you now have the ability to know which modules have been loaded and activated in the language. As well as specific information about a module if needed. This is great for inter-dependencies and checking if modules have loaded from BoxLang.

```cfscript
writedump( getModuleList() )
writeDump( getModuleInfo( "bx-image" ) )
```

<figure><img src="/files/zyekxQ8gtZ96iAKMDgch" alt=""><figcaption></figcaption></figure>

### [BL-285](https://ortussolutions.atlassian.net/browse/BL-285) Dumping of Java Classes now includes a dump of the \`toString()\` value to visualize values better

This is a developer eye-candy, so when you dump any Java class, you can actually see the value of the class instance data via the `toString()` method.

<figure><img src="/files/gP9BHE7kW94N8bIsQSzK" alt=""><figcaption></figcaption></figure>

### [BL-289](https://ortussolutions.atlassian.net/browse/BL-289) New dump template for BL Functions

The dumping of BoxLang Functions (Closures, Lambdas, UDFs), either standalone or from a class, has great visibility now. You can see even the class used to generate the function, the function annotations, and much more.

<figure><img src="/files/aLPuoZr6TdHEoYLnsfbv" alt=""><figcaption></figcaption></figure>

### [BL-292](https://ortussolutions.atlassian.net/browse/BL-292) Allow the `createDynamicProxy` bif to support the request class loader so it can load classes from loaded libraries in the application.bx, runtime and more.

If you use `createDynamicProxy()` to make a BoxLang class look like a Java class, you can continue to do so now, but it accounts for all class loaders in the application. If you come from a CFML engine, this is impossible and is always a pain and limitation.

In BoxLang, your context matters. So depending on where you create the dynamic proxy, it will account for the surrounding class loaders to be able to create the appropriate Java proxies.

```cfscript
createDynamicProxy( myclass, [ array of interfaces ] )
createDynamicProxy( myclass, interface path )
```

### [BL-298](https://ortussolutions.atlassian.net/browse/BL-298) New Script Binaries for `bxCFTranspiler`, `bxCompiler`, `bxFeatureAudit` tools in the distribution bin folder

We have introduced Windows and Mac/Linux binaries for running several CLI tools. You no longer need to refer to the docs with extra-long options. You can now use the provided binaries to call the appropriate CLI tool.

If you use the quick installer, all these binaries will be installed for you.

<figure><img src="/files/ZxGlBhgNJ1PrZ1GfshRw" alt=""><figcaption></figcaption></figure>

## Improvements

[BL-254](https://ortussolutions.atlassian.net/browse/BL-254) Refactor JDBC connection retrieval out of the QueryOptions class

[BL-280](https://ortussolutions.atlassian.net/browse/BL-280) Dynamic method matching discovery algorithms updated to do 2 pass algorithm: exact, loose coercion matching

[BL-283](https://ortussolutions.atlassian.net/browse/BL-283) Improvement of cache service and cache provider methods for easier boxlang interactions

[BL-290](https://ortussolutions.atlassian.net/browse/BL-290) Refactored the dump css to \`resources/dump/html/Dump.css\`

[BL-291](https://ortussolutions.atlassian.net/browse/BL-291) Migrate dynamic proxies to native java implementation from the JDK

[BL-296](https://ortussolutions.atlassian.net/browse/BL-296) passing the session id to the onsessionstart listener

[BL-297](https://ortussolutions.atlassian.net/browse/BL-297) Give better warnings if the sessionStorage is not a valid string

## Bug

[BL-198](https://ortussolutions.atlassian.net/browse/BL-198) attributecollection not handled properly on cfthrow

[BL-278](https://ortussolutions.atlassian.net/browse/BL-278) Left in system out calls that need to be removed

[BL-279](https://ortussolutions.atlassian.net/browse/BL-279) JSR ScriptEngine starting runtime without debug flag if passed

[BL-282](https://ortussolutions.atlassian.net/browse/BL-282) Creating a default cache was not setting the right name and a "default" already registered exception was being thrown

[BL-286](https://ortussolutions.atlassian.net/browse/BL-286) Default argument values not always checked for type

[BL-287](https://ortussolutions.atlassian.net/browse/BL-287) Implements missing from Box Class metadata

[BL-288](https://ortussolutions.atlassian.net/browse/BL-288) Static Scope missing from metadata


# 1.0.0-Beta2

June 21, 2024

BoxLang Betas are released weekly. This is our second beta marker. Here are the release notes.

## Bug

[BL-140](https://ortussolutions.atlassian.net/browse/BL-140) `Writedump` expanded collapsed support

[BL-141](https://ortussolutions.atlassian.net/browse/BL-141) `Writedump` `top` support

[BL-193](https://ortussolutions.atlassian.net/browse/BL-193) `listdeleteAt` returns a list with multiple delimiters as a list with whole delimiters

[BL-231](https://ortussolutions.atlassian.net/browse/BL-231) `StructNew` with `localeSensitive` flag throws error

[BL-235](https://ortussolutions.atlassian.net/browse/BL-235) `structKeyTranslate` returns `void`

[BL-241](https://ortussolutions.atlassian.net/browse/BL-241) `StructGet` does not create struct when missing

[BL-245](https://ortussolutions.atlassian.net/browse/BL-245) `StructFindValue` returning null owner

[BL-246](https://ortussolutions.atlassian.net/browse/BL-246) no named applications not auto creating name

[BL-247](https://ortussolutions.atlassian.net/browse/BL-247) application listener requests interception points not registered

[BL-248](https://ortussolutions.atlassian.net/browse/BL-248) ambiguous if statements when not using curly braces

[BL-249](https://ortussolutions.atlassian.net/browse/BL-249) `this.javasettings` not expanding / to correct pathing

[BL-250](https://ortussolutions.atlassian.net/browse/BL-250) `this.javasettings` ignores paths to actual jars and classes

[BL-257](https://ortussolutions.atlassian.net/browse/BL-257) `cfdirectory` fails on centos, converting datetime

[BL-263](https://ortussolutions.atlassian.net/browse/BL-263) `dateAdd`() modifies its argument!

[BL-265](https://ortussolutions.atlassian.net/browse/BL-265) \``toString`\` not formatting doubles correctly

[BL-266](https://ortussolutions.atlassian.net/browse/BL-266) Attempt to cast instead of expecting strings inside \``isValid`\`

[BL-270](https://ortussolutions.atlassian.net/browse/BL-270) Regression on JSON serialization of box classes with JSON exclude annotations

## New Features

### [BL-128](https://ortussolutions.atlassian.net/browse/BL-128) Encryption module

We have created the `bx-password-encrypt` module so you can use it for password encryption. Find out much more here: <https://forgebox.io/view/bx-password-encrypt>

This will collaborate several new BIFs and components:

* `ArgonHash`: Returns a secure input hash of the given string using the Argon2 hashing algorithm. ( Alias: `GenerateArgon2Hash` )
* `ArgonVerify`: Performs a Argon2 verification on the given string against the hashed value. ( Alias: `Argon2CheckHash` )
* `BCryptHash`: Returns a secure input hash of the given string using the BCrypt hashing algorithm.( Alias: `GenerateBCryptHash` )
* `BCryptVerify`: Performs a BCrypt verification on the given string against the hashed value. ( Alias: `BCryptCheckHash` )
* `SCryptHash`: Returns a secure input hash of the given string using the SCrypt hashing algorithm.( Alias: `GenerateSCryptHash` )
* `SCryptVerify`: Performs a SCrypt verification on the given string against the hashed value. ( Alias: `SCryptCheckHash` )
* `GeneratePBKDFKey`: Generates a PDFK key from the given password and salt.

### [BL-251](https://ortussolutions.atlassian.net/browse/BL-251) New event: ON\_REQUEST\_FLUSH\_BUFFER

You can now listen to when the engine flushes the output buffer and intercepts it. This will allow you to collaborate content to the buffer before it's sent to the output destination. The data received is:

* `context` - The execution context
* `output` - The string output to send to the buffer. This can be text or HTML

### [BL-258](https://ortussolutions.atlassian.net/browse/BL-258) Ability to coerce BoxLang functions, lambdas, and UDFs, to well-known functional interfaces for Java interop

This is one of our biggest tickets for this release to continue to close the Java interop cycle in BoxLang. This will allow BoxLang lambdas/closures/udfs to be coerced to Java Functional Interfaces at runtime. This means that ANY Java library that offers functional interfaces (lambdas) can be used natively in BoxLang. This means that using streams, completable futures, and Java lambdas are now native to BoxLang.

```java
fruits = [ "apple", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn" ];
result = fruits
  .parallelStream()
  .filter(  fruit -> fruit.startsWith( "a" ) )
  .toList();
  
  
// Call a Java class that accepts a Runnable lambda with a BoxLang lambda
myJavaclass.runAsync( () -> "Hello from BoxLang" )
// Call a Java class that accepts a Runnable lambda with a BoxLang closure
myJavaclass.runAsync( () => processMyClosureData() )
```

This can also be used to tap into high concurrency constructs in Java. You can combine the usage of BoxLang pure functions (lambdas) or context-aware closures.

```java
import java.util.concurrent.CompletableFuture

// Build out an async BoxLang task using native Java Interop
function main( args = [] ) {
    // Define closures to fetch data from APIs 
    // (can be replaced with actual API calls)
    data1Future = CompletableFuture.supplyAsync( () => simulateApiCall("API 1") )
    data2Future = CompletableFuture.supplyAsync( () => simulateApiCall("API 2") )

    // Combine futures (waits for both to complete)
    // With a BoxLang lambda
    data1Future.thenAcceptBoth( data2Future, (data1, data2) -> {
        println("Data from API 1: " + data1);
        println("Data from API 2: " + data2);
        println("Combined data: " + data1 + " " + data2);
    });

    // Wait for all futures to complete
    CompletableFuture.allOf( data1Future, data2Future ).get();
}

private static simulateApiCall( apiName ) {
    try {
        sleep(1000); // Simulate API call delay
        println("Fetching data from " + apiName);
        return "Data from #apiName#"
    } catch (InterruptedException e) {
        println( e )
    }
}
```

### [BL-260](https://ortussolutions.atlassian.net/browse/BL-260) Add parallel streams from BoxLang arrays

All BoxLang arrays have native stream support, and you get native parallel support as well.

```java
result = fruits
  .parallelStream()
  .filter(  fruit -> fruit.startsWith( "a" ) )
  .toList();
```

### [BL-264](https://ortussolutions.atlassian.net/browse/BL-264) Truthy / Falsey completion for boolean caster

Our truthy/false evaluations for arrays, structs, queries, Java lists, and collections are complete.

### [BL-268](https://ortussolutions.atlassian.net/browse/BL-268) New Fluent Attempt bif and class

This is inspired by Java Optionals for BoxLang. We have introduced a new class called `Attempt()`, which allows you to create fluent and functional code to work with values or delay attempts at code execution. Then, you can interact with the result of your attempt using our functional methods.

Another important aspect of attempts is that they evaluate that the seeded value is not `null` but also truthy. This means you can use it to evaluate that the value is truthy or false, not only null. You can also pass in a closure/lambda to be the value and once you request to evaluate the result, it will do it asynchronously and delayed.

```cfscript
attempt( userService.get( rc.id ).isLoaded() )
    .ifPresent( user -> populate( user ).save() )
    .orThrow( "UserNotFoundException" )
    
// A delayed attempt
userDataAttempt = attempt( () -> userData.getData() )
    .toMatchRegex( "^myRegex" )

....

return userDataAttempt
    .orElse( "" )
    
```

Here are the current functions available to you in this beta. There are more coming to make it more fluent.

{% embed url="<https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-beta2/ortus/boxlang/runtime/dynamic/Attempt.html>" %}

* `get():any` - Get the value or throw an exception if null or falsey
* `empty():Attempt` - Produce a new empty attempt
* `of( value ):Attempt` - Produce a new attempt with the passed value
* `ofFunction( context, function/closure/lambda ):Attempt` - Produce a new attempt with a closure or lambda.
* `isEmpty():boolean` - Is the value falsey or null
* `isPresent():boolean` - Is the value present
* `ifPresent( consumer ):Attempt` - Call the consumer lambda/closure if the value is present
* `ifPresentOrElse( consumer, action ):Attempt` - Call the consumer lambda/closure if present or the action lambda/closure if not.
* `ifEmpty( consumer ):Attempt` - Call the consumer if the value is not present
* `or( supplier ):Attempt` - If the value is present it returns itself, if not, it calls the supplier closure/lambda to produce a new attempt.
* `orElse( other ):any`- Get the value if present, or otherwise return the other value passed
* `orElseGet( supplier ):any` - Get the value if present, otherwise call the supplier closure/lambda to produce the value you want to return.
* `map( mapper ): Attempt` - Maps the value of the attempt if it exists, else returns the same attempt with no value.
* `filter( predicate )` - If the value is present it will call your predicate closure/lambda so you can run tests on the value. If the return is true it will return the same attempt, else an empty attempt.
* `orThrow():any` - Returns the value if it exists or throws an exception
* `orThrow( message ):any` - Returns the value if it exists or throws an exception with your custom message
* `orThrow( exception ):any` - Returns the value if it exists or throws your custom exception
* `stream():Stream` - If the value exists returns a stream with the value else an empty stream
* `toString():String` - Gives you a string representation of the value
* `isValid():Boolean` - If the value is present it will try to validate it with the registered validation schemas, if any.
* `toBeValid( closure or lambda ):Attempt` - This allows you to register a lambda/closure to validate the data if any. When calling `isValid()` it will call this function if registered.
* `toBeBetween( min, max ):Attempt` - This allows you to register a min and max numerical values to test the value. It must be in range to be valid.
* `toMatchRegex( regex ):Attempt` - This allows you to register a regular expression to match against the value.

### [BL-269](https://ortussolutions.atlassian.net/browse/BL-269) Add the ability to add member methods to BoxLang classes

This was something we always wanted to do. This allows module and BoxLang developers to contribute member methods to ANY BoxLang class. So now, you can serialize any Class to JSON natively using our BoxLang Class to JSON native serialization. Let's build a `Person` class:

```cfscript
/**
 * My Person 
 */
@jsonExclude "anotherprop, anotherProp2"
class Person{

	property String name;
	property String surname;
	property numeric age;
	property Date createdDate;
	property Date modifiedDate;
	property boolean isActive;
	property Array tags;
	@jsonExclude
	property any javaSystem;
	property anotherProp;
	property anotherProp2;

	function init(){
		variables.name = "John";
		variables.surname = "Doe";
		variables.age = 30;
		variables.createdDate = now();
		variables.modifiedDate = now();
		variables.isActive = true;
		variables.tags = ["tag1", "tag2"];
		variables.test = CreateObject( "java", "java.lang.System" );
		variables.anotherProp = "hello";
		variables.anotherProp2 = "hello";

		return this;
	}

	function sayHello(){
		return "Hello " & variables.name;
	}

}

```

As you can see, we have introduced a few annotations for JSON serialization based on our experience with the ColdBox mementifier project. You can tag properties to be excluded from serialization using the `jsonExclude` annotation. You can exclude a list of properties from the class annotation as well. Now, let's get some JSON data out using the `toJSON()` member function, which delegates it to the `jsonSerialize()` bif.

```cfscript
function main( args={} ){
    return new Person()
        .setName( "Luis" )
        .setSurname( "Majano" )
        .toJSON()
}
```

This will allow framework developers to collaborate with first-class methods in any BoxLang class.

### [BL-271](https://ortussolutions.atlassian.net/browse/BL-271) new static helper on Array class: \`fromString( list, delimiter )\` to create quick BoxLang arrays from strings

This is an internal convenience method for creating BoxLang arrays from strings.

### [BL-272](https://ortussolutions.atlassian.net/browse/BL-272) new BIFS for registered interceptors into the request pool and the global pool: BoxRegisterREquestInterceptor, BoxRegisterInterceptor

BoxLang is an event-driven language. It announces tons of events during the software life cycle. You can now listen to any global event via the new `BoxRegisterInterceptor()` bif. This will allow you to register classes, lambdas, or closures.

```cfscript
boxRegisterInterceptor( ()=> listenToRequestStarts(), "onServerScopeCreation" )
```

However, BoxLang also offers interceptors at the request level via the internal application listener. This means that you can listen to a specific request life-cycle by using the `boxRegisterRequestInterceptor()` bif.

```cfscript
boxRegisterRequestInterceptor( ()=> listenToRequestStarts(), "onRequestStart" )
```

### [BL-274](https://ortussolutions.atlassian.net/browse/BL-274) writedump abort support

More work towards compatibility is completed.

### [BL-275](https://ortussolutions.atlassian.net/browse/BL-275) writeoutput on complex BoxLang types should call the \`toString()\` on it

This has been a heached in current CFML engines. We now detect what you send in to the `writeOutput() or echo()` commands and we will convert them to string if they are complex objects or classes.

```cfscript
fruits = [ "apple", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn" ];BL-277 implements BIFs GenerateSecretKey, Encrypt, Decrypt

writeoutput( fruits )
writeOutput( server )
```

### Native Encrypt, Decrypt and GenerateSecretKey()

We now support all encryption and decryption algorithms natively in BoxLang without ANY third-party library. Secure by default and with 3 BIFS created for this. Supported algorithms:

* `AES`
* `ARCFOUR`
* `Blowfish`
* `ChaCha20`
* `DES`
* `DESede`
* `HmacMD5`
* `HmacSHA1`
* `HmacSHA224`
* `HmacSHA256`
* `HmacSHA384`
* `HmacSHA512`
* `HmacSHA3-224`
* `HmacSHA3-256`
* `HmacSHA3-384`
* `HmacSHA3-512`


# About This Book

Learn more about this book

The source code for this book is hosted on GitHub: <https://github.com/ortus-boxlang/boxlang-docs>. You can freely contribute to it and submit pull requests. Ortus Solutions, Corp copyrights the contents of this book and cannot be altered or reproduced without the author's consent. All content is provided *"As-Is"* and can be freely distributed.‌

## Notice of Liability

‌The information in this book is distributed **as is**, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity concerning loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software, and resources described in it.

## Charitable Proceeds‌

10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - <https://www.harvesting.org/>. So please donate and purchase the printed version of this book; every book sold can help a child for almost two months.‌

## Shalom Children's Home

<figure><img src="/files/y4I02GU0O3N44vdmqmvu" alt=""><figcaption><p>Shalom Children's Party!</p></figcaption></figure>

The Shalom Children's Home (<https://www.harvesting.org/>) is one of the ministries that are dear to our hearts located in El Salvador. During the 12-year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education, and life skills training in a Christian environment. A child sponsorship program supports the home.‌

We have supported Shalom since 2010; it is a place of blessings for many children in El Salvador who either have no families or have been abandoned. This is a good earth to seed and plant.


# Authors

Information about the authors

## Luis Fernando Majano Lainez

<figure><img src="/files/z0ve0aFssWwqDhjNEHiP" alt="" width="375"><figcaption><p>Luis F. Majano</p></figcaption></figure>

Luis Majano is a Computer Engineer who has been developing and designing software systems since 2000. During economic instability and civil war, he was born in San Salvador, El Salvador, in the late 70s. He lived in El Salvador until 1995 and then moved to Miami, Florida, where he completed his Bachelor of Science in Computer Engineering at [Florida International University](http://fiu.edu).

He is the CEO of [Ortus Solutions](http://www.ortussolutions.com), a consulting firm specializing in web development, BoxLang, Java development, and open-source professional services. He is the creator of ColdBox, ContentBox, CommandBox, WireBox, TestBox, LogBox, and anything "Box," and he contributes to over 250 open-source projects. He has a passion for learning and mentoring developers so they can succeed with sustainable software practices and the usage and development of open-source software. You can read his blog at [www.luismajano.com](http://www.luismajano.com)

Luis is passionate about Jesus, tennis, golf, volleyball, and anything electronic. Random Author Facts:

* He played volleyball in the Salvadorean National Team at the tender age of 17
* His favorite books are The Lord of the Rings and The Hobbit (Geek!)
* His first computer was a Texas Instruments TI-99 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)
* He has a geek love for circuits, microcontrollers, and overall embedded systems.
* He has, as of late, become a fan of organic gardening.

> Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!
>
> "Trust in the LORD with all your heart, and do not lean on your own understanding."\
> Proverbs 3:5


# Overview

A quick overview of the BoxLang Language & Framework

### What is BoxLang?

<figure><img src="/files/2oOY8iPVTCFINrb1rTeM" alt=""><figcaption><p>BoxLang</p></figcaption></figure>

**BoxLang** is a modern dynamic JVM language that can be deployed on multiple runtimes, including all operating systems, web servers, Java application servers, AWS Lambda, Google Cloud Functions, iOS, Android, web assembly, and more.

BoxLang combines many features from different programming languages, including Java, CFML, Python, Ruby, Go, and PHP, to provide developers with a modern, fluent, and expressive syntax. It has been designed to be a highly modular and dynamic language that takes advantage of all the modern features of the JVM.

### Goals <a href="#goals-3" id="goals-3"></a>

* Be dynamic, modular, lightweight and fast
* Be 100% interoperable with Java
* Be modern, functional and fluent
* Modularity at its core
* Take advantage of the modern JVM
* TDD/BDD Fully Tested Source
* Support and adapt to multiple runtimes
* Multi-Parser design to support running different dynamic languages like CFML, Groovy and more.
* Tooling and enhanced IDE

### Key Features

1. **Dynamic Language**: BoxLang is dynamically typed, meaning you don’t need to declare types if you don’t want to. It can do type inference, auto-casting, and promotions between different types. The language adapts itself to its deployed runtime. It can add/remove/modify methods and properties at runtime, making it highly flexible and adaptable.
2. **Low Verbosity Syntax:** BoxLang is a low-verbosity syntax language. It is highly functional, fluent, and human-readable. Our intent with BoxLang is to make it highly expressive and low ceremony.
3. **Scripting**: BoxLang can be used for enterprise modular applications and highly reusable and quick scripting on the JVM or Cloud Lambda architectures.
4. **InvokeDynamic:** BoxLang has a solid core foundation based on the JVM’s `InvokeDynamic` features. This makes the dynamic language extremely fast, predictable, and adaptable.
5. **Java Interoperability:** BoxLang is 100% interoperable with Java. You can extend and implement Java objects, use Java annotations, declare classes, import classes, and even write in Java seamlessly. Thanks to `InvokeDynamic` and our BoxLang `DynamicObject` core, everything in BoxLang is interoperable with Java.
6. **Pure Functions and Closures:** BoxLang supports creating and using closures as a functional programming aspect. However, it also supports [lambda pure functions 2](https://en.wikipedia.org/wiki/Pure_function) without access to the surrounding context, which makes them extremely fast and portable. Functions are first-class citizens in BoxLang. You can define them dynamically, pass them around, and execute them whenever possible, making BoxLang a highly functional language.
7. **Event-Driven Language: BoxLang has an** internal interception event bus that can extend the language's capabilities or even your applications. You can listen to almost every part of the language, parser, and runtime or collaborate with your custom events.
8. **Modular**: BoxLang has been designed internally to support the concept of BoxLang modules that can enhance every aspect of the language or your applications built with BoxLang. BoxLang is one of the first languages you can build upon using modules. You can add new built-in functions, templating components, and new/modified functions on existing classes, functionality, Runtime Debugger, and AOP aspects, or you can listen to events within the language.
9. **Professional Open-Source:** BoxLang is a professional open-source project based on the Apache 2 license. Ortus Solutions supports every aspect of the language, and you can get a BoxLang+ subscription for professional support, extended features, and modular capabilities.
10. **Multi-Platform Development:** BoxLang has been designed to run on multiple platforms. This allows you to write adaptive code for any Operating System JVM, a servlet container web server, cloud functions (such as AWS Lambda and Google Cloud Functions), iOS, Android, or even the browser via our web assembly package. BoxLang© builds upon its language core to be deployed on almost any running platform, present or future.
11. **Portable, Fluent, Human Scheduled Tasks:** BoxLang Scheduled Tasks Framework provides a centralized and portable way to define and manage scheduled tasks on your servers and applications. Source control your tasking with our scheduling DSL.
12. **CFML Compatible:** BoxLang supports a dual parser and transpiler to execute CFML code natively (maybe more languages later). This means that you can run all your applications written in CFML within BoxLang natively. We also provide tooling to automatically transpile your CFML code to BoxLang.© if you have a + Subscription.
13. **Tooling:** We provide the core language and several tools to help developers do their job easily and efficiently. We provide a Visual Studio Code extension for the language to provide syntax highlighting, debugger, code insight, code documentation, formatting, LSP integration, and more. Our + subscribers get even more tools like enhanced debuggers, CFML transformers, and more.
14. **Ecosystem:** Even though BoxLang is a new language, **it already has an established ecosystem** since every Java and CFML library works with BoxLang. This was our priority when designing BoxLang, and it would automatically be able to integrate and run libraries from the Java and CFML ecosystems. It ships with [CommandBox](https://www.ortussolutions.com/products/commandbox) as its package manager, server manager, task manager, and REPL tool. Almost any project in [https://central.sonatype.com/ 1](https://central.sonatype.com/) and [https://www.forgebox.io](http://www.forgebox.io/) should work with BoxLang.
15. **Interactive Learning:** Start learning BoxLang with [BoxLings](https://github.com/ortus-boxlang/boxlings), an interactive CLI learning tool with progressive exercises and test-driven feedback.

### Is it CFML compatible?

BoxLang had been designed with multiple parsers—one for BoxLang and one for CFML. The CFML parser transpiles to BoxLang at runtime or can be translated to BoxLang via our [CLI tools](/getting-started/ide-tooling). We try and support as much as we can from CFML. However, we have made very different decisions, and BoxLang is a fresh start for the JVM in a new language. We have introduced a [compatibility module](https://forgebox.io/view/bx-compat-cfml) to keep old-school CFML working as it is under the BoxLang runtime.

You will have the choice to continue with CFML-compatible code or come to our new vision with BoxLang. We will support both indefinitely.

{% hint style="success" %}
Thanks to our multi-parser architecture, the following parsers are currently being developed and will be supported as modules in the BoxLang ecosystem:

* Apache Groovy Programming Language
* COBOL (yes, finally migrate to a modern language easily!)
* ...
  {% endhint %}


# Multi-Runtime

BoxLang can be deployed to multiple runtimes

<figure><img src="/files/MULyRCAXGabK8GnDXuGJ" alt=""><figcaption></figcaption></figure>

BoxLang has been designed with a lightweight, fast, and modular core. The operating system binary is a whopping **8MB** in size. This allows us to build on this binary according to the deployed runtime of choice. Check out our [installation methods.](/getting-started/installation)

### Available Runtimes

The currently available and in-development runtimes are the following:

| Runtime                                                                               | Description                                         | Status        |
| ------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------- |
| **Android**                                                                           | Ability to run BoxLang in Android Devices           | *In Planning* |
| [**AWS Lambda**](/getting-started/running-boxlang/aws-lambda)                         | Ability to run BoxLang with AWS Lambda              | **Available** |
| **Azure Functions**                                                                   | Ability to run BoxLang with Microsoft Functions     | *In Progress* |
| [**CommandBox**](/getting-started/running-boxlang/commandbox)                         | A BoxLang engine for CommandBox                     | **Available** |
| [**Docker**](/getting-started/running-boxlang/docker)                                 | BoxLang CLI, MiniServer and CommandBox images       | **Available** |
| **Desktop**                                                                           | BoxLang native Desktop Applications                 | **Available** |
| [**DigitalOcean App Platform**](/getting-started/running-boxlang/digitalocean-app)    | DigitalOcean App Platform applications              | **Available** |
| **iOS**                                                                               | Ability to run BoxLang in iOS Devices               | *In Planning* |
| [**Google Cloud Functions**](/getting-started/running-boxlang/google-cloud-functions) | Ability to run BoxLang with Google Cloud Functions  | **Available** |
| [**JSR-223**](/getting-started/running-boxlang/jsr-223-scripting)                     | Java scripting interfaces                           | **Available** |
| [**MiniServer**](/getting-started/running-boxlang/miniserver)                         | A pure Java webserver built with BoxLang            | **Available** |
| [**Spring Boot**](/getting-started/running-boxlang/spring-boot)                       | A Spring Boot starter and auto configurator         | **Available** |
| **Servlet WAR**                                                                       | A servlet capable `war`                             | **Available** |
| [**OS**](/getting-started/running-boxlang)                                            | Bare metal runtime for any OS Java runs in          | **Available** |
| **WebAssembly**                                                                       | Ability to run BoxLang as WebAssembly compiled code | **Available** |

The core impetus of BoxLang is to grow through a hierarchical approach, targeting specific runtimes with specific behaviors. For example, the concepts of FORM, URL scope, web functions, and components are available only to runtimes that support web.

**Just because a runtime isn't listed here doesn't mean BoxLang can't run on it. These are just a collection of officially supported runtimes. You can use the core runtime and run it anywhere the JVM can run. You can embed it now in Android, Azure, OpenWhisk, and more. However, once we have official runtimes, we will post them here.**

{% hint style="success" %}
All of our runtime source code can be found in our organization: <https://github.com/ortus-boxlang>
{% endhint %}

### Third-Party Runtimes

We love our community. If you have created custom runtimes for BoxLang, please let us know, and we will add them here.


# Instructions & Interpreters

BoxLang is a dynamic JSR-223 language that runs on the JVM

## Dynamic Language

BoxLang, a compiled programming language, operates in a unique way. It doesn’t run directly on your processor but is instead processed by a middleman known as the **Java Virtual Machine**. This processing occurs in the form of **Java Bytecode**, a low-level representation of your BoxLang **code**. This approach, coupled with BoxLang's dynamic nature, frees you from the typed restrictions of compile-time languages like Java or Kotlin, offering a more flexible programming experience.

This means you have greater flexibility as the engine **infers** your types. It allows you to do runtime manipulations like method injections, removals, metadata programming, etc., that a typical typed language would not allow. It also allows us to escape the dreaded compile, build, deploy cycle since the BoxLang scripts will be evaluated, compiled, and executed all at runtime. This means no more re-deploying or annoying restarts, saving you valuable time and effort.

### ByteCode

BoxLang compiles to Java Byte code using two provided algorithms.

#### Debug JIT Algorithm

This algorithm uses our Java Compiler to convert BoxLang source code into Java source code, which is then compiled into byte code using the Java Compiler API. This approach is slower but provides better debugging information or if a requirement is to deploy static Java source code.

> Please note that this is NOT the production algorithm or the default algorithm.

```mermaid
graph TD
  BoxLang-Source --> BoxLang-AST --> Java-AST --> Java-Source --> ByteCode
```

#### Production JIT Algorithm

This algorithm uses our custom BoxLang ASM compiler to convert BoxLang source code directly into Java Byte code. This approach is faster and is the default algorithm used by BoxLang.

Please note that BoxLang also provides a transpiler that converts CFML source code into BoxLang source code, which is then compiled into byte code using the production JIT algorithm. This makes BoxLang **Multi-Parser** and allows you to run ColdFusion/CFML applications on the BoxLang runtime.

```mermaid
graph TD
  BoxLang-Source --> BoxLang-AST --> ByteCode
  CFML-Source --> CFML-Transpiler --> BoxLang-AST --> ByteCode
```

### Code - Execute - Refresh - Repeat

BoxLang is a dynamic language that allows you to do just-in-time compilation, so you don't have to compile, build, and deploy. You can write your BoxLang code, execute it, make changes, and re-execute it without any downtime. This is especially useful for development and testing, as you can quickly iterate on your code without the overhead of a traditional compile-deploy cycle.

### Code Portability

BoxLang will convert your code into byte code and feed it into the Virtual Machine (VM) to execute it. This approach benefits you by allowing you to write BoxLang code once and, typically, execute it on many different operating systems and hardware platforms. Then, you can use our multi-runtime approach and deploy to multiple runtimes.

Our [first-class compiler](/getting-started/ide-tooling/boxlang-compiler) allows you to compile and package your BoxLang code for a secure and portable deployment.

### Java Interop

BoxLang is 100% interoperable with Java since it runs on the JVM. It allows you to use all third-party Java libraries, import classes, extend, implement [JSR223](/getting-started/running-boxlang/jsr-223-scripting) scripting, and much more.

```groovy
// BoxLang allows you to import Java classes
import java.lang.System
// Even add aliases to provide better context
import java.util.Date as MyDate
import ortus.boxlang.runtime.types.Array

start = new MyDate().getTime()
num = 1000
myArray = []
// Call static Java methods directly
myCopy = Array.copyOf( myArray )
println( myCopy.size() )
```

### JSR-223

BoxLang is a certified [JSR-223 dynamic language](/getting-started/running-boxlang/jsr-223-scripting) that can be used by any JVM language via the Scripting API.

### Multi-Runtime

BoxLang has been designed to run in many [different runtimes](/getting-started/running-boxlang) using our multi-runtime approach. You can run BoxLang in any OS, web server, servlet container, docker engine, AWS Lambda, Google Cloud Functions, and more coming soon.

## Running from the Command Line

This is a durable way to write BoxLang code because you save your instructions into a file. That file can then be backed up, transferred, added to source control, etc.

### An Example Scripting File

We might create a file named `hello.bxs` like this:

```groovy
println( "Hello from BoxLang, printed on: " & now() )
```

Then we could run the program like this `boxlang hello.bxs` and get the following result:

```
Hello from BoxLang, printed on: {ts '2024-05-21 22:07:19'}
```

### BoxLang REPL

BoxLang ships with a memory REPL (Read Eval Print Loop) interface that you can use to test out the language. Just run the `boxlang` binary, and you are ready to roll:

<figure><img src="/files/DWOduh8VNpBNE6n9Kqby" alt=""><figcaption></figcaption></figure>

Keep reading our guides as you learn more about BoxLang.


# CommandBox CLI

CommandBox is the de facto standard for BoxLang development and execution.

<div align="center"><figure><img src="/files/JbA8JPCMKF6iozym4pcx" alt=""><figcaption></figcaption></figure></div>

CommandBox amalgamates many tools and borrows concepts from NPM, Grunt/Gulp, Maven, ANT, Node, and more. Features include:

* Operation System integration for executing commands
* Ability to create and execute commands built using BoxLang and CFML
* ForgeBox integration for cloud package management and installations
* ColdBox Platform, TestBox, and ContentBox CMS Integrations
* Integrated servlet server with rewrite capabilities
* Ability to create command recipes and execution
* Ability to interact with users via CLI and create workflows and

  installers
* Ability to execute workflows and tasks

## Installation

CommandBox is a Java-based executable running on the most recent desktop operating systems (Linux, Mac OS X, Windows). Since it is a command line tool that uses a shell interface, it does not require an operating system using a GUI. Below is a simple guideline to get you up and running, but an [in-depth guide](https://commandbox.ortusbooks.com/getting-started-guide) can be found here: <https://commandbox.ortusbooks.com/setup>

### Requirements

* 256MB+ RAM
* 250MB+ free hard drive space
* Multi-core CPU recommended
* JRE/JDK 21+

## Getting Started

We have created a small [getting started guide](https://commandbox.ortusbooks.com/getting-started-guide) to give you enough skills to move forward with any CommandBox development. You can find it here: [https://commandbox.ortusbooks.com/content/getting\_started\_guide.html](https://commandbox.ortusbooks.com/getting-started-guide)


# Quick Syntax Guide

Quickly learn what the BoxLang language offers.

This guide provides a quick overview of BoxLang syntax styles, intricacies, operators, and features. It aims to assist developers from other languages in their BoxLang development journey. BoxLang has been heavily inspired by many different languages, including Java, CFML, Groovy, Kotlin, Ruby, PHP, and more.

{% hint style="info" %}
After reviewing this guide, reinforce the concepts with [BoxLings](https://github.com/ortus-boxlang/boxlings), an interactive CLI exercise tool for learning BoxLang by doing.
{% endhint %}

{% hint style="success" %}
If you are a CFML developer, check out also our [CFML Guide.](/getting-started/overview/syntax-style-guide/cfml)
{% endhint %}

## 📋 Table of Contents

* [Dynamic & Loose Typing](#dynamic--loose-typing)
* [Any by default](#any-by-default)
* [High Precision Mathematics](#high-precision-mathematics)
* [Numeric Literal Separators](#numeric-literal-separators)
* [Case Insensitive Functionality](#case-insensitive-functionality)
* [BIFs = Built-In Functions](#bifs--built-in-functions)
* [BoxLang Components](#boxlang-components)
* [Expression Interpolation](#expression-interpolation)
* [Multi-Line Strings](#multi-line-strings)
* [Multi-Variable Assignments](#multi-variable-assignments)
* [Switch Statements](#switch-statements)
* [Catch any exception](#catch-any-exception)
* [Multi-Catch Exceptions](#multi-catch-exceptions)
* [No Semicolons, almost](#no-semicolons-almost)
* [Scopes](#scopes)
* [Full Null Support](#full-null-support)
* [CastAs Operator](#castas-operator)
* [Human Operators](#human-operators)
* [InstanceOf Operator](#instanceof-operator)
* [Data Types](#data-types)
* [Arrays are Human](#arrays-are-human)
* [Array/Struct Literal Initializers](#arraystruct-literal-initializers)
* [Unmodifiable Objects](#unmodifiable-objects)
* [Truthy/Falsey](#truthyfalsey)
* [Imports & Class Locators](#imports--class-locators)
* [Null Coalescing aka Elvis Operator](#null-coalescing-aka-elvis-operator)
* [Safe Navigation Operator](#safe-navigation-operator)
* [Assert](#assert)
* [Functional](#functional)
* [BoxLang Classes](#boxlang-classes)

## Dynamic & Loose Typing

BoxLang variables are **dynamic** and **type-inferred**. We try our best to infer which type you are trying to set for variables at compile-time, but they can completely change at runtime. You use the `var` keyword to specify a variable within functions or declare them inline if you are in a `bxs` or `bxm` script file.

{% hint style="info" %}
File Types:

* `bx` - A BoxLang class
* `bxs` - A BoxLang scripting file
* `bxm` - A BoxLang templating markup file
  {% endhint %}

```groovy
// Infered as 'String'
name = "boxlang"

// Inferred as Integer
age = 1
// But I can redeclare it to a string if I need to
age = "one"

// Inferred as Boolean
isActive = false

// Inferred as Date
today = now()

// Use the `var` keyword to define function-local only variables
function test(){
  var name = "hello"
}

```

You can also add types to arguments within functions or omit them, and it will default to `any,` which means, well, anything:

```cfscript
function add( required numeric a, required numeric b, boolean print = false ){

}
```

As you can see, not only can we make arguments **required** or not, but we can also add **default** values to arguments. BoxLang does not allow method overrides since basically, every method can take an infinite number of arguments, defined or even NOT defined.

We can also do type promotions and auto-casting from types that can be castable to other types. So, if we call our function like this:

```groovy
// we auto cast 1 to numeric, "true" to boolean
add( "1", 345, "true" )
```

This is handy as we really really try to match your incoming data to functional arguments.

## `Any` by default

If they are not specifically typed, all arguments and variable declarations are of `any` type. This means they will be inferred at runtime and can change from one type to another.

```cfscript
// Variables declared in a script are of any type and inferred
name = "luis"

function hello( name ){
    // argument name can be anything
}
```

## High Precision Mathematics

By default, BoxLang will use high-precision mathematics by evaluating your numbers and determining the right type for them. If the numbers are whole and short enough, they will be stored in an `Integer` or `Long`. If they contain decimals, they will be a `BigDecimal` and if you do math on them, the result will be the most precise of the two inputs. You don't have to be knowing or addressing the numerical types, we will do that for you.

{% hint style="warning" %}
You can change this [setting in the configuration to false](/getting-started/configuration#use-high-precision-math) and it will use basic Double mathematics and it will be up to you when to use high precision evaluations.
{% endhint %}

You can store a larger number like:

```undefined
123123123123123123123123123
```

in a `Double`, but behind the scenes, not all of that is stored. All Java tracks is

```undefined
1.2312312312312312 E 26
```

which means some digits of the original number are gone. So, if you run the math equation

```undefined
11111111111111111111 + 22222222222222222222
```

you get:

* Windows calculator: `33333333333333333333`
* BoxLang: `33333333333333333333`

You may not be too worried about the use case of very large numbers, but the floating point math has bitten every single developer who’s been around long enough and can wreak havoc on the simplest of math calculations.

### Level of Precision

Furthermore, Java’s BigDecimal class allows you to choose the level of precision you want to use. Java 21 defaults to “unlimited” precision, but we’ve dialed that back to the IEEE 754-2019 decimal128 format, which has 34 digits of precision and uses a rounding mode of HALF\_EVEN. You can change the amount of precision BoxLang uses for BigDecimal operations at any time like so:

```cpp
import ortus.boxlang.runtime.types.util.MathUtil;
MathUtil.setPrecision( 100 );
```

### Only When Needed

BoxLang has a smart parser that will always store a number in the smallest package possible, opting to promote the type only when necessary.

```ini
n = 1;  // smaller than 10 digits stores in an Integer
n = 11111111111111; // Smaller than 20 digits stores in a Long
n = 111111111111111111111111111; // Anything larger stores in a BigDecimal
n = 12.34;  // All floating point values, store in a BigDecimal
```

The “bigger” types are contagious. So if you add together an `Integer` and a `Long`, we store the result in a `Long`. If you add a `Long` and a `BigDecimal` together, we store the result in a `BigDecimal`. The idea is always to keep things small and fast until we can’t any longer.

## Numeric Literal Separators

Numeric placeholders allow you to place underscore characters (`_`) inside of a numeric literal for readability. Take a number like this

```ini
n = 1000000000
```

That’s 1 billion. Or was it 1 million? Or maybe it was 100 million… *pauses to re-count*.\
With numeric placeholders, your code can look like this:

```ini
n = 1_000_000_000
```

Ahh, so it *was* 1 billion! There are no rules on where you can place the underscores, so long as they are INSIDE the number and not leading or trailing. You can also place numeric separators in decimals:

```ini
n = 3.141_592_653_59
```

and in the exponent of scientific notation

```undefined
1e2_345
```

These underscores are thrown away at compile time. They are not represented in the bytecode and will not appear anywhere in your running app. They are purely for readability in your source code.

## Case Insensitive Functionality

Most things in BoxLang can be done with **no** case sensitivity by default. You can enable case sensitivity in many functions and components, but we try to be insensitive as much as possible :). Here are a few observations where access is case-insensitive by nature:

* variable access in any scope
* function calls, even to Java classes
* function arguments, even on Java classes
* class creation, even on Java classes

```cfscript
name = "luis"
// Name can be outputted in any case
println( "Hi, my name is #NamE#" )

// Even maps or arrays
myMap = { name : "luis", age : 12 }
println( "My name is #mymap.NAME# and my age is #mymap.age#" )
```

{% hint style="info" %}
Internally we leverage a `Key` class that provides us with case insensitivity. Each map has a `Key` as the, well, key.
{% endhint %}

## BIFs = Built-In Functions

BoxLang is inspired by many languages and offers [built-in functions](/boxlang-language/reference/built-in-functions) you can call from anywhere in your code. BoxLang ships with a plethora of functions that can be used headlessly or as member functions on different data types. Modules can also collaborate functions globally. There is no need to import them, they are automatically imported.

{% hint style="info" %}
Please check out the [reference section](/boxlang-language/reference) for all the contributed core BIFs.
{% endhint %}

```cfscript
// Runs the println() bif and the now() bif
println( "Hola from #now()#" )
```

{% hint style="success" %}
To get a sense of all the BIFs registered in your runtime, do a

`writedump( getFunctionList() ) or println( getFunctionList() )`
{% endhint %}

### Member Functions

Member functions are special functions attached to all data types in BoxLang, whether they are structs, arrays, strings, numbers, dates, Java objects, classes, etc. We provide tons of member functions, but developers can also contribute their own via BoxLang modules. All member functions map back to built-in functions (BIFs).

```cfscript
myArray = [1,2,3,4]
println( myArray.count() )

fruitArray = [
    {'fruit'='apple', 'rating'=4},
    {'fruit'='banana', 'rating'=1},
    {'fruit'='orange', 'rating'=5},
    {'fruit'='mango', 'rating'=2},
    {'fruit'='kiwi', 'rating'=3}
]
favoriteFruites = fruitArray.filter( item -> item.rating >= 3 )
```

{% hint style="info" %}
You can find all the collection of member functions in our [types](/boxlang-language/reference/types) section.
{% endhint %}

## BoxLang Components

Components are a special construct in BoxLang that allows the core and modules to contribute functionality that cannot be expressed in a simple BIF. This is for more complex contributions to the language like HTTP frameworks, FTP, Email, PDF tooling, Image tooling, etc. A simple BIF would not cut it. [These components](/boxlang-language/reference/components) can be called from anywhere in your source code, either in the script or in the templating language. Components usually are statements and not expressions. They also allow you to have bodies that can produce output if needed.

```java
bx:http url=apiURL result="result" {
  bx:httpparam type="header" name="Accept" value="application/json";
}

bx:timer variable="myTimer"{
  .. this code to time...
}
```

As you can see, they all start with the prefix of `bx:`and the name of the registered component. Each component can have attributes and nested components as well. The cool thing about components, is that they translate incredibly well for templating so that you can create rich templating tags as well.

```xml
<bx:query name="getUser" datasource="myDatasource">
    SELECT id, firstName, lastName, email
    FROM users
    WHERE email = <bx:queryparam value="#form.email#" cfsqltype="cf_sql_varchar">
</bx:query>
```

We ship several components as core:

* `Abort` - Abort the request
* `Application` - Update/Configure the running virtual application
* `Associate` - Associate variable data with a child or parent component
* `Cache` - Caches content
* `Directory` - Directory-based calls
* `DBInfo` - Get database metadata and information
* `Dump`- A cool UI/console dumper of data, simple or complex
* `Execute`- Execute OS binaries
* `Exit`- Exit from nested executions of components
* `File` - File-based calls
* `Flush`- Force flush the output buffer in BoxLang either to Web or Console or whatever runtime you are on.
* `Header`- Allows you to specify headers that modify the current response.
* `HTTP` - HTTP Calls
* `Include`- Include another template file into another template. Inception.
* `Invoke`- Invoke dynamic methods on dynamic objects with dynamic arguments
* `Lock`- Easy code locking and segmentation
* `Log`- Write to our log files
* `Loop`- Looping constructs for native or Java types
* `Module`- Call custom templates in an isolated fashion
* `Object`- Create BoxLang, Java, Custom objects
* `Output`- Wrap code/HTML to produce output to the buffers
* `Param`- Parameterize variables with default values if not defined
* `Query` - Execute quick queries
* `SaveContent`- Execute content and save it's output into a variable using template stylings
* `Setting`- Set global BoxLang setting directives
* `Silent`- Wrap code so it doesn't produce any output or whitespace
* `Sleep`- Sleeps the thread for the requested amount of time
* `StoredProc` - Execute stored procedures
* `Transaction` - Start JDBC Transaction demarcations
* `Timer` - Time code between it
* `Thread` - Create threaded code
* `Throw`- Throw an exception
* `Trace`- Trace debugging messages to the console or debugging facilities
* `XML`- Build or work with XML content
* `Zip`- Allows you to compress/uncompress and manipulate zip/gzip files

However, check out our [modules](/boxlang-framework/modularity) section for more components, and you can also build your own.

## Expression Interpolation

BoxLang can interpret ANYTHING within `#` as an expression. This can be used for output, assignments, and much more.

```cfscript
"#now()# is a bif, and this #12 % 2# is a math expression, and more!"
```

## Multi-Line Strings

In Java, you can declare a multi-line string easily (JKD15+) by using the triple (`"""`) quote marks.

<pre class="language-java"><code class="lang-java">public String getText(){
<strong>   return """
</strong>   My text block
      with nice identation

      -- Luis Majano""";
}
</code></pre>

It is by far the most convenient way to declare a multiline string as you dont have to deal with line separators or indentation spaces. In BoxLang, you only need 1 quote (`"`), we will take care of the rest!

```javascript
function getText(){
   return "
   My text block
      with nice identation

      -- Luis Majano";
}
```

## Multi-Variable Assignments

BoxLang supports the concept of multi-variable declaration and assignments by just cascading variables using the `=` operator.

```cfscript
name = threadname = taskName = "I am Spartacus!"
```

This will create the 3 variables in the `variables` scope with the value "I am Spartacus!"

## Switch Statements

The BoxLang switch statements can work on any literal but also on any expression

```cfscript
switch( expression ) {
    case value : case value2 :{
        break;
    }

    default : nothing
}
```

## Catch \`any\` exception

BoxLang allows you to catch `any` exception using our `any` operator

```
try{
    .. funky code here
} catch( any e ){

    // We just caught every single exception known to man!

}
```

## Multi-Catch Exceptions

In BoxLang you can catch multiple exceptions by using the pipe | operator. They can be both BoxLang exceptions or Java exception types:

```cfscript
catch( foo.com | brad | com.luis.majano e ) {}
```

## No Semicolons, almost

Semicolons are almost always optional except in some situations:

* `property` definitions in classes
* Component calls with no body
* Component child calls

{% hint style="success" %}
Components in BoxLang have contributed functionality that is not core language and can be used in a statement syntax. Examples are mail, http, ftp, etc.
{% endhint %}

```java
// Properties
class{

    property name="hello";
    property lastName;

}
```

```java
// Components

// No body, requires ;
bx:flush;

// With inline body ; not needed
bx:flush{}

// With Body using {}, so no ; needed
bx:savecontent variables="test"{
    echo( "hello" )
}

// With child calls ; needed
bx:http url=apiURL result="result" {
    bx:httpparam type="header" name="Accept" value="application/json";
    bx:httpparam type="header" name="x-test" value="test";
}
```

## Scopes

BoxLang offers many different persistence and variable scopes depending on where and what you are. All scopes in BoxLang are backed by the Map interface, which in BoxLang land are called Structures. They are case-insensitive by default; you can pass them around as much as you like.

#### Scripts (`bxm, bxs`)

Scripts can be written in full script (`bxs`) or using our templating language (`bxm`).

* `variables` - Where all variables are stored
* Unscoped variables go to the `variables` scope in a script

#### Classes

BoxLang supports all Object-oriented constructs know in several languages. We expand on the areas of metaprogramming and dynamic typing.

* `variables` - The private scope of the class
* `this` - The public scope of the class and also represents the instance
* `static` - The same as Java, a static scope bound to the blueprint of the class
* Unscoped variables go to the `variables` scope in a class

#### Functions/Lambdas/Closures

BoxLang supports 3 types of Functions.

* `local` - A local scope available only to the function
* `arguments` - The incoming arguments
* `variables` - Access to the script or class private scope
* `this` - Access to the class public scope
* Unscoped variables go to the `local` scope in a function by default

#### Persistence Scopes

BoxLang and some of it's runtimes also offer out of the box scopes for persistence.

* `session` - stored in server RAM or external storage tracked by a unique visitor
* `client` - stored in cookies, databases, or external storages (simple values only)
* `application` - stored in server RAM or external storage tracked by the running BoxLang application
* `cookie` - stored in a visitor's browser (Web Only)
* `server` - stored in server RAM for ANY application for that BoxLang instance
* `request` - stored in RAM for a specific request ONLY
* `cgi` - read-only scope provided by the servlet container and BoxLang (Web Only)
* `form` - Variables submitted via HTTP posts (Web Only)
* `URL` - Variables incoming via HTTP GET operations or the incoming URL (Web Only)

{% hint style="info" %}
Please visit our [scopes](/boxlang-language/syntax/variable-scopes) section to find out much more about scopes in BoxLang.
{% endhint %}

### Scope Hunting

When you access a variable without specific scope access, BoxLang will try to find the variable for you in its nearest scope. This is done internally via a context object, which can be decorated at runtime depending on WHERE the code is being executed (CLI, web, lambda, android, etc) Example:

```cfscript
function( name ){

    // add to data, which has no scope and no arguments exist
    // so it looks for it in the variables scope
    data.append( name )

    // Looks in arguments first
    return name;
}
```

Check out our [Scopes](/boxlang-language/syntax/variable-scopes) section to learn more about scope hunting.

## Full Null Support

`null` is a real thing! It's nothing but real! We support the `null` keyword, assignments, and usage just like Java. It follows the same rules.

## CastAs Operator

BoxLang has a natural casting operator that is fluent and readable: `castAs {expression}.` It can be an expression since the right-hand side can be dynamic. Unquoted identifers will be considered a string literal. Any other expression will be evaluated at runtime.

```java
myJavaClass( value castAs long )

return {
    age : value castAs int,
    tags : value castAs String[],
    isActive : "#value#" castAs Boolean
    spam : value castas "#DynamicType#"
}
```

You can also use our handy [`javaCast`](/boxlang-language/reference/built-in-functions/system/javacast)`()` BIF if you need to, but this is integrated into the language.

## Human Operators

You can see all the supported operators on our operator's page. We have several fluent operators using English instead of symbols, and some that are only English-based. You can see all the supported [operators](/boxlang-language/syntax/operators) on our operator's page.

| Symbol Operator | Human Operator          | Hint                                                                                                  |
| --------------- | ----------------------- | ----------------------------------------------------------------------------------------------------- |
| `==`            | `eq`                    |                                                                                                       |
| `!=, <>`        | `neq`                   |                                                                                                       |
| `>`             | `gt`                    |                                                                                                       |
| `>=`            | `gte`                   |                                                                                                       |
| `<`             | `lt`                    |                                                                                                       |
| `<=`            | `lte`                   |                                                                                                       |
|                 | `contains, ct`          | <p>Returns true if the left operand contains the right one.<br><code>'hello' contains 'lo'</code></p> |
|                 | `does not contain, nct` | Negated Contains                                                                                      |
| `!`             | `not`                   |                                                                                                       |
| `&&`            | `and`                   |                                                                                                       |
| `\|\|`          | `or`                    |                                                                                                       |
|                 | `XOR`                   | Exclusive OR                                                                                          |
|                 | `EQV`                   | Equivalence                                                                                           |
|                 | `IMP`                   | Implication                                                                                           |
| `%`             | `mod`                   | Modulus                                                                                               |

## InstanceOf Operator

Like other languages, we also offer an `instanceOf` operator alongside a nice BIF: `isInstanceOf()`. You can also use negation using our lovely `not` operator.

```java
isInstanceOf( obj, "Map" )

if( obj instanceOf "String" )
if( obj instanceOf "MyUser" )
if( obj not instanceOf "Integer" )

```

## Data Types

All Java types can be used alongside the core BoxLang types:

* `any`
* `array`
* `UnmodifiableArray`
* `binary`
* `boolean`
* `class`
* `closure`
* `date`
* `double`
* `guid`
* `function`
* `float`
* `integer`
* `lambda`
* `numeric`
* `number`
* `query`
* `UnmodifiableQuery`
* `string`
* `struct`
* `UnmodifiableStruct`
* `uuid`

## Arrays are Human

Arrays in BoxLang start at 1, not 0. End of story!

## Array/Struct Literal Initializers

Arrays and Structs in BoxLang can be created using literal constructs. Please note that values within the literal declarations can also be expressions.

```cfscript
// empty array
array = []
// array with data
array = [ 1, 23, 234 ]

// empty struct
myMap = {}

// struct with data
myMap = { age:1, test: now() }

// ordered struct with data
myMap = [ age:1, test: now(), anotherKey: "name" ]
myMap.each( ::println )

// Nesting
myArray = [
    {
        name: "BoxLang",
        type: "JVM Dynamic Language",
        version: "1.0.0",
        tags: ["dynamic", "JVM", "scripting", "modern"],
    },
    {
        name: "ColdBox",
        type: "MVC Framework",
        version: "7.0.0",
        tags: ["framework", "MVC", "CFML", "enterprise"],
    },
    {
        name: "TestBox",
        type: "BDD Testing Framework",
        version: "6.1.0",
        tags: ["testing", "BDD", "TDD", "automation"],
    },
];

println( myArray );
```

{% hint style="success" %}
**Tip:** Also remember you can nest arrays into structs and structs into arrays
{% endhint %}

### Trailing Commas

BoxLang supports trailing commas when defining array and struct literals. If you miss a dangling comma, we won't shout at you!

```groovy
myArray = [
    "BoxLang",
    "ColdBox",
    "TestBox",
    "CommandBox",
]
println( myArray )

myStruct = {
    name: "BoxLang",
    type: "JVM Dynamic Language",
    version: "1.0.0",
}
println( myStruct )
```

## Unmodifiable Objects

BoxLang supports the concept of unmodifiable objects: arrays, structures or queries. These are objects that cannot be modified once they are created. You can also use two BIFs for working with these types:

* `toUnmodifiable( array or structure or query)` - Make an array or structure unmodifiable
* `toModifiable( array or structure or query )` - Make an array or structure modifiable

These are also available on the types as member methods

```java
myArray = [ 1, 2, 3, 4, 5].toUnmodifiable()
myData = { id: 1, when: now() }.toUnmodifiable()
```

## Truthy/Falsey

BoxLang Truthy and Falsey are concepts used in programming to determine the "truth" of a value in a Boolean context. In many programming languages, values other than true and false can be evaluated for their truthiness. Understanding truthy and falsey values is crucial for writing effective and accurate code when evaluating conditions or performing logical operations.

### **Truthy values**

* positive numbers (or strings which can be parsed as numbers)
* boolean true
* string “true”
* string “yes”
* array with at least one item
* query with at least one row
* struct with at least one key

### **Falsey values:**

* A `null` value
* The number 0 or string “0”
* boolean false
* string “false”
* string “no”
* empty arrays
* empty queries
* empty structs

## Imports & Class Locators

BoxLang offers the ability to import both BoxLang and Java classes natively into scripts or classes.

```java
// Import java classes
import java:java.io.IOException
import java:java.nio.file.FileSystems
import java:java.nio.file.Path

// Import BoxLang classes
import models.User
import models.cborm.MyService

// Imported classes are class references
user = User( "Luis" )
```

Works just like Java. However, you will notice a nice `java:` prefix. This is called an class locator prefix. BoxLang supports these out of the box:

* `java:` - Java classes to import or instantiate
* `bx:` - BoxLang classes to import or instantiate (Default, not required)

{% hint style="warning" %}
You can also remove the `java:` prefix and BoxLang will try to locate the class for you. Careful, as it will scan all locations.
{% endhint %}

#### Import Aliases

You can also alias imports to provide less ambiguity when dealing with classes with the same name:

```java
// Import java classes
import java:java.nio.file.Path as jPath
import models.utils.Path

myJavaPath = new jPath()
myBxPath = new Path()
```

All the object resolvers prefixes can be used anywhere a class or path is expected:

* Creating classes and instances: `createObject(), new, Class.init(), Class()`
* Using `imports`
* Extending classes
* Implementing interfaces

```java
class implements="java:java.util.List" {

}

class extends="java:ortus.boxlang.runtime.types.Struct"{

}
```

## Null Coalescing aka Elvis Operator

BoxLang supports the null coalescing operator `?:` to allow you to evaluate if values are empty or null. This is **not** a shortened ternary as other languages.

```
( expression ) ?: 'value or expression'
```

This tests the left-hand side of the `?:` and if its `null` then it will evaluate the right expression or value. This can be used on if statements, assignments, loops, etc.

## Safe Navigation Operator

BoxLang supports safety navigation on ANY object that can be dereferenced: structs, maps, classes, etc. This basically allows you to test if the value exists or not and continue dereferencing or return null

```cfscript
age = form.userdata?.age;

fullName = userClass?.getFullName()
```

Imagine how tedious this code is

```java
if( order ){

    if( order.hasCustomer() ){
        if( order.getCustomer().hasAddress() ){
            println( order.getCustomer().getAddress() )
        }
    }

}
```

Now let's transform this code:

```java
println( order?.getCustomer()?.getAddress() )
```

## Assert

BoxLang offers an `assert` operators that will evaluate an expression and if the expression is falsey it will throw an assert exceptions.

```groovy
// Asserts that the name is truthy
assert name

// Assert an expression
assert myService.hasData()
assert name.length() > 3

// Assert a lambda/closure result.
assert ()-> { do something }
assert ()=> { do something }

```

## Functional

BoxLang functions are first-class citizens. That means you can pass them around, execute them, dynamically define them, inject them, remove them, and so much more.

It has three major functional types:

* **UDF—User-Defined Function**—Can be created on any scripting template or within Classes. They carry no context with them except where they exist.
* **Closures** are *named* or *anonymous* functions that carry their surrounding scope and context with them. It uses the fat arrow `=>` syntax.
* **Lambdas** are *pure* functions that can be *named* or *anonymous* and carry **NO** enclosing scope. They are meant to be pure functions and produce no side effects. Data in, Data out. It uses the skinny arrow `->` Syntax.

{% code title="hola.bxs" %}

```javascript
// This is a script that can define functions

// A scripting UDF
function sayHello(){
    return "Hola!"
}

// Execute the UDF
println( sayHello() )
```

{% endcode %}

{% code title="MyClass.bx" %}

```java
// Some class UDFs
class{

    function init(){
        return this
    }

    function sayHello(){
        return "Hola!"
    }

}
```

{% endcode %}

{% code title="test.bxs" %}

```javascript
// This script uses the defined class above
myClass = new MyClass()

// Let's create an alias for the function
// Functions are first-class citizens in BoxLang
// They can be added, removed, mixed at runtime
myClass.hola = myClass.sayHello

// Let's remove the sayHello function
myClass.sayHello = null
// Or use a global BIF call to remove it
structDelete( myClass, "sayHello" )

println( myClass.hola() )
```

{% endcode %}

Let's write up another script that leverages closures and lambdas.

{% code title="test.bxs" %}

```javascript
// Named closure
myClosure = item => item++;
myClosure( 1 )

// Anonymous Closure
[1,2,3].filter( item => item > 2 )

// Named Lambda
myLambda = item -> item++;
myLambda( 1 )

// Anonymous Lambda
[1,2,3].filter( item -> item > 2 )
```

{% endcode %}

### `Public` by default

All functions and classes are `public` by default, so there is no need to add the `public` identifier if you don't want to. This creates a very nice and low-verbosity approach to function declaration:

```cfscript
function hello(){}
// Same as:
public function hello(){}

// private
private function getData(){}

// protected
protected function bindData(){}
```

### Non-required arguments by default

All arguments are NOT required by default and will be defaulted to `null` if not passed. You can use the `required` identifier to mark them as required.

```cfscript
function save( required user, boolean transactional = false, Logger logger ){

}
```

### Default Arguments

You can create defaults for arguments, which can be literal or actual expressions:

```cfscript
function save( transactional = true, data = {}, scope = "#expression#" ){
}

function hello( name = variables.defaultName ){
    println( "Hola #arguments.name#" )
}
```

### Argument Collections

Similar to var arguments in Java, BoxLang allows the `arguments` scope to be completely be variable. meaning you can declare the arguments, but you can pass as many as you like and they will all be added into the `arguments` scope.

Another feature is that you can bind and apply these arguments at function execution time from any map or structure via the `argumentCollection` special argument. This allows you to collect arguments and dispatch the function call, and BoxLang will match the argument names for you. This can be great for dynamic argument collection, form collection, JSON packets, etc.

```cfscript
function save( name, age, isActive, logIt=false ){
    .. Do your thing here!!
}

// Call the save using a map/struct
myMap = { name: "test", age: 40, isActive: true }
// Use the special argumentCollection designator
save( argumentCollection : myMap )
```

This is a great time saver.

### Auto-casting Arguments & Return Values <a href="#auto-casting-argument-and-return-value-types" id="auto-casting-argument-and-return-value-types"></a>

In BoxLang, we actively cast the incoming argument value to the specified declared argument.

```cfscript
function setAge( numeric age )
```

BoxLang will try to auto cast the incoming argument to the `numeric` type in this instance.

It will also auto cast the outgoing return value for you. So if your function specifies that the return value is a boolean, but you return a string, it will auto cast it to boolean for you.

```cfscript
function Boolean isAlive(){
    return "yes"
}
```

## BoxLang Classes

BoxLang classes are enhanced in many capabilities compared to Java, but they are similar to Groovy and CFML.

* Automatic `package` definition
* Automatic Hash Code and Equals methods
* Automatic constructor created for you based on the defined `properties`
* No need to add a name to the `class` definition, we use the filename
* Implements by default `IClassRunnable, IReferenceable, IType, Serializable`
* Automatic getters and setters for any `property` definition
* Automatic implicit property accessors and mutators
* Allows for pseudo constructor blocks for initializations and more (Space between last property and first function)
* Output is **false** by default for pseudo-constructors and functions
* Automatic metadata registration into the `$bx` BoxMeta programming object
* Allows for single inheritance
* Allows for interfaces
* Allows for `static` blocks, functions, and properties
* Allows for `final` properties (coming soon)
* Allows for `lazy` properties (coming soon)
* Allows for property observers (coming soon)
* Allows for scope observers (coming soon)
* Functions in a class can have different visibilities: `private, public, protected, remote`

Check out our [Classes](#classes) section for further information

### Properties, not Fields

BoxLang classes can define properties as data members; they are not called fields and are always `private` meaning they will be stored in the `variables` scope. You can define them in short or long format. Please note that properties do require a semi-colon, as they can be very ambiguous.

All properties are stored in the `variables` scope.

#### Short Form

The short form allows for `property [type=any] name [default=expression];`

```cfscript
class{

    // No type means `any`, no default means null
    property firstName;
    // A numeric age with a default value of 1
    property numeric age default=1;
    // A struct data with a default struct literal
    property struct data default={ name:"this", age : 3, whatever : now() };

}
```

#### Long Form

The long form allows for name-value pairs. We distinguish some value pairs from those we don't, and those we don't will be added as metadata to the property.

```cfscript
class{

    property name="firstName" type="string" default="boxlang";
    property name="age" type="numeric";

    property name="data"
        type="struct"
        default={ name:"this", age : 3, whatever : now() };

}
```

Check out our [properties](/boxlang-language/classes/properties) section for all valid attributes. Here are a few common ones

* `default` - The property's default value
* `name` - The property's name
* `getter` - Boolean indicator to generate or not the getter for the property. Default is **true**
* `required` - If the property requires a value or not.
* `setter` - Boolean indicator to generate or not the setter for the property. Default is **true**
* `type` - The default type of the property defaults to `any`

{% hint style="info" %}
BoxLang also advertises Class creations, so modules can collaborate with extra metadata and properties or inspect the properties and act on them.

Our dependency injection framework does this.
{% endhint %}

### Automatic Constructor

Constructors in classes for BoxLang are not overloads but a single `init()` method. However, by default we create one for you. It can also take in named parameters or an `argumentCollection` to initialize all properties. You can construct BoxLang and Java classes with `new`, by calling `.init()` on the class reference, or by invoking the class reference directly.

{% code title="User.bx" lineNumbers="true" %}

```cfscript
class{

	property name;
	property email;
	property isActive;

}

// Create a new user with no data
user = new User()
user = User.init()
user = User()

// Create one with named params
user = new User( name: "BoxLang", email: "info@boxlang.io", isActive: true )
user = User.init( name: "BoxLang", email: "info@boxlang.io", isActive: true )
user = User( name: "BoxLang", email: "info@boxlang.io", isActive: true )

// Create one with an arg collection
myArgs = { name: "BoxLang", email: "info@boxlang.io", isActive: true }
user = new User( argumentCollection: myArgs )
user = User.init( argumentCollection: myArgs )
user = User( argumentCollection: myArgs )
```

{% endcode %}

{% hint style="danger" %}
If you create your own `init()` then it's your job to initialize your class :)
{% endhint %}

### Annotations

BoxLang annotations can be added to `properties`, `functions`, and `classes`. Using the following pattern:

```java
@annonationName
// or...
@annonationName( value, value, value )
```

The `value` is a literal expression (string, boolean null, number, array, or struct) or an identifer. Since runtime variables aren't allowed here, identifiers will be treated as quoted strings. If no value is supplied, then omit the parentheses.

{% hint style="success" %}
**Tip:** Remember that string literals you can use quotes, single quotes or none.
{% endhint %}

```java
@singleton
class{

    @inject
    property name="wirebox";


    @returnFormat( json )
    function getData(){
        return data
    }

    @cache( true )
    @returnFormat( "xml" )
    function getXMLData(){

    }

}
```

You can add as many as you like to the target locations without creating annotation classes or boilerplate.

### Metadata: $bx

All of these annotations and metadata can be retrieved at runtime by using the `getMetadata()` or `getClassMetadata()` bifs. You can also look at the `.$bx` property in every boxlang object. Which contains not only the metadata about each object, but ways to do meta-programming with it. Like adding/modifying/removing properties/functions/annotations.

Extra metadata can be added to functions, properties, classes, or annotations.

```java
@singleton
@transientCache( false )
@myMetadata( hello, "another value" )
class{

}

myClass = new MyClass()
writeOutput( myClass.$bx.meta ) or println( myClass.$bx.meta )
```

The `$bx` object is the BoxLang meta-object. It contains all the necessary metadata information about an object, it's Java class representations and useful methods for meta-programming. From it's Java Class, to functions, properties, data, etc. It can be used on ANY BoxLang Type. Here are the properties in the `$bx` object available to you. It also contains many methods that exist in the `BoxMeta` object.

* `meta` - A struct of metadata about the class
* `$class` - The Java `Class` that represents your class

### Getter and Setters

By default, automatic **getters** and **setters** for properties are enabled. You can disable them all for the class or one by one. All the setters return an instance of `this`. You can also override them as you see fit.

```cfscript
class{

    property name="firstName" type="string" default="boxlang";
    property name="age" type="numeric"

    // Override the getter
    function getAge(){
        // log it
        return variables.age
    }

    // Override the setter
    function setFirstName( firstName ){
        // Log here
        variables.firstname = arguments.firstName;
        return this;
    }

}

myClass = new MyClass().setFirstname( "luis" );
```

### Implicit Accessors

Implicit accessor/mutator invocations are on by default in BoxLang. You can disable them by adding the `invokeImplicitAccessor` annotation to false. Implicit accessors allows you to invoke getters and mutators as if you are working properties on a class. It's just syntactical sugar to make your code look a lot less verbose when calling getters and setters.

```cfscript
class{
    property name="firstName" type="string" default="boxlang";
    property name="age" type="numeric"
}

// Invoke Using implicit invokers
myClass = new MyClass();
myClass.age = 23
printLn( myClass.age )

// Disable invokers
@invokeImplicitAccessor( false )
class{
    property name="firstName" type="string" default="boxlang";
    property name="age" type="numeric"
}
```


# Differences From CFML

A quick guide on key differences and issues when migrating from CFML

{% hint style="danger" %}
CFML compatibility in BoxLang is now stable and production-ready. We are committed to continuing to expand and refine compatibility. Please check back periodically for the latest updates.
{% endhint %}

BoxLang is a new language with a dual parser to support the CFML ecosystem. It also has a compatibility module (`bx-compat-cfml`) that will allow the BoxLang runtime to behave like an Adobe or Lucee Server. We also recommend you read the [Quick Syntax Style Guide](/getting-started/overview/syntax-style-guide) to understand all the new features of BoxLang.

You can install the compatibility module using `box install bx-compat-cfml` or if you have a `server.json` you can add the following:

```java
    "scripts":{
        "onServerInitialInstall":"install bx-compat-cfml"
    }
```

Even if you forget the server, when you start it up, it’ll get the compatibility module automatically.

## File Types

BoxLang can parse and run all of the traditional CFML file types

* `.cfc` - Components
* `.cfs` - Scripts
* `.cfm` - Templates

## Components are Classes

CFML Components (CFCs) are called classes in BoxLang, like any other language. You can also use the `class` declaration for them. You can continue to write components if you like, but if you use our `.bx` extensions, they are now classes.

```java
class{

    property name=¨firstName¨

}
```

## Tags are Components

Since BoxLang is not a tag-based language but a dynamic language offering a templating language. There are no concepts of tags but of BoxLang components that can be accessed via our templating language or script. In CFML the templating language uses a `<cf` prefix, in BoxLang we use a `<bx:` prefix.

```xml
<bx:if expression>

<bx:else>

</bx:if>
```

## Default assignment scope

In CFML, the default assignment scope is always `variables`, but in BL it can differ based on the context. For Functions, it will be `local`. The BoxLang runtime will toggle this behavior based on the type of the compiled source code. So for `.cfm` or `.cfc` source files, the default assignment scope in functions will remain `variables` but for code compiled from `.bx`, `.bxs` or `.bxm` files, the default assignment scope in functions will be `local`.

## StructCopy with Components

This only affects users coming from Lucee, where a `structCopy( cfc )` would return a new shallow copy of a CFC. In BoxLang, this returns a struct representation of the CFC's properties. To get a shallow copy of a CFC, use the `duplicate()` method. This is a Lucee undocumented feature, plus semantically a `structCopy` should return a struct, not a CFC.

```js
var myCFC = new MyComponent();
var myCFCopy = myCFC.duplicate();
```

## CastAs operator

BoxLang has a new `castAs` operator that you can use instead of the `javaCast()` bif.

```jsx
expression castAs type
```

No transpilation changes are needed since this is a BL-only feature.

## Multiple catch types

BoxLang supports

```jsx
catch( foo.com | brad | com.luis.majano e ) {}
```

No transpilation changes are needed since this is a BL-only feature.

## Annotations

BoxLang will allow for proper annotations before UDF declarations, properties, and classes. The annotation's value can be a string, struct literal, or array literal. You can also use multi-spaced or indentation.

```jsx
@foo
@bar( value )
@output( true )
function myFunc() {
}
```

No transpilation changes are needed since this is a BL-only feature.

## No `CLIENT` scope

BoxLang does not implement a native `client` scope. This decision was made since there is no more difference between `session` scope. In BoxLang, these persistence scopes can be backed by any Cache Provider and distribute. The `client` scope was introduced in ColdFusion due to the issue of distributing sessions at the time. This is no longer a problem and we consider it a legacy scope and completely discourage it.

However, if you NEED to leverage it, then you can install the `bx-compat-cfml` module and it will come with a `client` scope.

## Documentation Comments (Javadoc style)

BL will support documentation comments like CF, but will NOT allow them to actually influence the function’s behavior. When transpiling CFML to BL, any annotations set in a doc comment modifying the function or any arguments need to be moved to proper annotations in BL.

So the CFML

```jsx
/**
* My function hint
*
* @output false
* @brad wood
* @name Luis
*
* @myService my hint here for the arg
* @myService.inject
*/
function foo( required any myService ) {}
```

would turn into this BoxLang

```jsx
/**
* My function hint
*
* @myService my hint here for the arg
*/
@output( false)
@brad( wood ) // Strings can use quotes or no quotes
@name( “Luis” )
@myService.inject
function foo( required any myService ) {}
```

## Function output defaults to false

The `output` of functions will be false in BL. The BoxLang runtime will toggle this behavior based on the type of the compiled source code. So for `.cfm` or `.cfc` source files, default value of the `output` annotation on classes and functions will remain `true` but for code compiled from `.bx`, `.bxs` or `.bxm` files, the default value of the `output` annotation on classes and functions will be `false`.

## Accessors True

Accessors in BoxLang are automatically `true` for all classes by default. This is `false` for CFML. You can also disable as normal if needed.

```groovy
@displayName( “user” )
class{

    Property name=“fullName”;

}

// Accessors are on by default
user = new User()
user.setFullName( “Luis” )
println( user.getFullName() )
```

## Invoke Implicit Accessors True

We also default invoking of implicit accessors by default to `true` . You can also disable this at the class level or at the runtime level in the configuration. This is a syntactic sugar to make a delegated call to the accessor/mutator by making it look like if they are property access.

```groovy
@displayName( “user” )
class{

    Property name=“fullName”;

}

// Accessors and invoke implicit are on by default
user = new User()
user.fullName = “Luis Majano”
println( user.fullName )
```

## Import keyword

CFML has the import tag, but there doesn’t seem to be any special script version of it, ours looks like this:

```jsx
import taglib="/relative/path/customTags" prefix="tags";
```

```jsx
import package.Class as alias
```

## Import Aliases

You can also import classes from any resolver and attach an alias to remove any ambiguity.

```julia
import java:org.apache.User as jUser;
import models.User;

var oUser = new jUser()
var testUser = new User()
```

## Object Resolvers

Any `import` or `new` can be prefixed with an object resolvers prefix. A resolver adheres to our resolver interface to provide access into any type of object or filesystem. By default we ship with two resolvers:

1. `java` : Java classes
2. `bx` : BoxLang classes

This allows you to import or easily create classes from any source.

```julia
// Default resolver is bx : boxlang
import models.User;
// Same as
import bx:models.User;

// Java resolver
import java:java.util.ConcurrentHashMap;

// Custom Resolver
import cborm:entity
```

This will allow us to modularly provide object resolvers for any type of integrations. You will also be able to use the resolvers for `extends` and `implements`

```julia
class implements="java:java.util.List" {

}

class extends="java:ortus.boxlang.runtime.types.Struct"{

}
```

## Auto-casting argument and return value types

In CF an argument or return value of Numeric will allow a String through untouched so long as that string can be cast to a number. In BoxLang, we are actively casting the value to a “real” number. In theory, this is seamless, but could affect if you are checking the underlying Java type or passing to a Java method. There is no transpilation that can undo this, unless we add some setting or runtime configuration to disable the “feature”.

## GetCurrentTemplatePath() and relative includes

Both Adobe and Lucee do not agree with each other and are inconsistent even within themselves regarding

* The return value of the `getCurrentTemplatePath()` BIF
* The lookup of relative templates being included
* The lookup of relative CFC paths for object instantiation

Here is some documentation on their differences:

* Given a method that's originally part of a CFC
  * getCurrentTemplatePath() returns the original CFC (**Adobe** and **Lucee** agree here)
  * `new RelativeCFC()` find CFCs in the same folder as the original CFC (**Adobe** and **Lucee** agree here)
  * `include "relativePath.cfm";` find CFCs in the same folder as the original CFC (**Adobe** and **Lucee** agree here)
* Given a UDF defined in a file in a different directory that's injected into another CFC
  * getCurrentTemplatePath()
    * returns the original birthplace of the UDF source in **Lucee**
    * returns the new CFC the UDF was injected into in **Adobe**
  * Relative CFC path resolution
    * finds the CFC relative to the original birthplace of the UDF source in **Lucee**
    * finds the CFC relative to the NEW CFC's path in **Adobe**
  * Relative cfinclude path resolution
    * finds the CFC relative to the original birthplace of the UDF source in **Lucee**
    * finds the CFC relative to the original birthplace of the UDF source in **Adobe**
* Given a UDF defined in a file in a different directory that's passed into a UDF in another CFC for invocation
  * getCurrentTemplatePath()
    * returns the new CFC the UDF was injected into in **Lucee**
    * returns the new CFC the UDF was injected into in **Adobe**
  * Relative CFC path resolution
    * finds the CFC relative to the original birthplace of the UDF source in **Lucee**
    * finds the CFC relative to the NEW CFC's path in **Adobe**
  * Relative cfinclude path resolution
    * finds the CFC relative to the original birthplace of the UDF source in **Lucee**
    * finds the CFC relative to the original birthplace of the UDF source in **Adobe**

In BoxLang, this is being simplified and made consistent across the board. In ALL cases the “current template path” and relative lookup directory will tie to the original source path on disk of the file that contains the currently executing code. So, whether it’s an include, a UDF, an injected UDF from another location, or a closure defined elsewhere - whatever original source file for the code in question is what determines the “current template path” and relative lookups.

## BIF Renaming

Some bifs have been renamed in BoxLang.

| CFML                 | BoxLang          |
| -------------------- | ---------------- |
| asc                  | ascii            |
| chr                  | char             |
| deserializeJSON      | jsonDeserialize  |
| getComponentMetadata | getClassMetadata |
| serializeJSON        | jsonSerialize    |

## CreateObject Types

The `component` type for create object becomes `class` in BoxLang

```groovy
createObject( ”class”, path )
```

## JDBC Queries

### Parameter SQL Types

Both Adobe ColdFusion and Lucee Server utilize a `cfsqltype` key on query parameters to denote the type of the value being used in a prepared statement or query:

```js
queryExecute(
  "select quantity, item from cupboard where item_id = :itemID"
  { itemID : { value : arguments.itemID, cfsqltype : "cf_sql_numeric" } }
);
```

In BoxLang, you'll need to replace `cfsqltype` with just `sqltype`. In addition, we'd prefer to see all usage of the `cf_sql_`/`CF_SQL` prefixes stripped:

```js
queryExecute(
  "select quantity, item from cupboard where item_id = :itemID"
  { itemID : { value : arguments.itemID, sqltype : "numeric" } }
);
```

Here's a full breakdown of the various syntaxes:

* `sqltype:"numeric"` - The preferred syntax.
* `cfsqltype:"cf_sql_numeric"` - will throw an error in BoxLang core. In CFML syntax files, is transpiled to `sqltype:"cf_sql_numeric"`.
* `sqltype:"cf_sql_numeric"` - is silently treated as `sqltype:"numeric"`.

### BlockFactor Query Option

The `blockfactor` query option in Adobe CF and Lucee Server is used to set a custom batch size when selecting large numbers of rows:

```js
queryExecute( "Select * FROM myBigTable", {}, { blockfactor : 100 } );
```

In BoxLang, this is renamed to `fetchSize`:

```js
queryExecute( "Select * FROM myBigTable", {}, { fetchSize : 100 } );
```

You can use the `blockfactor` nomenclature by installing the `bx-compat-cfml` module.

## Date and Time Handling

Legacy CFML engines use the `java.util.Date` class as a backing object for their date and time handling. BoxLang uses the `java.time` [classes](https://cachebox.ortusbooks.com/7.x-1/readme/about-this-book/author), more specifically the [ZonedDateTime class](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/ZonedDateTime.html) as the backing date object. This offers greater precision and localization/internationalization capabilities than the Timezone-unaware `java.util` classes can provide.\
\
If interacting with Java classes which use `java.util.Date`, Boxlang will automatically coerce the runtime date object to the correct type. In some circumstances you may need to retrieve the object manually. You may do so with the `toLegacyDate( myDate )` method which will return the legacy Date class.

### Date Modification and Addition Operations

In BoxLang dates operation and comparison precision is to the millisecond level, compared to the legacy behavior of precision to the second. With the CFML compat module, date comparison functions will revert to using second-level precision.

In addition rounding behavior of date addition may be different than other CFML engines, but in a good way.\
\
The following code, when executed in non-BoxLang engines:

```
epochDate = parseDateTime( "1970-01-01T00:00:00.000Z" );
updatedDate = dateAdd( "s", 500/1000, epochDate );
result = dateTimeFormat( updatedDate, "yyyy-MM-dd'T'HH:mm:ss.SSSX", "UTC" );
```

will produce an incorrect rounding to the minute ( e.g. `1970-01-01T00:01:00.000Z` ). In BoxLang, the addition of ½ second produces a correctly rounded result to the second of `1970-01-01T00:00:01.000Z`

## Regex Escapes

There is a difference between how Lucee and Adobe CF handle backslashes in regex replacements.  Given the following code:

```javascript
reReplaceNoCase( "${boxlang.home}/logs", '(\$\{.*?})', '\\1', 'all' )
```

that code produces

* Lucee - `\${boxlang.home}/logs`&#x20;
* Adobe - `\1/logs`
* BoxLang (we matched Adobe, which is arguably more correct) - `\1/logs`

So in Adobe or BoxLang, you'd need to double up the `\` literal as well, so it doesn't escape the backreference (`'\\\1'`)&#x20;

If you are migration from Adobe CF to BoxLang, this should not affect you.  If you are migration from Lucee to Boxlang, check any backslash literals before special sequences.


# Running ColdFusion/CFML Apps

Learn how to migrate your existing ColdFusion/CFML apps to BoxLang

BoxLang is an innovative language designed to seamlessly\*\* substitute Adobe ColdFusion and Lucee in your existing projects. It offers robust functionality, ensuring compatibility with your current systems while providing enhanced performance, modern features and world-class support.

```mermaid
graph TD
  BoxLang-Source --> BoxLang-AST --> ByteCode
  CFML-Source --> CFML-Transpiler --> BoxLang-AST --> ByteCode
```

With its straightforward syntax and comprehensive toolset, BoxLang empowers developers to maintain and upgrade their applications with minimal hassle. Whether you're starting a new project or migrating an existing one, BoxLang serves as a reliable and efficient choice for modern web development needs.

{% hint style="danger" %}
**Warning**

There could be situations where certain functionality in Adobe/Lucee might not be available in BoxLang due to proprietary technology. Please contact us to see if this will be supported or not. We have tried to document as much as we can, but there are always edge-cases we have not covered.
{% endhint %}

{% stepper %}
{% step %}

## Install BoxLang OS & CommandBox

<figure><img src="/files/MULyRCAXGabK8GnDXuGJ" alt=""><figcaption></figcaption></figure>

Install the BoxLang **operating system** binary for your platform by following the instructions in the [Installation Guide](/getting-started/installation). **Please note that BoxLang is a multi-runtime platform, so you can install multiple versions side-by-side if needed. This is NOT like Adobe or Lucee where they only have a web application server model.**

{% hint style="success" %}
If you install BoxLang using our [Quick Installer](/getting-started/installation/boxlang-quick-installer) or our [BoxLang Version Manager (BVM)](/getting-started/installation/boxlang-version-manager-bvm), you will have the option to install CommandBox as well.
{% endhint %}

We start with the operating system binary in order to run command line tools to help you audit and migrate your applications. You can also achieve this and more via our [BoxLang IDE](/getting-started/ide-tooling). So make sure you download VSCode and install our BoxLang extension as well.

### CommandBox

![CommandBox Logo](https://www.ortussolutions.com/__media/contentbox:2025/products/logos/Commandbox.png)

[CommandBox](https://www.ortussolutions.com/products/commandbox) is our powerful package manager, cli tool and Java application server. This will allow you to easily run and manage your BoxLang web applications. CommandBox is the defacto enterprise Java Server for running BoxLang web applications. We also recommend that you use CommandBox to run your BoxLang applications in development, staging, and production environments. There is no need for a separate web server like Apache, IIS, Nginx, as CommandBox can handle all of your web serving needs and proxying.

Follow these instructions to install CommandBox: [CommandBox Installation Guide](https://commandbox.ortusbooks.com/setup/installation).

{% hint style="warning" %}
BoxLang +/++ subscribers get access to premium features in CommandBox such as multi-site support, clustering, advanced monitoring, and more.
{% endhint %}
{% endstep %}

{% step %}

## Audit Your Application

We have provided a CFML auditor in order to help you identify potential compatibility issues when migrating your ColdFusion/CFML applications to BoxLang. This tool scans your codebase and generates a report highlighting areas that may require attention or modification.

You can either run it in the [command line](/getting-started/ide-tooling/cfml-feature-audit) or via our VSCode extension.

```bash
boxlang featureAudit --help
```

The easiest way to run the audit tool is via VSCode.

<figure><img src="/files/dZQoTJdOYXzTlO6YvBdO" alt=""><figcaption></figcaption></figure>

1. Open your project folder in VSCode and then open the command palette (Ctrl+Shift+P or Cmd+Shift+P on Mac) and type "Feature Audit"
   1. You can also right click on a folder in the file explorer and select "BoxLang: Run Feature Audit on Folder"
2. Configure the audit settings as needed (e.g., specify directories to scan, set output format).
   1. Make sure you select `Missing Only` if you only want to see potential issues, else it would report back everything it scanned.
3. Run the audit and review the generated report for any compatibility issues or recommendations.

<figure><img src="/files/V9MYIKYMCajmXFir1DSN" alt=""><figcaption></figcaption></figure>

This will scan your codebase and provide you with a detailed report of any potential issues or areas that may require modification for compatibility with BoxLang. It will also tell you which modules you will need in order for your application to run properly in BoxLang. You can then add those modules to your CommandBox server via the `server install` command or via the `server.json` file (See below).

{% hint style="success" %}
If there is a situation where you are using a feature that is not supported in BoxLang, please [contact us](mailto:boxlang@ortussolutions.com) and we can help you find a solution or workaround.
{% endhint %}

### Modules

We have an extensive list of modules that provide additional functionality and compatibility for BoxLang applications. You can find a list of available modules in our [BoxLang Module Repository](/boxlang-framework/modularity) and or [BoxLang +/++ Module Repository](/boxlang-+-++/modules). Make sure to include any necessary modules in your `server.json` file or install them via the CommandBox CLI.
{% endstep %}

{% step %}

## CFML Engine Configuration

CommandBox allows you to easily extract the configuration of your existing ColdFusion or Lucee server and apply it to your BoxLang application using our [CFConfig Module](https://cfconfig.ortusbooks.com/). This ensures that your application runs with the same settings and environment as before. This is done via the `CFConfig` module that ships with CommandBox. To make sure we have the latest and greatest, please run the following command:

```bash
box install commandbox-cfconfig,commandbox-boxlang
```

Then you can extract your existing server configuration (<https://cfconfig.ortusbooks.com/using-the-cli/command-overview/export-settings>) by running the following command:

```bash
cfconfig export myConfig.json
cfconfig export from=serverNameToExportFrom to=myconfig.json
cfconfig export from=/path/to/server/home to=myconfig.json
```

This will produce a `.cfconfig.json` file that contains all of your server settings. Just make sure it is in the root of your application, because CommandBox will automatically pick it up when you start your BoxLang server.

{% hint style="info" %}
There could be the case that you already have a `.cfconfig.json` file in your application root. If so, then you can skip the export step and just modify that file as needed.
{% endhint %}

### Custom Settings

There are cases where you could have custom settings that are not part of the standard export. This includes:

* Custom Jar Files
* Custom JVM Arguments

#### Custom Jar Files

Custom Jar files will need to be copied over to your BoxLang server's `lib` directory found at the `{boxlang_home}/lib` path ([BoxLang Runtime Configuration](/getting-started/configuration)). BoxLang supports many custom locations for finding Jar files, so please refer to the [JVM Configuration Guide](https://boxlang.ortusbooks.com/getting-started/overview/pages/3QlEQBxo4wDrTDpGxySM##java-library-paths) for more details.

#### Custom JVM Arguments

These are easy to migrate as well. We will add them to our CommandBox `server.json` file in the `jvm` section (<https://commandbox.ortusbooks.com/embedded-server/configuring-your-server/jvm-args>). Here is an example of how to add custom JVM arguments to your `server.json` file:

```json
{
  "jvm": {
    "args": [
      "-Xmx2G",
      "-Dmy.custom.property=value",
      "--add-opens=java.base/java.net=ALL-UNNAMED"
    ]
  }
}
```

or via the command line:

```bash
server set jvm.args=["-XX:+UseG1GC"]
server set jvm.args=["-XX:-CreateMinidumpOnCrash"] --append
server set jvm.args=["--add-opens=java.base/java.net=ALL-UNNAMED"] --append
```

{% endstep %}

{% step %}

## Server.json Configuration

Now that we have audited our application and exported our server settings, we can now create a `server.json` file to configure our BoxLang server. This file is used by CommandBox to configure the server settings for your BoxLang application. It is extremely powerful and flexible, allowing you to customize your server settings to fit your specific needs. Here is the basics that you will need to get started:

```json
{
    // Best practice is to name your server after your application
    "name":"myApp",
    "app":{
        // This is the engine to use for this server, this might have been lucee or adobe previously
        "cfengine":"boxlang@1"
    },
    // Web Server Settings
    "web":{
        // Enable directory browsing if needed
        "directoryBrowsing":true,
        // HTTP Settings
        "http":{
            "port":"8599"
        },
        // You can also add HTTPS settings here if you need to
        // URL Rewrites and Aliases
        "rewrites":{
            "enable":true
        },
        "aliases":{
        }
    },
    // Java Virtual Machine Settings
    "JVM":{
        "heapSize":"512",
        // JRE 21 is the default for BoxLang 1.x
        "javaVersion":"openjdk21_jre",
        // This is where you can add custom JVM arguments, this can be a single line or an array
        "args": [
            // The following is an example of enabling remote debugging on port 9998 for VSCode
            "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9998"
        ]
    },
    // CFConfig Settings
    "cfconfig":{
        "file":".cfconfig.json"
    },
    // Get debugging information
    "env":{
        "BOXLANG_DEBUG":true
    },
    // The modules to install on server startup based on the audit
    "scripts":{
        "onServerInitialInstall":"install bx-compat-cfml,bx-esapi,bx-orm,bx-mail,bx-pdf,bx-mysql --noSave"
    }
}
```

{% hint style="success" %}
BoxLang ships with a robust code line debugger. You must enable it in the `server.json` and then tell VSCode about it. Then you can do line debugging and code breakpoints to your heart's desire. You can find more information about setting up the BoxLang debugger in VSCode [in our IDE documentation](/getting-started/ide-tooling/boxlang-debugger/commandbox-debugging).
{% endhint %}

Please note that the `bx-compat-cfml` module is required for BoxLang to run ColdFusion/CFML applications. This module provides compatibility functions, settings, and components (tags) that are not natively supported in BoxLang. You can find more information about this module [in its configuration page](/boxlang-framework/modularity/compat-cfml). Make sure to include it in your `server.json` file under the `onServerInitialInstall` script section.

Make sure you configure it accordingly by placing these settings in the `.cfconfig.json`

```js
"modules": {
    "compat-cfml" : {
        "disabled" : false,
        "settings" : {
            "engine" : "adobe",
            // JSON control character auto-escaping flag
            // IF you turn to true, be aware that the entire JSON serialization will be escaped and be slower.
            "jsonEscapeControlCharacters" : true,
            // This simulates the query to empty value that Adobe/Lucee do when NOT in full null support
            // We default it to true to simulate Adobe/Lucee behavior
            "queryNullToEmpty" : true,
            // The CF -> BL AST transpiler settings
            // The transpiler is in the core, but will eventually live in this module, so the settings are here.
            "transpiler" : {
                // Turn foo.bar into foo.BAR
                "upperCaseKeys" : true,
                // Add output=true to functions and classes
                "forceOutputTrue" : true,
                // Merged doc comments into actual function, class, and property annotations
                "mergeDocsIntoAnnotations" : true
            }
        }
    }
}
```

{% endstep %}

{% step %}

## Start & Test Your Application

Now that you have your `server.json` file configured, you can start your BoxLang server using CommandBox. Navigate to your application directory in the command line and run the following command:

```bash
box server start --console --debug
```

Please note that we have added the `--debug` flag to enable debug logging. This will help you identify any issues that may arise during the startup process. You can also check the logs in the `logs` directory of your BoxLang server for more information. We also use the `--console` flag to see the logs in the console as well as in the log files.

Now that your server is started, you can access your application in your web browser at `http://localhost:8599` (or whatever port you configured in your `server.json` file). Test your application thoroughly to ensure that everything is working as expected. If you encounter any issues, refer to the logs for troubleshooting information.

{% hint style="info" %}
Remember to regularly update your BoxLang installation and modules to benefit from the latest features and improvements.
{% endhint %}
{% endstep %}
{% endstepper %}


# Frequently Asked Questions

You can find a collection of frequently asked questions in our main website here: <https://www.boxlang.io/#faq>

{% embed url="<https://www.boxlang.io/#faq>" %}


# Installation

Getting started with BoxLang is easy!  Choose your path wisely!

BoxLang can be deployed on multiple runtimes, and each runtime can be set up differently. We recommend you leverage the "Running BoxLang" section for those specific runtimes. We recommend getting started by installing BoxLang at the global operating system level first. This is what this guide does!

**You can choose to either install a single version of BoxLang (Quick Installer) or our BoxLang Version Manager (BVM), so you can manage multiple versions of BoxLang on your operating system.**

## Next Step: Learn with BoxLings

{% hint style="success" %}
Once BoxLang is installed, jump into [BoxLings](https://github.com/ortus-boxlang/boxlings), our interactive CLI learning tool.

```bash
git clone https://github.com/ortus-boxlang/boxlings.git
cd boxlings
boxlang BoxLings.bx init
boxlang BoxLings.bx
```

{% endhint %}

## Requirements <a href="#requirements-7" id="requirements-7"></a>

BoxLang is a JVM language, so we need a JVM. You should be able to grab the Java 21 JRE for your OS and CPU arch here: [Download Java 21 JRE](https://adoptium.net/temurin/releases/?package=jre\&version=21). Alternatively, see the tabs below for instructions on automating it.

{% hint style="warning" %}
To use our BoxLang/CFML to Java transpiler, you must have the JDK installed, not the JRE.
{% endhint %}

{% tabs %}
{% tab title="🍎 Mac" %}
We recommend using [Homebrew](/getting-started/installation/homebrew) to get started on a Mac with the **BoxLang** by either installing our [BoxLang Version Manager](#boxlang-version-manager-bvm) or the [BoxLang Quick Installer](/getting-started/installation/boxlang-quick-installer). It will take care of all the requirements for you.

```bash
brew tap ortus-boxlang/boxlang

# BVM
brew install ortus-boxlang/boxlang/bvm
bvm install latest && bvm use latest

# Quick Installer
brew install ortus-boxlang/boxlang/boxlang
install-boxlang
```

{% endtab %}

{% tab title="🐧 \*Unix/Linux" %}
Leverage your system‘s package manager to install the needed requirements.

**APT**

```bash
# Update OS first
sudo apt-get update
sudo apt-get full-upgrade

# Install requirements
sudo apt-get install openjdk-21-jre
```

**Yum**

```bash
# Update OS first
sudo yum update
sudo yum upgrade

# Install requirements
sudo yum install java-21-openjdk

```

Note that you may need to tell the system to use the correct JDK version. This can be done via `update-alternatives --config java` (sudo may be required).

**XBPS (Voidlinux)**

```bash
# Update OS first
sudo xbps-install -Su

# Install requirements
sudo xbps-install openjdk21

```

Note that you may need to tell the system to use the correct JDK version. This can be done via `sudo xbps-alternatives -g jdk -s openjdk21`

**Arch Linux Variants**

```bash
# Update OS first
sudo pacman -Syu

# Install requirements
sudo pacman -S jre21-openjdk

```

Note that you may need to tell the system to use the correct JDK version. This can be done via `sudo archlinux-java set java-21-openjdk`
{% endtab %}

{% tab title="🪟 Windows" %}
Use the following **PowerShell 7.x script** to install the JRE 21. **HOWEVER, MAKE SURE YOU RUN THIS AS AN ADMINISTRATOR.**

**Powershell 7.x:**

```powershell
pwsh -NoProfile -ExecutionPolicy Bypass -NoExit -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://downloads.ortussolutions.com/ortussolutions/boxlang-quick-installer/helpers/install-jre.ps1'))"
```

**Windows PowerShell (5.x):**

```powershell
powershell -NoProfile -ExecutionPolicy Bypass -NoExit -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://downloads.ortussolutions.com/ortussolutions/boxlang-quick-installer/helpers/install-jre.ps1'))"
```

* Once this runs, the JRE will be installed in your `C:\Program Files\Java\jre{version}`
* A `JAVA_HOME` will be created for you

{% hint style="danger" %}
Ensure you restart any terminal windows for the changes to take effect.
{% endhint %}
{% endtab %}
{% endtabs %}

## Quick Installer

Once the requirements above are installed, get started quickly with BoxLang using our BoxLang Quick Installer for Mac, Linux, Unix, or Windows. This will allow you to execute the script in your favorite terminal application.

{% hint style="info" %}
Please note that some OS will require you to run it as an `administrator` or with `sudo` capabilities.
{% endhint %}

You can see the full documentation for the quick installer in the link below:

{% content-ref url="/pages/Ks9tp0OSqQb6EPvvrPVv" %}
[BoxLang Quick Installer](/getting-started/installation/boxlang-quick-installer)
{% endcontent-ref %}

Let's get started:

{% tabs %}
{% tab title="Bash / ZSH" %}
Just copy the following into your terminal to install by default for your user.

```bash
curl -fsSL https://install.boxlang.io/ | bash
```

If you want a system-wide installation, then prefix it with `sudo`:

```bash
curl -fsSL https://install.boxlang.io/ | sudo bash
```

Please make sure you use the `--help` on our scripts to see everything you can do with them.
{% endtab %}

{% tab title="Homebrew" %}
Make sure you have Homebrew installed:

```bash
brew tap ortus-boxlang/boxlang

# Quick Installer
brew install ortus-boxlang/boxlang/boxlang
install-boxlang
```

{% endtab %}

{% tab title="SH" %}
Just copy the following into your terminal to install byin default for your user.

```bash
curl -fsSL https://install.boxlang.io/ | sh
```

If you want a system-wide installation, then prefix it with `sudo`:

```bash
curl -fsSL https://install.boxlang.io/ | sudo sh
```

Please make sure you use the `--help` on our scripts to see everything you can do with them.
{% endtab %}

{% tab title="Windows PowerShell" %}
Just copy this into a Powershell Terminal.\
**HOWEVER, MAKE SURE YOU RUN THIS AS AN ADMINISTRATOR.**

```powershell
powershell -NoExit -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://install-windows.boxlang.io'))"
```

Please make sure you use the `--help` on our scripts to see everything you can do with them.
{% endtab %}
{% endtabs %}

{% hint style="danger" %}
If your system requires admin privileges (Like Chromebooks or Linux distros), make sure you use `sudo` or make sure the `/usr/local` folder is yours as the owner.
{% endhint %}

The quick installer will install the latest stable **BoxLang** **OS** binary and the **MiniServer** in the above directories. It will also install the following scripts for you:

* `boxlang` - Our BoxLang binary runner, [learn more](/getting-started/running-boxlang)
* `boxlang-miniserver` - Our BoxLang MiniServer binary runner, [learn more](/getting-started/running-boxlang/miniserver)
* `install-boxlang` - The quick installer so you can reuse it to upgrade your installations or install the `snapshot` version of BoxLang. Run `install-boxlang --help` for more commands.
* `install-bx-module` - A module installer. Just pass in the slug of the module, an optional version or a list of modules. Run `install-bx-module` for more commands.

```bash
# Test BoxLang works:
boxlang --version

# Get Help
install-boxlang --help

# Upgrade your installation
install-boxlang

# Uninstall
install-boxlang --uninstall

# Install a single module
install-bx-module bx-compat-cfml

# Install a specific version of a module
install-bx-module bx-compat-cfml@1.11.0

# Install multiple async modules
install-bx-module bx-compat-cfml bx-esapi bx-pdf

# Remove a module
install-bx-module --remove bx-esapi

# List your modules
install-bx-module --list

# Check for outdated modules
install-bx-module --outdated

# Update outdated modules
install-bx-module --update

# Update modules without confirmation
install-bx-module --update --force

# Get all the help
install-bx-module --help
```

### Module Dependency Management

The Quick Installer now tracks installed modules in a `box.json` dependencies manifest. Global modules use:

```
~/.boxlang/modules/box.json
```

For project-specific modules, use the `--local` flag. Local modules are managed in:

```
./boxlang_modules/box.json
```

Installing or removing a module updates its dependency entry. The `--list` command reads from this manifest and can generate one automatically when modules were installed before manifest tracking was added.

Use `--outdated` to compare the installed versions with the latest versions available from ForgeBox:

```bash
install-bx-module --outdated
install-bx-module --outdated --local
```

Use `--update` to update outdated modules. The command asks for confirmation before making changes; add `--force` for unattended workflows:

```bash
install-bx-module --update
install-bx-module --update --force
install-bx-module --update --force --local
```

Explicit module versions continue to be supported, including versions resolved during updates:

```bash
install-bx-module bx-compat-cfml@1.11.0
```

The installer uses the correct ForgeBox version endpoint for pinned installs and falls back to the direct module artifact when ForgeBox does not provide a download URL.

### Upgrading Your Install

The `install-boxlang` script will allow you to upgrade your OS installation easily. If you call it without arguments, it will install the **latest stable** release and override the local install. You can also pass a specific version to install as the second argument, or the word `snapshot`to install the bleeding edge release. You can find all the latest artifacts here: <https://downloads.ortussolutions.com/#/ortussolutions/boxlang/>

```bash
# Upgrade to the latest stable version
install-boxlang

# Upgrade or Downgrade to a specific version
install-boxlang 1.0.0

# Use the latest snapshot
install-boxlang snapshot
```

{% hint style="success" %}
You can get the version of the current BoxLang Runtime by running `boxlang --version`
{% endhint %}

### Installing Modules

You can use the `install-bx-module` binary to install modules into your boxlang home. Just pass in the name of the slug you want. You can use the `install bx-modules`to install multiple modules at once as well.

{% hint style="info" %}
All our modules are available in the cloud software directory [FORGEBOX](https://forgebox.io/type/boxlang-modules). You can also register and collaborate with modules of your own :person\_raising\_hand:.
{% endhint %}

#### Install in the BoxLang Home

```bash
# install individual modules
install-bx-module bx-compat-cfml
install-bx-module bx-esapi

# install multiple modules
install-bx-module bx-compat-cfml bx-esapi
```

#### Install Locally

You can also install modules to the running application (CLI, web) by using the `--local`option in the command. This will create a `boxlang_modules`folder from which you ran the command and install the modules locally.

```bash
# install individual modules
install-bx-module bx-compat-cfml --local
install-bx-module bx-esapi --local

# install multiple modules
install-bx-module bx-compat-cfml bx-esapi --local
```

## BoxLang Version Manager (BVM)

BVM is a simple version manager for BoxLang, similar to jenv or nvm. It allows you to easily install, manage, and switch between different versions of BoxLang. Read the full documentation at the link below:

{% content-ref url="/pages/ZvtlSWM3WF734cGieJXS" %}
[BoxLang Version Manager (BVM)](/getting-started/installation/boxlang-version-manager-bvm)
{% endcontent-ref %}

To get started easily, just follow the instructions:

{% tabs %}
{% tab title="Bash/Zsh" %}
Just copy the following into your terminal to install by default for your user.

<pre class="language-bash"><code class="lang-bash"># Install BVM
<strong>curl -fsSL https://install-bvm.boxlang.io/ | bash
</strong>

# Or download and run locally
wget --content-disposition https://install-bvm.boxlang.io/
chmod +x install-bvm.sh
./install-bvm.sh
</code></pre>

{% endtab %}

{% tab title="Homebrew" %}

```bash
brew tap ortus-boxlang/boxlang

# Quick Installer
brew install ortus-boxlang/boxlang/bvm
bvm install latest && bvm use latest
```

{% endtab %}

{% tab title="Sh" %}

<pre class="language-bash"><code class="lang-bash"># Install BVM
<strong>curl -fsSL https://install-bvm.boxlang.io/ | sh
</strong>

# Or download and run locally
wget --content-disposition https://install-bvm.boxlang.io/
chmod +x install-bvm.sh
./install-bvm.sh
</code></pre>

{% endtab %}

{% tab title="Windows" %}
Coming Soon
{% endtab %}
{% endtabs %}

## R.E.P.L.

**Read, Evaluate, Print Loop**

A REPL, or Read-Evaluate-Print Loop, is an interactive programming environment that takes single-user inputs, executes them, and returns the result to the user. This is particularly useful for testing code snippets and debugging in real time. In the context of BoxLang, running `boxlang` will start the REPL, allowing you to write and test code quickly within the BoxLang environment.

The REPL will also remember state, so you can define variables and use them in your testing and explorations. Code away :rocket:

<figure><img src="/files/1qkpdKoAtYM0QyOuYFdS" alt=""><figcaption></figcaption></figure>

## Binaries

The quick installer is the best and easiest way to get installed on Mac or \*Nix. However, below, you can find a collection of all our installers and binaries for running BoxLang and each Runtime.

### Operating System Binaries

Here, you can find the installers and binaries for all Operating Systems:

* Windows Installer:\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang/boxlang-installer.exe>
* Zip (All OSs):\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang/boxlang-latest.zip>
* Jar:\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang/boxlang-latest-all.jar>
* Quick Installer (Mac/\*nix)\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang/install-boxlang.sh>

### MiniServer Binaries

The BoxLang MiniServer includes the BoxLang OS runtime with the addition of our super-fast and lightweight web server.

* All OSs:\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-miniserver/boxlang-miniserver-latest.zip>

### AWS Lambda Binaries

BoxLang can also run on AWS Lambdas. It even powers our entry playground at [https://try.boxlang.io](https://try.boxlang.io/).

* Runtime:\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-aws-lambda/boxlang-aws-lambda-latest-all.jar>
* Template\
  <https://github.com/ortus-boxlang/boxlang-starter-aws-lambda>

### Google Cloud Functions Runtime

BoxLang can also run on Google Cloud Functions using our Java 21 runtime integration.

* Runtime Source:\
  <https://github.com/ortus-boxlang/boxlang-google-functions>
* Starter Template\
  <https://github.com/ortus-boxlang/boxlang-starter-google-functions>

### CommandBox BoxLang Server

BoxLang can also be deployed using [CommandBox](https://www.ortussolutions.com/products/commandbox). This is our preferred way to deploy web applications using BoxLang. BoxLang +/++ Subscribers even get access to [CommandBox Pro](https://www.ortussolutions.com/products/commandbox-pro). Note: This installation method is typically tailored for a specific web application and is not typically accessible by other applications.

```bash
box install commandbox-boxlang
box server start cfengine=boxlang javaVersion=openjdk21_jdk
```

Learn more in our [CommandBox guide.](/getting-started/running-boxlang/commandbox)

### Servlet EE Binaries

This is the servlet edition of BoxLang that you can deploy on any servlet container (Jetty, Tomcat, JBoss, etc)

* WAR:\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-servlet/boxlang-servlet-latest.war>
* JAR:\
  <https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-servlet/boxlang-servlet-latest-all.jar>

### Spring Boot Starter

The BoxLang Spring Boot Starter allows you to use BoxLang as a view engine and runtime inside any Spring Boot 3 web application.

* Spring Boot Starter Integration Guide:\
  [Spring Boot Integration](/getting-started/running-boxlang/spring-boot)

### Docker

We have a full [Docker guide you can follow here.](/getting-started/running-boxlang/docker)

## BoxLang IDE & Tools

BoxLang provides officially supported tooling for popular IDEs to enhance your development experience.

<div align="left"><figure><img src="/files/DvvNFFXrnfZzH9Frk3GM" alt=""><figcaption><p>BoxLang IDE for VSCode</p></figcaption></figure></div>

### VSCode Extension

The BoxLang IDE for VSCode is a collection of tools that gives you a line debugger, LSP (Language Server Protocol), highlighting, introspection, generation, and much more. You can find it here:

{% embed url="<https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-boxlang>" %}
Install VSCode IDE
{% endembed %}

### IntelliJ IDEA Plugin

We also have a robust plugin for IntelliJ IDEA and other JetBrains IDEs. It provides syntax highlighting, auto-completion, formatting, and debugging capabilities for your BoxLang projects.

{% embed url="<https://plugins.jetbrains.com/plugin/23812-boxlang>" %}
Install IntelliJ Plugin
{% endembed %}

Learn more about all the available tools in our [IDE & Tooling Section](/getting-started/ide-tooling).

## Core Modules

The BoxLang core is lightweight and fast. Everything that extends the core comes as modules or individual runtimes. We have a collection of core modules that the BoxLang team maintains and curates. We also have several enterprise modules for our **BoxLang +, ++** subscribers, and the community can create and share modules in our cloud package manager [FORGEBOX](https://forgebox.io).

{% content-ref url="/pages/Ndnm9Q2wdUb7WqkyoBez" %}
[Modules](/getting-started/installation/modules)
{% endcontent-ref %}

## BoxLang+, ++ Modules

Our [BoxLang+, and ++](https://boxlang.io/plans) subscribers not only get professional/customized support but also new features, and modules. You can find out more about our subscriptions here: <https://boxlang.io/plans>. Here is the collection of modules that you will get with your subscription which are not part of the open source edition.

{% content-ref url="/pages/lrVKXiiSN9KfqKDxuIHQ" %}
[+Modules](/boxlang-+-++/modules)
{% endcontent-ref %}

| Module                                                                                                               | Description                                                                                                       | Status |
| -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------ |
| [`bx-azure-secrets`](/boxlang-+-++/modules/bx-azure-secrets)                                                         | Azure Key Vault integration for `getSystemSetting()` using the `azure.` namespace.                                | Done   |
| [`bx-aws-secrets`](/boxlang-+-++/modules/bx-aws-secrets)                                                             | AWS Secrets Manager integration for `getSystemSetting()` using the `aws.` namespace.                              | Done   |
| [`bx-google-secrets`](/boxlang-+-++/modules/bx-google-secrets)                                                       | Google Secret Manager integration for `getSystemSetting()` using the `google.` namespace.                         | Done   |
| [`bx-csv`](https://github.com/ortus-boxlang/boxlang-docs/tree/v1.x/boxlang-framework/boxlang-plus/modules/bx-csv.md) | Streaming CSV parsing & generation for large datasets                                                             | Done   |
| [`bx-couchbase`](/boxlang-+-++/modules/bx-couchbase)                                                                 | Native Couchbase integration for caching, NoSQL, session distribution and advanced Couchbase usage.               | Done   |
| [`bx-ldap`](/boxlang-+-++/modules/bx-ldap)                                                                           | A comprehensive LDAP module for BoxLang that brings full-featured LDAP directory access to your applications.     | Done   |
| [`bx-plus`](/boxlang-+-++/modules/bx-plus)                                                                           | Subscription bootstrap, entitlement validation, shared utilities                                                  | Done   |
| [`bx-pdf`](/boxlang-+-++/modules/bx-plus-pdf)                                                                        | PDF generation and manipulation for documents, reports, and forms. Includes free-tier and licensed functionality. | Done   |
| [`bx-redis`](/boxlang-+-++/modules/bx-redis)                                                                         | Native Redis integration is used for caching, session distribution, and publish-subscribe events.                 | Done   |
| [`bx-rest-compat`](/boxlang-+-++/modules/rest-compat-+)                                                              | REST component compatibility and routing translation layer for running legacy framework-less REST architectures.  | Done   |
| [`bx-spreadsheet`](/boxlang-+-++/modules/bx-spreadsheet)                                                             | Read, write, and style spreadsheet documents (XLSX).                                                              | Done   |
| [`bx-soap-compat`](/boxlang-+-++/modules/soap-compat-+)                                                              | SOAP compatibility layer for generating, parsing, and communicating with web services.                            | Done   |
| [`bx-word`](/boxlang-+-++/modules/bx-word)                                                                           | Read, write, and style Word documents (DOCX).                                                                     | Done   |


# BoxLang Quick Installer

The BoxLang Quick Installer is the fastest way to get started with BoxLang.

<div data-full-width="false"><figure><img src="/files/X1mH3zhhdPBihGRN7XoR" alt=""><figcaption><p>BQI</p></figcaption></figure></div>

The BoxLang Quick Installer provides convenient installation scripts for Mac, Linux, and Windows systems to get BoxLang up and running in minutes. Choose between a single-version installer for simplicity or BVM (BoxLang Version Manager) for advanced version management.

## 🚀 Quick Start

**Mac and Linux:**

```bash
/bin/bash -c "$(curl -fsSL https://install.boxlang.io)"

# With automatic Java 21  installation
curl -fsSL https://install.boxlang.io | bash -s -- --with-jre
```

**Homebrew**

```bash
brew tap ortus-boxlang/boxlang

# Quick Installer
brew install ortus-boxlang/boxlang/boxlang
install-boxlang
```

**Windows:**

```powershell
# Single version (simple)
powershell -NoExit -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://install-windows.boxlang.io'))"
```

### Verify Installation

```bash
# Check BoxLang version
boxlang --version

# Start BoxLang REPL
boxlang

# Start MiniServer
boxlang-miniserver --port 8080
```

## 📋 Prerequisites

The installer will attempt to install any missing prerequisites automatically, but there are some that will need to be installed manually depending on your platform.

* **bash** - Required shell execution environment, especially on Alpine Linux
* **curl** - For downloading releases
* **PowerShell 6+** - Required for Windows installations

**Alpine Linux** : You will need to install bash manually as it is not included by default.

```bash
apk add --no-cache bash curl
```

### Requirements

The following are automatically installed for you, but you can install them manually if you prefer.

* **Java 21+** - JRE or JDK
* **unzip** - For extracting downloaded files
* **jq** - For parsing JSON (BVM only)

### Manual Installation

Remember, we do this automatically for you, but if you want to do it manually, here are the commands:

**macOS (with Homebrew):**

```bash
brew install curl unzip jq openjdk@21
```

**Ubuntu/Debian:**

```bash
sudo apt update && sudo apt install curl unzip jq default-jdk
```

**RHEL/CentOS/Fedora:**

```bash
sudo dnf install curl unzip jq java-21-openjdk
```

**Alpine Linux:**

```bash
# Prerequisites automatically installed by installer
apk add --no-cache bash curl unzip jq openjdk21
# Java 21 automatically installed with --with-jre option
```

## 📋 Table of Contents

* [Quick Start](#quick-start)
* [Prerequisites](#prerequisites)
* [Installation Options](#installation-options)
* [Command Options](#command-options)
* [What Gets Installed](#what-gets-installed)
* [Help Command](#help-command)
* [Detailed Usage](#detailed-usage)
* [Running Applications](#running-applications)
* [Configuration](#configuration)
* [Troubleshooting](#troubleshooting)
* [Resources](#resources)
* [License](#license)
* [Support](#support)

## 📦 Installation Options

### Option 1: Single-Version Installer (Recommended for Most Users)

**Choose this if you:**

* 📌 Need one BoxLang version system-wide
* 🎯 Want the simplest possible installation
* 🏢 Are setting up production servers
* ⚡ Want the fastest installation with minimal overhead

**Features:**

* ✅ Installs latest stable BoxLang version
* ✅ Sets up BoxLang runtime and MiniServer
* ✅ Includes all helper scripts
* ✅ Automatic PATH configuration
* ✅ User or system-wide installation options

### Option 2: BVM (BoxLang Version Manager)

**Choose this if you:**

* 🔄 Work on multiple projects needing different BoxLang versions
* 🧪 Want to test code against different BoxLang releases
* 🚀 Need to switch between stable and snapshot versions
* 📦 Want centralized management of BoxLang installations
* 🛠️ Are a BoxLang developer or advanced user

**Features:**

* ✅ Install and manage multiple BoxLang versions
* ✅ Switch between versions with one command
* ✅ List local and remote versions
* ✅ Clean uninstall capabilities
* ✅ Health check and diagnostics

## ⚙️ Command Options

Here are the available options for the install command.

| Option                 | Short | Description                                                 |
| ---------------------- | ----- | ----------------------------------------------------------- |
| `--help`               | `-h`  | Show this help message                                      |
| `--uninstall`          |       | Remove BoxLang from the system                              |
| `--check-update`       |       | Check if a newer version is available                       |
| `--system`             |       | Force system-wide installation (requires sudo)              |
| `--force`              |       | Force reinstallation even if already installed              |
| `--with-commandbox`    |       | Install CommandBox without prompting                        |
| `--without-commandbox` |       | Skip CommandBox installation                                |
| `--with-jre`           |       | ✨ Automatically install Java 21 JRE if not found            |
| `--without-jre`        |       | ✨ Skip Java installation (manual installation required)     |
| `--yes`                | `-y`  | Use defaults for all prompts (installs CommandBox and Java) |

### Notes

* Use `--system` when you want to install BoxLang for all users on the system
* The `--force` option is useful when you need to reinstall or update an existing installation
* `--yes` automatically accepts all defaults, including installing CommandBox and Java
* `--with-commandbox` and `--without-commandbox` give you explicit control over CommandBox installation
* ✨ `--with-jre` automatically installs OpenJDK 21 JRE if Java 21+ is not found
* ✨ `--without-jre` skips Java installation entirely (you must install Java manually)
* ✨ The installer can detect your OS (macOS/Linux/Alpine) and architecture (x64/ARM64) for Java installation
* 🐋 **Container-friendly** - Works in Docker containers with minimal base images

## 🛠️ What Gets Installed

### Core Components

* **BoxLang Runtime** (`boxlang`, `bx`) - The main BoxLang Runtime Engine
* **BoxLang MiniServer** (`boxlang-miniserver`, `bx-miniserver`) - Lightweight web application server

### Helper Scripts

* **install-bx-module** - Install modules from ForgeBox.
* **install-boxlang** - Single-version BoxLang installer, so you can reinstall, install specific versions, uninstall and more.

### Directory Structure

```
~/.local/boxlang/           # BoxLang home directory
├── bin/              # Executable binaries
├── lib/              # Core libraries
├── scripts/          # Installed scripts

# System installation locations:
System Wide: /usr/local/bin/       # Binaries (Linux/Mac)
Local User: ~/.local/bin/          # Binaries (Linux/Mac)

C:\BoxLang\  # Installation directory (Windows)
```

## 📖 Help Command

Always make sure to run the `--help` command to get the latest and greatest command usage.

```bash
📦 BoxLang® Quick Installer v@build.version@

This script installs the BoxLang® runtime, MiniServer and tools on your system.

Usage:
  install-boxlang [version] [options]
  install-boxlang --help

Arguments:
  [version]         (Optional) Specify which version to install
                    - 'latest' (default): Install the latest stable release
                    - 'snapshot': Install the latest development snapshot
                    - '1.2.0': Install a specific version number

Options:
  --help, -h            Show this help message
  --uninstall           Remove BoxLang from the system
  --check-update        Check if a newer version is available
  --system              Force system-wide installation (requires sudo)
  --force               Force reinstallation even if already installed
  --with-commandbox     Install CommandBox without prompting
  --without-commandbox  Skip CommandBox installation
  --with-jre            ✨ Automatically install Java 21 JRE if not found
  --without-jre         ✨ Skip Java installation (manual installation required)
  --yes, -y             Use defaults for all prompts (installs CommandBox and Java)

Examples:
  install-boxlang
  install-boxlang latest
  install-boxlang snapshot
  install-boxlang 1.2.0
  install-boxlang --force
  install-boxlang --with-commandbox
  install-boxlang --without-commandbox
  install-boxlang --with-jre
  install-boxlang --without-jre
  install-boxlang --with-commandbox --with-jre
  install-boxlang --yes
  install-boxlang --uninstall
  install-boxlang --check-update
  sudo install-boxlang --system

Non-Interactive Usage:
  🌐 Install with CommandBox: curl -fsSL https://boxlang.io/install.sh | bash -s -- --with-commandbox
  🌐 Install without CommandBox: curl -fsSL https://boxlang.io/install.sh | bash -s -- --without-commandbox
  🌐 Install with Java auto-install: curl -fsSL https://boxlang.io/install.sh | bash -s -- --with-jre
  🌐 Full auto-install (Java + CommandBox): curl -fsSL https://boxlang.io/install.sh | bash -s -- --yes
  🌐 Install with defaults: curl -fsSL https://boxlang.io/install.sh | bash -s -- --yes
```

## 🎯 Detailed Usage

### Single-Version Installer Commands

```bash
# Install latest stable version
install-boxlang

# Install specific version
install-boxlang --version 1.2.0

# Install snapshot version
install-boxlang --snapshot

# ✨ NEW: Auto-install with Java (if not found)
install-boxlang --with-jre

# ✨ NEW: Skip Java installation entirely
install-boxlang --without-jre

# ✨ NEW: Full automation (Java + CommandBox)
install-boxlang --yes

# ✨ NEW: Combine options for specific setup
install-boxlang --with-commandbox --with-jre

# System-wide installation (requires sudo)
sudo install-boxlang --system

# Uninstall BoxLang
install-boxlang --uninstall

# Get help
install-boxlang --help
```

### Module Management

```bash
# Install a module globally
install-bx-module bx-orm

# Install multiple modules
install-bx-module bx-orm,bx-mail,bx-db

# Install to specific directory
install-bx-module bx-orm --directory ./modules

# Install specific version
install-bx-module bx-orm@1.0.0

# Get help
install-bx-module --help
```

## 🌐 Running Applications

### BoxLang Runtime

```bash
# Start REPL
boxlang

# Run a class
boxlang Task.bx

# Run a script
boxlang myscript.bxs

# Execute inline code
boxlang -c "println('Hello BoxLang!')"

# Compile to bytecode
boxlang compile myscript.bx

# Show version
boxlang --version
```

### BoxLang MiniServer

```bash
# Start with default settings
boxlang-miniserver

# Specify port
boxlang-miniserver --port 8080

# Set web root
boxlang-miniserver --webroot ./public

# Enable development mode
boxlang-miniserver --dev

# Show all options
boxlang-miniserver --help
```

## 🔧 Configuration

### Environment Variables

```bash
# BoxLang home directory
export BOXLANG_HOME=~/.boxlang

# Java options for BoxLang
export BOXLANG_OPTS="-Xmx2g -Xms512m"

# Module search paths
export BOXLANG_MODULES_PATH="./modules:~/.boxlang/modules"
```

## 🐛 Troubleshooting

### Common Issues

**BoxLang not found after installation:**

```bash
# Restart terminal or reload profile
source ~/.bashrc  # or ~/.zshrc

# Check PATH
echo $PATH | grep boxlang
```

**Java not found:**

```bash
# ✨ NEW: Let BoxLang installer handle Java automatically
install-boxlang --with-jre

# Or check Java installation manually
java -version

# Manual Java installation options:
# Install Java 21 (Ubuntu/Debian)
sudo apt install default-jdk

# Install Java 21 (macOS)
brew install openjdk@21

# Download from Adoptium (cross-platform)
# https://adoptium.net/temurin/releases/
```

**Permission denied errors:**

```bash
# Fix permissions for user installation
chmod +x ~/.boxlang/bin/*

# Or use system installation
sudo install-boxlang --system
```

**Module installation fails:**

```bash
# Check network connectivity
curl -I https://forgebox.io

# Clear module cache
rm -rf ~/.boxlang/modules/.cache

# Install with verbose output
install-bx-module bx-orm --verbose
```

### Getting Help

```bash
# Command-specific help
install-boxlang --help
install-bx-module --help
bvm help

# Health check (BVM only)
bvm doctor

# Verbose output for debugging
install-boxlang --verbose
install-bx-module --verbose
```

## 📚 Resources

### Documentation

* 📖 [Official Documentation](https://boxlang.io/docs)
* 🚀 [Getting Started Guide](https://boxlang.io/docs/getting-started)
* 📋 [Language Reference](https://boxlang.io/docs/reference)
* 🔧 [Module Development](https://boxlang.io/docs/modules)

### Community

* 💬 [Discord Community](https://boxlang.io/discord)
* 📧 [Mailing List](https://boxlang.io/mailing-list)
* 🐛 [Issue Tracker](https://github.com/ortus-boxlang/boxlang/issues)
* 💡 [Feature Requests](https://github.com/ortus-boxlang/boxlang/discussions)

### Examples

* 🧑‍💻 [Interactive Playground](https://try.boxlang.io)
* 📁 [Sample Applications](https://github.com/ortus-boxlang/bx-demos)
* 🎓 [Tutorials](https://learn.boxlang.io)

### Testing

Help test new features and releases:

```bash
# Install snapshot for testing
bvm install snapshot
bvm use snapshot

# Report any issues found
```

## 📄 License

This project is licensed under the [Apache License, Version 2.0](https://github.com/ortus-boxlang/boxlang-docs/tree/v1.x/getting-started/installation/license.txt).

## 🆘 Support

### Community Support (Free)

* 🌐 Website: <https://boxlang.io>
* 📖 Documentation: <https://boxlang.ortusbooks.com>
* 💾 GitHub: <https://github.com/ortus-boxlang/boxlang>
* 💬 Community: <https://community.ortussolutions.com/>
* 🧑‍💻 Try: <https://try.boxlang.io>
* 📧 Mailing List: <https://newsletter.boxlang.io>

### Professional Support

* 🫶 Enterprise Support: <https://boxlang.io/plans>
* 🎓 Training: <https://learn.boxlang.io>
* 🔧 Consulting: <https://www.ortussolutions.com/services/development>
* 📞 Priority Support: [Available with enterprise plans](https://boxlang.io/plans)

***

Made with ♥️ in USA 🇺🇸, El Salvador 🇸🇻 and Spain 🇪🇸


# BoxLang Version Manager (BVM)

BVM is a simple version manager for BoxLang, similar to jenv or nvm. It allows you to easily install, manage, and switch between different versions of BoxLang.

<figure><img src="/files/osuHPXCW8GeO2jiiKPjb" alt=""><figcaption><p>BoxLang Version Manager</p></figcaption></figure>

BVM is an advanced version manager for BoxLang, similar to `jenv` or `nvm`. It allows you to easily install, manage, and switch between different versions of BoxLang.

## 🆚 BVM vs Single-Version Installer

**Choose BVM if you:**

* 🔄 Work on multiple projects that might need different BoxLang versions
* 🧪 Want to test your code against different BoxLang releases
* 🚀 Need to switch between stable and snapshot versions
* 📦 Want centralized management of BoxLang installations
* 🛠️ Are a BoxLang developer or advanced user

**Choose the single-version installer (`install-boxlang.sh`) if you:**

* 📌 Only need one BoxLang version system-wide
* 🎯 Want the simplest possible installation
* 🏢 Are setting up production servers with a specific BoxLang version
* ⚡ Want the fastest installation with minimal overhead

**Both installers provide identical functionality:**

* ✅ Same BoxLang runtime and MiniServer
* ✅ Same helper scripts (`install-bx-module`, `install-bx-site`, etc.)
* ✅ Same command-line tools (`boxlang`, `bx`, `boxlang-miniserver`, etc.)
* ✅ Same installation quality and reliability

The only difference is that BVM adds version management capabilities on top.

## 🛠️ Features

* 📦 **Install complete BoxLang environment** - runtime, MiniServer, and helper scripts
* 🔄 **Switch between versions easily** - change your active BoxLang version with one command
* 📋 **List installed versions** - see what's installed locally with `bvm list` or `bvm ls`
* 🌐 **List remote versions** - see what's available for download with `bvm list-remote` or `bvm ls-remote`
* 🗑️ **Clean Removal** - remove versions you no longer need with `bvm remove`, or `bvm rm`
* 🔍 **Health check** - verify your BVM installation with `bvm doctor` or `bvm health`
* 🧹 **Cache management** - clean up downloaded files with `bvm clean`
* 🚀 **Execute BoxLang components** - run BoxLang, MiniServer through BVM with version management
* 🔗 **Seamless integration** - wrapper scripts make all tools available in PATH
* ⚡ **Command aliases** - convenient short aliases for all major commands
* 🛠️ **Helper script integration** - all BoxLang helper scripts work with active version
* 📦 **Module dependency tracking** - module installs and removals maintain a `box.json` manifest
* 🔄 **Module updates** - find outdated modules with `--outdated` and update them with `--update`
* 🎯 **Smart version detection** - automatically detects actual version numbers from installations
* 🚀 **First-install activation** - automatically activates the first BoxLang version you install
* 🐚 **Shell initialization** - centralizes BVM and BoxLang PATH setup for Bash, Zsh, and Fish
* ⌨️ **Command completion** - provides BVM command and version completion for Bash and Zsh
* 🆙 **Built-in update checker** - check for BVM updates and upgrade easily
* ☕ **Automatic Java installation** - installs Java 21 JRE if needed with `--with-jre` option
* 🗑️ **Uninstall BVM** - Remove completely BVM, versions, etc.

## 🚀 Quick Start

## 📋 Prerequisites

The installer will attempt to install any missing prerequisites automatically, but there are some that will need to be installed manually depending on your platform.

* **bash** - Required shell execution environment, especially on Alpine Linux
* **curl** - For downloading releases
* **PowerShell 6+** - Required for Windows installations

**Alpine Linux** : You will need to install bash manually as it is not included by default.

```bash
apk add --no-cache bash curl
```

The following are automatically installed for you, but you can install them manually if you prefer.

* **Java 21+** - JRE or JDK
* **unzip** - For extracting downloaded files
* **jq** - For parsing JSON (BVM only)

### Manual Installation

Remember, we do this automatically for you, but if you want to do it manually, here are the commands:

{% tabs %}
{% tab title="macOS (Homebrew)" %}

```bash
brew tap ortus-boxlang/boxlang

# Quick Installer
brew install ortus-boxlang/boxlang/bvm
bvm install latest
```

{% endtab %}

{% tab title="Ubuntu/Debian" %}

```bash
sudo apt update && sudo apt install curl unzip jq default-jdk
```

{% endtab %}

{% tab title="RHEL/CentOS/Fedora" %}

```bash
sudo dnf install curl unzip jq java-21-openjdk
```

{% endtab %}

{% tab title="Alpine Linux" %}

```bash
# Prerequisites automatically installed by installer
apk add --no-cache bash curl unzip jq openjdk21
# Java 21 automatically installed with --with-jre option
```

{% endtab %}
{% endtabs %}

## ⬇️ Installation

```bash
# Install BVM (auto-installs Java 21 if needed)
curl -fsSL https://install-bvm.boxlang.io | bash -s -- --with-jre

# Or standard installation (requires Java 21 to be pre-installed)
curl -fsSL https://install-bvm.boxlang.io | bash

# Download and run locally
wget https://raw.githubusercontent.com/ortus-boxlang/boxlang-quick-installer/main/src/install-bvm.sh
chmod +x install-bvm.sh
./install-bvm.sh --with-jre  # Auto-install Java if needed
```

## 💻 Basic Usage

```bash
# Install the latest stable BoxLang version
bvm install latest
# If this is the first installed version, BVM activates it automatically

# Switch to the latest version
bvm use latest

# Check current version
bvm current

# List installed versions
bvm list

# Set up project-specific version
bvm local latest              # Creates .bvmrc with 'latest'
bvm use                       # Uses version from .bvmrc

# Check for BVM updates
bvm check-update

# Run BoxLang
bvm exec --version

# Get help
bvm help
# or use aliases
bvm --help
bvm -h
```

## 🐚 Shell Initialization

The Unix installer creates a single initialization hook at `~/.bvm/scripts/bvm-init.sh` and adds it to the detected shell profile. The Fish equivalent is `~/.bvm/scripts/bvm-init.fish`.

The initialization hook:

* Exports `BVM_HOME` and `BOXLANG_HOME` with defaults of `~/.bvm` and `~/.boxlang`.
* Adds the BVM wrapper directory, active version, and BoxLang home `bin` directory to `PATH`.
* Loads BVM command and installed-version completions for Bash and Zsh.

For an existing terminal, reload the profile path printed by the installer or open a new terminal session:

```bash
source ~/.bashrc  # or ~/.zshrc
```

Fish users can reload their configuration with:

```fish
source ~/.config/fish/config.fish
```

## 📂 What BVM Installs

When you install a BoxLang version with BVM, it downloads and sets up:

### Core Components

* **BoxLang Runtime** (`boxlang`, `bx`) - The main BoxLang interpreter
* **BoxLang MiniServer** (`boxlang-miniserver`, `bx-miniserver`) - Web application server

### Helper Scripts

* **install-bx-module** - BoxLang module installer (available in PATH after installation)
* **install-bvm** - BVM installer script (available in PATH after installation)
* **Other utility scripts** - Various helper tools

## 💡 Examples

```bash
# Install and use the latest BoxLang (detects actual version)
bvm install latest    # Downloads latest, detects version (e.g., 1.2.0), installs as 1.2.0
bvm use latest        # Uses the latest symlink

# Install a development snapshot (detects actual version)
bvm install snapshot  # Downloads snapshot, detects version (e.g., 1.3.0-snapshot), installs as 1.3.0-snapshot
bvm use 1.3.0-snapshot

# Install a specific version
bvm install 1.2.0
bvm use 1.2.0

# Force reinstall latest (get updates)
bvm install latest --force

# Force reinstall to recover from corruption
bvm install 1.2.0 --force

# Use short aliases for efficiency
bvm ls                    # List installed versions
bvm ls-remote            # List available versions
bvm rm 1.1.0             # Remove old version
bvm ms --port 8080       # Start MiniServer

# Check performance statistics
bvm stats                # Full stats output
bvm performance          # Same as stats
bvm usage               # Same as stats

# Health check with alias
bvm doctor              # Full command
bvm health              # Short alias

# Project-specific versions with .bvmrc
cd my-project
bvm local 1.2.0       # Creates .bvmrc with "1.2.0"
bvm use               # Uses version from .bvmrc (1.2.0)

cd ../another-project
bvm local latest      # Creates .bvmrc with "latest"
bvm use               # Uses version from .bvmrc (latest)

# Check current .bvmrc
bvm local             # Shows current .bvmrc version

# See what's installed (shows actual version numbers)
bvm list
# Example output:
#   * 1.2.0 (current)
#     latest → 1.2.0
#     1.3.0-snapshot
#     1.1.0

# or use the short alias
bvm ls

# Check what versions are available
bvm list-remote
# or use the short alias
bvm ls-remote

# Run BoxLang REPL
bvm exec
# or use the direct command (after installation)
boxlang

# Run BoxLang MiniServer
bvm miniserver
# or use the direct command
boxlang-miniserver --port 8080

# Install a BoxLang module (using helper script)
install-bx-module bx-orm

# Install a BoxLang site template (using helper script)
install-bx-site mysite

# Run a BoxLang script
bvm exec myscript.bx

# Get BoxLang version
bvm exec --version

# Check BVM health
bvm doctor

# Clean up cache
bvm clean
```

## 🔒 Security & Reliability

BVM includes several security and reliability enhancements to ensure safe and reliable installations:

### SHA-256 Checksum Verification

* 🔒 **Automatic verification** - Downloads and verifies SHA-256 checksums for all BoxLang downloads
* ✅ **Cryptographic integrity** - Ensures downloaded files haven't been tampered with
* 🛡️ **Security first** - Available for BoxLang 1.3.0 and later versions
* ⚠️ **Graceful fallback** - Clear warnings for pre-1.3.0 versions without checksums
* 🔧 **Multiple tools** - Supports both `sha256sum` (Linux) and `shasum` (macOS)

### Force Reinstallation

Use the `--force` flag to reinstall existing versions:

```bash
# Reinstall latest version (useful for getting updates)
bvm install latest --force

# Reinstall a specific version (useful for corruption recovery)
bvm install 1.2.0 --force

# Force works with any version
bvm install snapshot --force
```

**When to use `--force`:**

* 🔄 Recover from corrupted installations
* 🆙 Get the latest "latest" or "snapshot" builds
* 🛠️ Troubleshoot installation issues
* 🧪 Testing and development scenarios

### Command Aliases

BVM provides convenient short aliases for all major commands:

```bash
# List commands
bvm list          # Full command
bvm ls            # Short alias

bvm list-remote   # Full command
bvm ls-remote     # Short alias

# Remove commands
bvm remove 1.2.0  # Full command
bvm rm 1.2.0      # Short alias

# MiniServer commands
bvm miniserver    # Full command
bvm mini-server   # Alternative
bvm ms            # Short alias

# Maintenance commands
bvm doctor        # Full command
bvm health        # Alias

bvm stats         # Full command
bvm performance   # Alias
bvm usage         # Alias

# Version commands
bvm version       # Full command
bvm --version     # Standard flag
bvm -v            # Short flag

# Help commands
bvm help          # Full command
bvm --help        # Standard flag
bvm -h            # Short flag
```

### Automatic Snapshot Updates

BVM automatically ensures you have the latest development builds:

```bash
# When switching to snapshot, BVM automatically re-downloads
bvm use snapshot
# Output: "Snapshot version detected, re-downloading..."

# This ensures you always have the latest development build
# without manually forcing reinstallation
```

BVM now intelligently detects actual version numbers when installing "latest" or "snapshot" versions, providing clear and accurate version tracking.

### How Version Detection Works

When you install using aliases like "latest" or "snapshot", BVM:

1. **Downloads the requested version** (latest stable or development snapshot)
2. **Inspects the BoxLang JAR file** to extract the actual version number
3. **Installs under the detected version** (e.g., `1.2.0` or `1.3.0-snapshot`)
4. **Creates appropriate symlinks** (only for "latest" - points to the actual version)

### Benefits

* 🎯 **Clear version tracking** - `bvm list` shows actual version numbers, not generic aliases
* 📋 **Accurate history** - see exactly which versions you have installed
* 🔍 **No confusion** - distinguish between different snapshot builds
* 🔗 **Smart symlinks** - "latest" symlink for convenience, actual versions for clarity

### Example

**Before** (old behavior):

```bash
$ bvm list
Installed BoxLang versions:
  * latest (current)
    snapshot
    1.1.0
```

**After** (new behavior):

```bash
$ bvm list
Installed BoxLang versions:
  * 1.2.0 (current)
    latest → 1.2.0
    1.3.0-snapshot
    1.1.0
```

## 📁 Project-Specific Versions (.bvmrc)

BVM supports project-specific version configuration through `.bvmrc` files, similar to tools like `jenv` or `nvm`. This allows different projects to automatically use different BoxLang versions.

### How .bvmrc Works

* 📁 **Per-project configuration** - Each project can have its own BoxLang version
* 🔍 **Automatic discovery** - BVM searches from current directory up to root for `.bvmrc`
* 🎯 **Simple format** - Just the version number on the first line
* 🚀 **Seamless switching** - Use `bvm use` without arguments to activate the project version

### Creating .bvmrc Files

```bash
# Set current directory to use latest BoxLang
bvm local latest

# Set specific version for a project
bvm local 1.2.0

# Show current .bvmrc version (if any)
bvm local
```

### Using .bvmrc Files

```bash
# Activate the version specified in .bvmrc
bvm use

# This will search for .bvmrc starting from current directory
# and going up the directory tree until found
```

### .bvmrc File Format

The `.bvmrc` file is simple - just put the version on the first line:

```bash
# .bvmrc examples

# Use latest stable
latest

# Use specific version
1.3.0

# Comments (lines starting with #) are ignored
# Empty lines are also ignored
```

### Example Workflow

```bash
# Set up a new project
mkdir my-boxlang-project
cd my-boxlang-project

# Configure project to use specific BoxLang version
bvm local 1.2.0

# Install the version if not already installed
bvm install 1.2.0

# Use the project version (reads from .bvmrc)
bvm use

# Verify active version
bvm current

# The .bvmrc file is created in current directory
cat .bvmrc
# Output: 1.2.0

# When you return to this directory later, just run:
bvm use  # Automatically uses 1.2.0 from .bvmrc
```

### Directory Hierarchy

BVM searches for `.bvmrc` files starting from the current directory and walking up the directory tree:

```
/home/user/projects/
├── .bvmrc (latest)          # Root project config
├── project-a/
│   ├── .bvmrc (1.2.0)      # Project A uses 1.2.0
│   └── src/                 # When in src/, uses 1.2.0 from parent
└── project-b/
    ├── .bvmrc (1.2.0)    # Project B uses 1.2.0
    └── modules/
        └── auth/            # When in auth/, uses 1.2.0 from ancestor
```

## ⌨️ Commands

### Version Management

* `bvm install <version>` - Install a specific BoxLang version
  * `bvm install latest` - Install latest stable release (detects and installs actual version, e.g., `1.2.0`)
  * `bvm install snapshot` - Install latest development snapshot (detects and installs actual version, e.g., `1.3.0-snapshot`)
  * `bvm install 1.2.0` - Install specific version
  * `bvm install <version> --force` - Force reinstall existing version (useful for updates or corruption recovery)
* `bvm use <version>` - Switch to a specific BoxLang version
  * Can use actual version numbers (e.g., `1.2.0`, `1.3.0-snapshot`) or `latest` symlink
  * `bvm use` - Use version from `.bvmrc` file (if present)
* `bvm local <version>` - Set local BoxLang version for current directory (creates `.bvmrc`)
  * `bvm local` - Show current `.bvmrc` version
* `bvm current` - Show currently active BoxLang version
* `bvm remove <version>` - Remove a specific BoxLang version (use actual version number)
  * Aliases: `bvm rm <version>`
* `bvm uninstall` - Completely uninstall BVM and all BoxLang versions

### Information

* `bvm list` - List all installed BoxLang versions (shows actual version numbers and symlinks)
  * Alias: `bvm ls`
  * Example output: `1.2.0`, `latest → 1.2.0`, `1.3.0-snapshot`
* `bvm list-remote` - List available BoxLang versions for download
  * Alias: `bvm ls-remote`
* `bvm which` - Show path to current BoxLang installation
* `bvm version` - Show BVM version
  * Aliases: `bvm --version`, `bvm -v`

### Execution

* `bvm exec <args>` - Execute BoxLang with current version
  * Alias: `bvm run <args>`
* `bvm miniserver <args>` - Start BoxLang MiniServer with current version
  * Aliases: `bvm mini-server <args>`, `bvm ms <args>`

### Maintenance

* `bvm check-update` - Check for BVM updates and optionally upgrade
* `bvm clean` - Clean cache and temporary files
* `bvm stats` - Show performance and usage statistics
  * Aliases: `bvm performance`, `bvm usage`
* `bvm doctor` - Check BVM installation health
  * Alias: `bvm health`
* `bvm help` - Show help message
  * Aliases: `bvm --help`, `bvm -h`

## 🔄 Keeping BVM Updated

BVM includes a built-in update checker that helps you stay current with the latest version.

### Checking for Updates

```bash
# Check if a newer version of BVM is available
bvm check-update
```

### Update Process

When you run `bvm check-update`, BVM will:

1. **Check your current version** - reads from local installation
2. **Fetch the latest version** - checks the remote repository
3. **Compare versions** - determines if an update is available
4. **Show status** - displays current vs. latest version information

### Interactive Upgrade

If a newer version is available, BVM will:

* 🆙 **Display the available update** - shows current and latest version numbers
* ❓ **Prompt for confirmation** - asks if you want to upgrade
* 🚀 **Automatically upgrade** - downloads and installs the latest version if you confirm
* ✅ **Preserve your installations** - keeps all your BoxLang versions intact

### Example Update Session

```bash
$ bvm check-update

─────────────────────────────────────────────────────────────────────────────
🔄 BVM Update Checker
─────────────────────────────────────────────────────────────────────────────

🔍 Checking for BVM updates...

Current BVM version: 1.0.0
Latest BVM version:  1.1.0

🆙 A newer version of BVM is available!

Would you like to upgrade to version [1.1.0]? [Y/n]: Y

🚀 Starting BVM upgrade to version [1.1.0]...
⚡Executing upgrade using: /Users/username/.bvm/scripts/install-bvm.sh
```

### Status Messages

* 🦾 **Up to date**: "You have the latest version of BVM!"
* 🆙 **Update available**: "A newer version of BVM is available!"
* 🧑‍💻 **Development version**: "Your BVM version is newer than the latest release"

## 🗑️ Uninstalling BoxLang Versions and BVM

BVM provides two different uninstall options depending on your needs.

### Removing Individual BoxLang Versions

Use `bvm remove` (or `bvm rm`) to remove specific BoxLang versions you no longer need:

```bash
# Remove a specific version
bvm remove 1.1.0
# or use the alias
bvm rm 1.1.0

# List installed versions first to see what's available
bvm list
```

#### Important Notes

* **Cannot remove active version**: You cannot remove the currently active BoxLang version
* **Confirmation required**: BVM will ask for confirmation before removing a version
* **Use actual version numbers**: Use the actual version number (e.g., `1.2.0`), not aliases like `latest`

#### Example Session

```bash
$ bvm list
Installed BoxLang versions:
  * 1.2.0 (current)
    latest → 1.2.0
    1.1.0

$ bvm remove 1.1.0
Are you sure you want to uninstall BoxLang 1.1.0? [y/N]: y
✅ BoxLang 1.1.0 uninstalled successfully
```

### Completely Uninstalling BVM

Use `bvm uninstall` to completely remove BVM and all installed BoxLang versions:

```bash
bvm uninstall
```

#### What Gets Removed

* 🗑️ **All BoxLang versions** - every installed version will be deleted
* 🗑️ **BVM home directory** - `~/.bvm` and all contents
* 🗑️ **Cache files** - all downloaded installers and temporary files
* 🗑️ **Version symlinks** - `latest` and other version links

#### Complete Uninstall Process

```bash
$ bvm uninstall

⚠️  COMPLETE BVM UNINSTALL ⚠️

This will completely remove BVM and ALL installed BoxLang versions from your system!

Installed versions that will be DELETED:
  • 1.2.0 (current)
  • 1.1.0
  • latest → 1.2.0

Cache and configuration that will be DELETED:
  • ~/.bvm/cache (downloaded files)
  • ~/.bvm/versions (all BoxLang installations)
  • ~/.bvm/scripts (BVM helper scripts)
  • ~/.bvm/config (BVM configuration)

Are you absolutely sure you want to completely uninstall BVM? [y/N]: y

🔄 Uninstalling BVM...
✅ Removed BVM home directory: /Users/username/.bvm
🎉 BVM has been completely uninstalled!

Manual cleanup required:
  • Remove any BVM-related entries from your shell profile (~/.bashrc, ~/.zshrc, etc.)
  • Remove the BVM binary from your PATH if you installed it system-wide
```

#### Manual Cleanup

After running `bvm uninstall`, you may need to manually:

1. **Remove shell profile entries** - delete BVM-related lines from `~/.bashrc`, `~/.zshrc`, etc.
2. **Remove from PATH** - if you installed BVM system-wide, remove it from your PATH
3. **Restart terminal** - open a new terminal session to ensure changes take effect

## 🔄 Migrating from Single-Version Installer to BVM

If you currently have BoxLang installed via `install-boxlang.sh` and want to switch to BVM for version management:

{% stepper %}
{% step %}

### Uninstall Current BoxLang (Recommended)

```bash
# Remove system-wide installation
sudo install-boxlang.sh --uninstall

# Or remove user installation
install-boxlang.sh --uninstall
```

{% endstep %}

{% step %}

### Install BVM

```bash
curl -fsSL https://install-bvm.boxlang.io | bash
```

{% endstep %}

{% step %}

### Install Your Preferred BoxLang Version

```bash
# Install the same version you had before
bvm install latest  # or specific version like 1.2.0
bvm use latest
```

{% endstep %}

{% step %}

### Verify Everything Works

```bash
bvm doctor
boxlang --version
```

**Note:** Your BoxLang home directory (`~/.boxlang`) with modules, settings, and data will be preserved during migration.
{% endstep %}
{% endstepper %}

````

## 🔧 Troubleshooting

### BVM not found after installation

- Restart your terminal
- Check that `~/.bvm/bin` is in your PATH
- Run `source ~/.bashrc` (or your shell's profile file)

### BoxLang not found after switching versions

- Run `bvm doctor` to check installation health
- Verify the version exists with `bvm list`
- Try `bvm use <version>` again

### Download failures

- Check your internet connection
- Verify the version exists with `bvm list-remote`
- Try clearing cache with `bvm clean`

### Health check

```bash
bvm doctor
````

This will check your BVM installation and identify any issues.

## 🤝 Contributing

BVM is part of the BoxLang Quick Installer project. To contribute:

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Test thoroughly
5. Submit a pull request

```

## 📄 License

MIT License - see LICENSE file for details.

## 💬 Support

- 🌐 Website: https://boxlang.io
- 📖 Documentation: https://boxlang.io/docs
- 💾 GitHub: https://github.com/ortus-boxlang/boxlang
- 💬 Community: https://boxlang.io/community
- 🧑‍💻 Try: https://try.boxlang.io
- 🫶 Professional Support: https://boxlang.io/plans
```


# Homebrew

Easily install BoxLang or our BoxLang Version Manager (BVM) with Homebrew!

**🥊 The official Homebrew tap for the BoxLang JVM Language!**

Make sure you have Homebrew installed: <https://brew.sh/>

{% embed url="<https://brew.sh/>" %}

### Installation

First, add this tap to Homebrew:

```bash
brew tap ortus-boxlang/boxlang
```

***

### Formulas

#### `bvm` — BoxLang Version Manager

Installs [BVM](https://boxlang.ortusbooks.com/getting-started/installation/boxlang-version-manager-bvm), the BoxLang Version Manager, which lets you install and switch between multiple BoxLang versions.

```bash
brew install ortus-boxlang/boxlang/bvm
```

After installation, install and activate BoxLang:

```bash
bvm install latest
bvm use latest
boxlang --version
```

Common BVM commands:

```bash
bvm install latest    # Install the latest stable BoxLang
bvm install snapshot  # Install the latest snapshot
bvm use latest        # Switch to the latest version
bvm list              # List locally installed versions
bvm current           # Show the active version
bvm help              # Show all available commands
```

***

#### `boxlang` — BoxLang Quick Installer

Installs the [BoxLang Quick Installer](https://boxlang.ortusbooks.com/getting-started/installation/boxlang-quick-installer), which sets up BoxLang (runtime and MiniServer) in a single step.

```bash
brew install ortus-boxlang/boxlang/boxlang
```

After installation, run the installer to set up BoxLang:

```bash
install-boxlang
```

Additional options:

```bash
install-boxlang --with-jre     # Auto-install Java 21 JRE if not found
install-boxlang --yes          # Accept all defaults (non-interactive)
sudo install-boxlang --system  # Install system-wide (all users)
```

After the installer completes, add the following to your shell profile (`~/.zshrc` or `~/.bashrc`) and restart your terminal:

```bash
export PATH="$HOME/.local/bin:$PATH"
```

You can then run BoxLang:

```bash
boxlang               # Start the BoxLang REPL
boxlang --version     # Check the installed version
boxlang-miniserver    # Start the BoxLang MiniServer
```

***

### Prerequisites

Both formulas automatically pull in the following dependencies via Homebrew:

* `curl`
* `unzip`
* `jq`
* `openjdk@21`

***

### Auto-updates

This tap ships with a GitHub Actions workflow (`.github/workflows/update-formulas.yml`) that keeps the formulas up to date automatically:

* **Scheduled**: runs daily at 06:00 UTC.
* **Manual**: trigger the *Update Homebrew Formulas* workflow from the Actions tab at any time.
* **On release**: the `ortus-boxlang/boxlang-quick-installer` repository can trigger an update immediately after publishing a new release by dispatching a `repository_dispatch` event of type `installer-released` to this repository.

When a new version of the [BoxLang Quick Installer](https://github.com/ortus-boxlang/boxlang-quick-installer) is published the workflow updates both formulas and commits the change automatically. Once the tap formula is updated, users running `brew upgrade` will receive the latest installer version.

> **Note on BoxLang runtime versions**: the formulas install the *installer tool*, not a pinned BoxLang runtime. After upgrading the formula you can get the latest BoxLang runtime with `bvm install latest && bvm use latest` or by re-running `install-boxlang`.


# Modules

The Officially supported BoxLang modules

Our official modules can be found in the BoxLang Software Directory: **FORGEBOX**: [www.forgebox.io](https://www.forgebox.io).

{% hint style="success" %}
Every runtime can use modules, and the installation process can differ. So, make sure you review each of the sections on Running BoxLang and adapt your installation process accordingly.
{% endhint %}

For web runtimes running on CommandBox, our servlet server, then use the `box` CommandBox CLI for installation and `server.json` for tracking dependencies. For our operating system runtime, use our `install-bx-module` binary.

### Operating System Modules

{% code title="Operating System" %}

```bash
# Install os-wide modules
install-bx-module bx-compat-cfml

# Install BoxLang+ MCP stack (requires subscription)
install-bx-module bx-plus bx-ai bx-mcp

# Install os-wide modules with a specific version
install-bx-module bx-compat-cfml@1.0.0

# Install multiple modules
install-bx-module bx-compat-cfml bx-esapi bx-orm
```

{% endcode %}

#### Local CLI Application Modules

BoxLang also supports the concept of local loading. Meaning, if you have a `boxlang_modules` folder in the root of where you run your CLI applications, then BoxLang will load those modules first and then fall back to the user's home directory for the operating system.

{% hint style="info" %}
A module can also ship modules of its own, in a `modules` folder inside it — loaded before the module itself. A `.jar` dropped into any modules folder is a module too. See [Module Inception](/boxlang-framework/module-development/module-inception).
{% endhint %}

{% code title="myAppDirectory" %}

```bash
# Install locally
install-bx-module bx-compat-cfml --local

# Install locally
install-bx-module bx-compat-cfml@1.0.0 --local

# Install multiple modules locally
install-bx-module bx-compat-cfml bx-esapi bx-orm --local
```

{% endcode %}

### CommandBox Runtimes

The CommandBox CLI installs BoxLang modules into web runtimes.

{% hint style="warning" %}
Eventually, CommandBox will be the de-facto standard of installation once it's migrated to BoxLang.
{% endhint %}

{% code title="CommandBox" %}

```bash
box install bx-compat-cfml,bx-esapi

# Install BoxLang+ MCP stack (requires subscription)
box install bx-plus,bx-ai,bx-mcp
```

{% endcode %}

{% hint style="info" %}
The `bx-mcp` module is a premium BoxLang+/++ module and requires both `bx-plus` and `bx-ai`.
{% endhint %}

### Configuration

You can customize the boxlang module directory by changing the `runtime.modulesDirectory` setting in your `config/boxlang.json` file:

{% code title="boxlang.json" %}

```json
{

    // A collection of BoxLang module directories, they must be absolute paths
    "modulesDirectory": [
      "${boxlang-home}/modules"
    ],

}
```

{% endcode %}

## Core Modules

Visit the [Modules](/boxlang-framework/modularity) section of our docs for the most up to date listing of our supported modules.

## CLI Executables and Bash Completions

When you install a module with `install-bx-module`, it can also come with its own CLI wrapper executable(s) and a bash completion script, both wired up automatically. See [CLI Executables and Completions](/boxlang-framework/module-development/module-descriptor#cli-executables-and-completions) in the module authoring docs for how a module declares these in its `box.json`.


# Running BoxLang

BoxLang and the Multiverse!

{% hint style="warning" %}
Please check out our [installation page ](/getting-started/installation)to make sure you install the right runtime you want to deploy on. We are assuming you have it installed and `boxlang` and `boxlang-miniserver` are in your machine's path.
{% endhint %}

{% hint style="info" %}
The script for \*nix/Mac is `boxlang`

The script for Windows is `boxlang.bat`
{% endhint %}

### BoxLang Home <a href="#start-the-repl-8" id="start-the-repl-8"></a>

By default, once you execute a `boxlang` binary it will look for a `BOXLANG_HOME` environment variable so it can be used as the home for the OS runtime. If you don't provide one, then by default, it will use the currently logged-in user's home folder + `.boxlang`

{% tabs %}
{% tab title="Mac" %}

```javascript
/Users/username/.boxlang
```

{% endtab %}

{% tab title="Linux" %}

```bash
/home/username/.boxlang
```

{% endtab %}

{% tab title="Windows" %}

```python
C:\Users\myuser\.boxlang
```

{% endtab %}
{% endtabs %}

This is important because inside of the home folder, you can have several folders and files by convention that will be used for the runtime execution.

{% hint style="danger" %}
Please note that each runtime can have a different location for the BoxLang home. So make sure you read each of the runtime's docs to see where each goes.
{% endhint %}

<table><thead><tr><th width="257">Folder/FIle</th><th>Description</th></tr></thead><tbody><tr><td><code>/classes</code></td><td>Where all the compiled classes will be stored</td></tr><tr><td><code>/config</code></td><td>Where configuration files are stored for the runtime</td></tr><tr><td><code>/config/boxlang.json</code></td><td>The <a href="/pages/MGinWajbd84HFWrqmvLt">runtime configuration file</a>. Here is where you can configure all the settings, caches, datasources, compiler information, and so much more.</td></tr><tr><td><code>/global</code></td><td>Where global BoxLang classes and component templates can be stored for the entire runtime</td></tr><tr><td><code>/lib</code></td><td>You can place any *.jar files here, and they will be loaded into the runtime at startup. This is a great place to put third-party jars that will be available at runtime.</td></tr><tr><td><code>/logs</code></td><td>All log files will be stored here</td></tr><tr><td><code>/modules</code></td><td>Here is where the BoxLang modules are installed and will be available for the entire operating system binary.</td></tr><tr><td><code>version.properties</code></td><td>The version information of the installed runtime.</td></tr></tbody></table>

### Start the REPL <a href="#start-the-repl-8" id="start-the-repl-8"></a>

The first thing you can do is start up the BoxLang REPL, make sure the insaller has added your installation directory to the `PATH` system variable.

{% tabs %}
{% tab title="Mac/\*nix" %}

```javascript
boxlang
```

{% endtab %}

{% tab title="Windows" %}

```ruby
boxlang.bat
```

{% endtab %}

{% tab title="Jar" %}

```
java -jar path/to/boxlang-1.0.0.jar
```

{% endtab %}
{% endtabs %}

<figure><img src="/files/1qkpdKoAtYM0QyOuYFdS" alt=""><figcaption></figcaption></figure>

You can run one-off expressions from the REPL like so:

```shell
Enter an expression, then hit enter.
Press Ctrl-C to exit.

BoxLang> 2+2
4

BoxLang> dateFormat( now(), "full" )
Wednesday, March 13, 2024

BoxLang> "brad".ucase().reverse()
DARB

BoxLang> a=3
3

BoxLang> b=5
5

BoxLang> a*b
15

BoxLang> ["luis","gavin","jorge"].map( name->name.ucFirst() )
[Luis, Gavin, Jorge]

```

{% hint style="success" %}
Press Ctrl-C to exit the REPL or type `exit` or `quit`
{% endhint %}

Please note that the REPL remembers state, so you can use the variables you declare and build a mini-program with it.

### Executing a File <a href="#execute-a-file-9" id="execute-a-file-9"></a>

You can also use the `boxlang` binary to execute BoxLang or even CFML code. You can pass a second argument to the binary and it can be a relative (to the current directory you are on) or an absolute path to a file that you wish to execute.

{% hint style="info" %}
Allowed files are:

* `*.bx -` A BoxLang class with a `main( args=[] )` method
* \*.bxs - A BoxLang script file
* \*.bxm - A Boxlang markup template file

If you are using the `bx-compat-cfml` module for CFML Support:

* \*.cfs - A CFML script file
* \*.cfm - A CFML markup template file
  {% endhint %}

Modify the same command you run above to execute the REPL but add a file path to the end. It can be absolute or relative to the current working directory.

{% tabs %}
{% tab title="Mac / \*Unix" %}

```bash
boxlang task.bx
boxlang myscript.bxs
boxlang mytemplate.bxm

boxlang /full/path/to/test.bxs
boxlang /full/path/to/Task.bx
```

{% endtab %}

{% tab title="Windows" %}

```powershell
boxlang.bat task.bx
boxlang.bat myscript.bxs
boxlang.bat mytemplate.bxm
```

{% endtab %}

{% tab title="Jar" %}

```ruby
java -jar boxlang-1.0.0.jar task.bx
java -jar boxlang-1.0.0.jar /full/path/to/test.bxs
```

{% endtab %}
{% endtabs %}

#### Producing Output

As you navigate all the built-in functions and capabilities of BoxLang, let's learn how to produce output to the system console.

* `printLn()` - Print with a line break
* `print()` - Print with no line break
* `writeOutput()` - Writes to the output buffer (Each runtime decides what it's buffer is. The CLI is the system output, the Web is the HTML response buffer, etc)

```groovy
println( "Time is #now()#" )
```

I get the output:

```bash
╰─ boxlang test.bxs
Time is {ts '2024-05-22 22:09:56'}
```

Hooray! You have executed your first script using BoxLang. Now let's build a class with a `main( args=[] )` convention. This is simliar to Java or Groovy.

```groovy
class{

        function main( args=[] ){

                println( "Task called with " & arguments.toString() )

        }

}
```

You can now call it with zero or more arguments!

```bash
╰─ boxlang Task.bx
Task called with {ARGS=[]}

╰─ boxlang Task.bx boxlang rocks
Task called with {ARGS=[boxlang, rocks]}
```

### One Off Code Execution

So, to give a quiet example of the `--bx-code` flag here’s running some one-off code.

```bash
boxlang --bx-code "2+2"
```

{% hint style="warning" %}
This assumes script, not templating tags.
{% endhint %}

### Piping code <a href="#piping-code-11" id="piping-code-11"></a>

You can also pipe statements into the BoxLang binary for execution as well. This assumes script, not tags.

```bash
echo "2+2" | java -jar boxlang-1.0.0.jar
echo "2+2" | boxlang
```

or

```bash
# on *nix
cat test.cfs | java -jar boxlang-1.0.0.jar
cat test.cfs | boxlang

# on Windows
type test.cfs | java -jar boxlang-1.0.0.jar
type test.cfs | boxlang.bat
```

### Printing the Abstract Syntax Tree (AST)

BoxLang can emit the parsed **Abstract Syntax Tree** of any source as JSON, which is useful for tooling, debugging, and editor integrations. There are two ways to access the AST.

#### Via the CLI Flag

Use the `--bx-printAST` flag with any of the three input modes:

```bash
# From a file
boxlang --bx-printAST /path/to/MyClass.bx

# From inline code
boxlang --bx-printAST --bx-code "x = 1 + 2"

# From stdin
cat MyComponent.bx | boxlang --bx-printAST

# Integrate with jq for targeted inspection
cat MyComponent.bx | boxlang --bx-printAST | jq '.body[0]'
```

#### Via the `boxAST()` BIF

You can also retrieve the AST programmatically at runtime using the `boxAST()` built-in function, which returns the JSON AST of any BoxLang source string:

```js
ast = boxAST( "result = 1 + 2" )
writeDump( ast )
```

{% hint style="info" %}
The `boxAST()` BIF is useful for meta-programming, code analysis tooling, or any scenario where you need to inspect the structure of BoxLang code at runtime.
{% endhint %}

### Command Line Arguments <a href="#other-command-line-args-10" id="other-command-line-args-10"></a>

If you interact with the `boxlang` binary then you will be executing the `BoxRunner` class in BoxLang. You can use several options and positional arguments to our runtime. Let's explore them.

#### Options

* `--bx-code "code here"`—This is used to pass ad-hoc code to execute. Provide code in the next argument, quoted.
* `--bx-config` - Pass a path to a JSON file for BoxLang configuration. See [Runtime Configuration](/getting-started/configuration) for more information.
* `--bx-debug` - Enable debug mode (more debug logs!)
* `--bx-home` - Pass a path to a custom runtime home directory for storing modules, configuration, and more. See [Runtime Home Directory](/getting-started/configuration#runtime-home-directory) for more information.
* `--bx-printAST` - Prints out BoxLang AST in JSON format for debugging. Supports three input modes:
  * **File path**: `boxlang --bx-printAST /path/to/MyClass.bx`
  * **Inline code**: `boxlang --bx-printAST --bx-code "x = 1 + 2"`
  * **Stdin piping**: `cat MyComponent.bx | boxlang --bx-printAST`
* `--bx-transpile` - Prints out transpiled Java source that would be compiled to create the bytecode for the passed template path. (for debugging)
* `--version` - Output the current runtime's version information

#### Positionals

* `script_path | class_path` - The template, class, or script to execute
  * If it's a class, it must have a `main( args )` method.
* `module:{name}` - The executable module to execute. This will execute a Modules' `ModuleConfig.main( args )` method.
* `{actionCommand: compile,featureAudit, cftranspile}` - If you send any of those action commands, we will execute those CLI tools

### Using 3rd Party Jars <a href="#using-3rd-party-jars-14" id="using-3rd-party-jars-14"></a>

You can load custom third-party JARs at runtime by adding all your `*.jar` to the `BOXLANG_HOME/lib` folder. This will be loaded at runtime and available to use and integrate.

### Environment Variables

The `boxlang` binary will also scan for several environment variables as overrides to the execution process.

| Env Variable                  | Purpose                      |
| ----------------------------- | ---------------------------- |
| `BOXLANG_CONFIG` = PATH       | Override the `boxlang.json`  |
| `BOXLANG_DEBUG = BOOLEAN`     | Enable or disable debug mode |
| `BOXLANG_HOME = DIRECTORY`    | Override the HOME directory  |
| `BOXLANG_PRINTAST = BOOLEAN`  | Print the AST                |
| `BOXLANG_TRANSPILE = BOOLEAN` | Tranpile the code            |

In addition to core runtime OS-level settings, you can also use the environment or Java properties to adjust granular configuration setting. For more [see the Runtime Configuration section](https://boxlang.ortusbooks.com/getting-started/configuration#environmental-properties-configuration).


# AWS Lambda

BoxLang Runtime for AWS Lambda! Serverless for the win!

<figure><img src="/files/39e1J1SsNBiFoZAvvz4f" alt=""><figcaption></figcaption></figure>

## What is AWS Lambda?

<figure><img src="/files/QWKZxhyRKeUhu5xVZsPy" alt=""><figcaption></figcaption></figure>

AWS Lambda is a serverless computing service provided by Amazon Web Services (AWS) that lets you run code without provisioning or managing servers. It automatically scales applications by running code in response to events and allocates compute resources as needed, allowing developers to focus on writing code rather than managing infrastructure (<https://docs.aws.amazon.com/lambda/>).

The **BoxLang AWS Runtime** allows you to code in BoxLang and create Lambda functions in this ecosystem. We provide you a nice template so you can work with serverless: <https://github.com/ortus-boxlang/boxlang-starter-aws-lambda>. This template will give you a turnkey application with features like:

* Unit and Integration Testing
* Java dependency management via Maven
* BoxLang dependency management
* Automatic shading and packaging
* Class compilation caching for improved performance
* Connection pooling for database operations
* Configuration management with environment overrides
* SAM CLI integration for local testing
* GitHub actions to: test, build and release automatically to AWS
* Performance monitoring and debugging capabilities

{% @github-files/github-code-block url="<https://github.com/ortus-boxlang/boxlang-starter-aws-lambda>" %}

## 📋 Table of Contents

* [What is AWS Lambda?](#what-is-aws-lambda)
* [BoxLang Lambda Handler](#boxlang-lambda-handler)
* [Environment Variables](#environment-variables)
* [BoxLang AWS Template](#boxlang-aws-template)
* [Lambda.bx](#lambdabx)
* [Performance Enhancements](#performance-enhancements)
* [Convention-Based URI Routing](#convention-based-uri-routing)
* [Multiple Functions Header](#multiple-functions-header)
* [Lambda Modules](#lambda-modules)
* [Local Development & Testing](#local-development--testing)
* [Deploy to AWS](#deploy-to-aws)
* [Runtime Source Code](#runtime-source-code)

## BoxLang Lambda Handler

<figure><img src="/files/T9zrv7ovyzHOaniqCLqS" alt=""><figcaption></figcaption></figure>

Our BoxLang AWS Handler acts as a front controller to all incoming Lambda executions. It provides you with:

* Automatic request management to an `event` structure
* Automatic logging and tracing
* Execution of your Lambda classes by convention
* Automatic error management and exception handling
* Automatic response management and serialization
* Life-Cycle Events via our `Application.bx`
* **NEW**: Class compilation caching for improved performance
* **NEW**: Connection pooling for database operations
* **NEW**: Performance metrics and debugging capabilities
* **NEW**: Custom method resolution via headers

The BoxLang AWS runtime provides a pre-built Java handler for Lambda already configured to accept JSON in as a BoxLang Struct and then output either by returning a simple or complex object or using our `response` convention struct. Our runtime will automatically convert your results to JSON.

The default handler you configure your lambda with is:

```
ortus.boxlang.runtime.aws.LambdaRunner::handleRequest
```

{% hint style="info" %}
You can see the code for the handler here: <https://github.com/ortus-boxlang/boxlang-aws-lambda/blob/development/src/main/java/ortus/boxlang/runtime/aws/LambdaRunner.java#L161>
{% endhint %}

The handler will look for a `Lambda.bx`in your package and execute the `run()`method by convention.

{% code title="Lambda.bx" %}

```java
class {

    function run( event, context, response ){


    }

}
```

{% endcode %}

## Environment Variables

The following are all the environment variables the Lambda runtime can read and detect. If they are set by you or the AWS Lambda runner, then it will use those values to alter operations. This doesn't mean that they will exist at runtime, it just means you can set them to alter behavior.

| Environment Variable                  | Description                                                                                                                            |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `BOXLANG_LAMBDA_CLASS`                | Absolute path to the lambda to execute. The default path is: `/var/task/Lambda.bx` Which is your lambda deployed within your zip file. |
| `BOXLANG_LAMBDA_DEBUGMODE`            | Turn runtime debug mode on or off. When enabled, provides performance metrics and detailed logging.                                    |
| `BOXLANG_LAMBDA_CONFIG`               | Absolute path to a custom `boxlang.json` configuration for the runtime. Defaults to `/var/task/boxlang.json`                           |
| `BOXLANG_LAMBDA_CONNECTION_POOL_SIZE` | **NEW**: Configure the connection pool size for database operations. Default is 2 connections.                                         |
| `LAMBDA_TASK_ROOT`                    | Lambda deployment root directory. Defaults to `/var/task`                                                                              |

You can also leverage ANY environment variable to configure the BoxLang runtime using our runtime [environment conventions](/getting-started/configuration).

### Performance Environment Variables

The runtime now includes several performance optimizations that can be controlled via environment variables:

* **Class Compilation Caching**: Lambda classes are automatically cached to avoid recompilation
* **Connection Pooling**: Database connections are pooled and reused across invocations
* **Performance Metrics**: Debug mode provides timing and memory usage information

## BoxLang AWS Template

The BoxLang default template for AWS lambda can be found here: <https://github.com/ortus-boxlang/boxlang-starter-aws-lambda>. The structure of the project is the following:

```
/.vscode - Some useful vscode tasks and settings
/gradle - The gradle runtime, keep in source control
/src
  + main
    + bx
      + Application.bx (Your life-cycle class)
      + Lambda.bx (Your BoxLang Lambda function)
  + resources
    + boxlang.json (A custom BoxLang configuration file)
    + boxlang_modules (Where you will install BoxLang modules)
  + test
    + java
      + com
        + myproject
          + LambdaRunnerTest.java (An integration test for your Lambda)
          + TestContext.java (A testing context for lambda)
          + TestLogger.java (A testing logger for lambda)
/workbench - AWS lambda utilities and scripts
  + config.env - Default configuration settings
  + config.local.env - Local configuration overrides (create from config.env)
  + sampleEvents/ - Sample Lambda event payloads for testing
  + template.yml - SAM template for local testing and deployment
  + *.sh - Deployment and management scripts
/box.json - Your project's dependency descriptor for CommandBox
/build.gradle - The gradle build configuration
/gradle.properties - Where you store your version and metadata
/gradlew - The gradle shell executor, keep in source control
/gradlew.bat - The gradle shell executor, keep in source control
/settings.gradle - The project settings
```

The BoxLang AWS Lambda runtime will look for a `Lambda.bx` in your package by convention and execute the `run()` method for you.

### Key Template Features

* **Configuration Management**: Hierarchical configuration system using `config.env` → `config.local.env` → environment variables
* **SAM Integration**: Full AWS SAM support for local testing and deployment
* **Maven Dependency Resolution**: Automatic dependency management via Maven
* **Performance Optimizations**: Class caching, connection pooling, and performance monitoring built-in
* **Local Testing**: Multiple Gradle tasks for local development and testing
* **AI Development Support**: Comprehensive GitHub Copilot instructions for enhanced development experience

{% hint style="info" %}
**AI-Assisted Development**: The BoxLang AWS Lambda template includes comprehensive GitHub Copilot instructions (`.github/copilot-instructions.md`) that provide AI assistants with detailed context about:

* Project architecture and conventions
* Build system and deployment workflows
* Pascal case routing patterns
* Configuration management
* Testing strategies and file locations

This enables more accurate and contextual assistance when developing BoxLang Lambda functions.
{% endhint %}

### Building and Testing

```bash
# Create local configuration (customize as needed)
cp workbench/config.env workbench/config.local.env

# Run the tests
./gradlew test

# Build the project, create the lambda zip
# The location is /build/distributions/{project}-{version}.zip
./gradlew build

# Local testing with SAM
./gradlew runLocal          # Basic Lambda execution
./gradlew runLocalApi       # API Gateway event
./gradlew runLocalLegacy    # Legacy API Gateway event

# Start local HTTP server for API testing
./gradlew startSamServerBackground

# Clean build artifacts
./gradlew clean
```

## Lambda.bx

The Lambda function is a BoxLang class with a single function called `run()`.

<pre class="language-groovy" data-title="Lambda.bx" data-line-numbers><code class="lang-groovy"><strong>/**
</strong> * My BoxLang Lambda
 */
class{

	function run( event, context, response ){
		response.body = {
			"error": false,
			"messages": [],
			"data": "====> Incoming event " &#x26; event.toString()
		};
		response.statusCode = 200;
	}
}
</code></pre>

### Arguments

It accepts three arguments:

<table><thead><tr><th width="137">Argument</th><th width="264">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>event</code></td><td><code>Struct</code></td><td>All the incoming JSON as a BoxLang struct</td></tr><tr><td><code>context</code></td><td><code>com.amazonaws.services.lambda.runtime.Context</code></td><td>The AWS context object. You can find much <a href="https://docs.aws.amazon.com/lambda/latest/dg/java-context.html">more information here.</a></td></tr><tr><td><code>response</code></td><td><code>Struct</code></td><td>A BoxLang struct convention for a response.</td></tr></tbody></table>

{% hint style="success" %}
You can find more information about the AWS Context object here: <https://docs.aws.amazon.com/lambda/latest/dg/java-context.html>
{% endhint %}

#### Event

The `event` structure is a snapshot of the input to your lambda. We deserialize the incoming JSON for you and give you a nice struct.

#### Context

This is an Amazon Java class that provides extensive information about the request. For more information, check out the API in the Amazon Docs (<https://docs.aws.amazon.com/lambda/latest/dg/java-context.html>)

#### Context methods

* `getRemainingTimeInMillis()` – Returns the number of milliseconds left before the execution times out.
* `getFunctionName()` – Returns the name of the Lambda function.
* `getFunctionVersion()` – Returns the [version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html) of the function.
* `getInvokedFunctionArn()` – Returns the Amazon Resource Name (ARN) that's used to invoke the function. Indicates if the invoker specified a version number or alias.
* `getMemoryLimitInMB()` – Returns the amount of memory that's allocated for the function.
* `getAwsRequestId()` – Returns the identifier of the invocation request.
* `getLogGroupName()` – Returns the log group for the function.
* `getLogStreamName()` – Returns the log stream for the function instance.
* `getIdentity()` – (mobile apps) Returns information about the Amazon Cognito identity that authorized the request.
* `getClientContext()` – (mobile apps) Returns the client context that's provided to Lambda by the client application.
* `getLogger()` – Returns the [logger object](https://docs.aws.amazon.com/lambda/latest/dg/java-logging.html) for the function.

#### Response

The `response` argument is our convention to help you build a nice return structure. However, it is completely optional. You can easily return a simple or complex object from your lambda, and we will convert it to JSON.

```json
response : {
  statusCode : 200,
  headers : {
    content-type :  "application/json",
    access-control-allow-origin : "*",
  },
  body : YourLambda.run() results
}
```

{% code lineNumbers="true" %}

```groovy
/**
 * My BoxLang Lambda Simple Return
 */
class{

  function run( event, context, response ){
    return "Hello World!"
  }

}

/**
 * My BoxLang Lambda Complex Return
 */
class{

  function run( event, context, response ){
    return {
      age : 1,
      when : now(),
      data : [ 12,3234,23423 ]
    };
  }

}
```

{% endcode %}

Now you can go ahead and build your function. You can use TestBox to unit test your `Lambda.bx` or we even include a `src/test` folder in Java, that simulates the full life-cycle of the runtime. Just run `gradle test` or use VSCode BoxLang IDE to run the tests. Now we go to production!

## Performance Enhancements

The BoxLang AWS Lambda runtime includes several performance optimizations:

### Class Compilation Caching

Lambda classes are automatically cached between invocations to avoid recompilation overhead:

```javascript
// Your Lambda classes are compiled once and cached
class {
    function run( event, context, response ) {
        // This class is cached after first compilation
        return processEvent( event );
    }
}
```

### Connection Pooling

Database connections are pooled and reused across Lambda invocations:

```javascript
// Configure connection pool size via environment variable
// BOXLANG_LAMBDA_CONNECTION_POOL_SIZE=5

function run( event, context, response ) {
    // Connections are automatically pooled and reused
    var results = queryExecute( "SELECT * FROM users" );
    return results;
}
```

### Performance Monitoring

Enable debug mode to get performance metrics:

```bash
# Set environment variable for performance monitoring
BOXLANG_LAMBDA_DEBUGMODE=true
```

This provides:

* Class compilation timing
* Memory usage metrics
* Request processing duration
* Connection pool statistics

## Convention-Based URI Routing

**NEW in v1.5.0**: The runtime now supports automatic routing using **PascalCase conventions**, allowing you to build multi-class Lambda functions with BoxLang easily following our conventions.

When your Lambda is exposed as a URL, the runtime can automatically route to different BoxLang classes based on the URI path:

```javascript
// URL: /products -> Products.bx
// URL: /home-savings -> HomeSavings.bx
// URL: /user-profile -> UserProfile.bx
```

### Example Multi-Class Structure

```
/src/main/bx/
  ├── Lambda.bx          # Default handler (fallback)
  ├── Products.bx        # Handles /products
  ├── HomeSavings.bx     # Handles /home-savings
  └── UserProfile.bx     # Handles /user-profile
```

Each class should implement a `run` function:

```groovy
// Products.bx
class {
    function run( event, context, response ) {
        return {
            "statusCode" : 200,
            "body" : serializeJSON( getProductCatalog() )
        };
    }

    function getProductCatalog() {
        return [
            { "id": 1, "name": "BoxLang Runtime" },
            { "id": 2, "name": "CommandBox" }
        ];
    }
}
```

### URI to Class Name Conversion

The routing follows these conventions:

* `/products` → `Products.bx`
* `/home-savings` → `HomeSavings.bx`
* `/user-profile` → `UserProfile.bx`
* `/user_profile` → `UserProfile.bx`

Hyphens and underscores are converted to PascalCase. Subdirectories are not currently supported.

## Multiple Functions Header

The runtime also allows you to create other functions inside of your Lambda that can be targeted if your AWS Lambda is exposed as an URL. You will be able to target different functions in your `Lambda.bx` by using the following header when executing your lambda:

```bash
x-bx-function=methodName
```

This makes it incredibly flexible where you can respond to that incoming header in a different function than the one by convention.

## Lambda Modules

You can use any BoxLang module with the BoxLang Lambda runtime by installing them to the `src/resources/boxlang_modules` folder. All modules placed there during the build process will be packaged into your lambda deployment.

```bash
# Using CommandBox to install modules directly
box install id=bx-module directory=src/resources/boxlang_modules

# Or add them to box.json and install
cd src/resources && box install
```

## Local Development & Testing

The template provides comprehensive local development and testing capabilities:

### SAM CLI Integration

```bash
# Test your function locally with different event types
./gradlew runLocal          # Basic Lambda execution
./gradlew runLocalApi       # API Gateway event simulation
./gradlew runLocalLegacy    # Legacy API Gateway event

# Start a local HTTP server for API testing
./gradlew startSamServerBackground
./gradlew stopSamServer
```

### Sample Events

The template includes sample event files in `workbench/sampleEvents/`:

* `api.json` - API Gateway event
* `event.json` - Basic Lambda event
* `event-live.json` - Production-like event for testing

### Testing Framework

The Java integration tests simulate the complete Lambda lifecycle:

```java
// Example from LambdaRunnerTest.java
@Test
public void testLambdaExecution() {
    LambdaRunner runner = new LambdaRunner();
    String result = runner.handleRequest(sampleEvent, testContext);
    assertThat(result).contains("success");
}
```

## Deploy to AWS

You can deploy your lambda using the provided deployment scripts or GitHub Actions. The template includes a comprehensive deployment system with configuration management.

### Configuration-Based Deployment

The template uses a hierarchical configuration system:

1. **Base Configuration**: `workbench/config.env` - Default settings
2. **Local Overrides**: `workbench/config.local.env` - Your custom settings
3. **Environment Variables**: Final overrides

```bash
# Create your local configuration
cp workbench/config.env workbench/config.local.env

# Edit your settings
vim workbench/config.local.env
```

Example configuration:

```bash
# AWS Settings
AWS_LAMBDA_BUCKET=my-lambda-deployments
STACK_NAME=my-boxlang-app
FUNCTION_NAME=my-function
LAMBDA_MEMORY=512
LAMBDA_TIMEOUT=30
ENVIRONMENT=development
```

### Deployment Scripts

The template provides several deployment scripts:

```bash
# Check AWS credentials and configuration
./workbench/0-check-aws.sh

# Create S3 bucket for deployments
./workbench/1-create-bucket.sh

# Deploy your Lambda function
./workbench/2-deploy.sh

# Invoke your deployed function
./workbench/3-invoke.sh

# Clean up resources
./workbench/4-cleanup.sh
```

### GitHub Actions Deployment

Below is the enhanced GitHub Action that uses the new configuration system:

{% hint style="info" %}
The Lambda function will be created automatically via CloudFormation if it doesn't exist, or updated if it does.
{% endhint %}

```yaml
- name: Deploy BoxLang Lambda
  run: |
    ./workbench/2-deploy.sh
  env:
    AWS_REGION: ${{ secrets.AWS_REGION }}
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_PUBLISHER_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_PUBLISHER_KEY }}
    AWS_LAMBDA_BUCKET: ${{ secrets.AWS_LAMBDA_BUCKET }}
    ENVIRONMENT: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
```

### SAM Template Integration

The template includes a parameterized SAM template (`workbench/template.yml`) that:

* Creates the Lambda function with proper configuration
* Sets up IAM roles and permissions
* Configures environment variables
* Provides function outputs (name, ARN) for integration

### Required Configuration

The automated deployment requires storing your credentials in your repository's secrets or environment variables:

* `AWS_REGION` - The region to deploy to
* `AWS_PUBLISHER_KEY_ID` - The AWS access key
* `AWS_SECRET_PUBLISHER_KEY` - The AWS secret key
* `AWS_LAMBDA_BUCKET` - S3 bucket for deployment artifacts

### Environment-Based Deployments

The build process supports multiple environments based on Git branches:

* **Development Branch** → `staging` environment
* **Main/Master Branch** → `production` environment

The template automatically creates appropriately named functions:

* `{functionName}-staging` - For development/staging
* `{functionName}-production` - For production releases

{% hint style="success" %}
The `{functionName}` comes from your `FUNCTION_NAME` configuration setting.
{% endhint %}

<figure><img src="/files/42VUSY4tumjuQyEGQ4Nm" alt=""><figcaption></figcaption></figure>

Log in to the Lambda Console and click on `Create function` button.

<figure><img src="/files/CPsZjlcxP35xAPTokJti" alt=""><figcaption><p>AWS Lambda Console</p></figcaption></figure>

Now let's add the basic information about our deployment:

* Add a function name: `{projectName}-staging or production`
* Choose `Java 21` as your runtime
* Choose `x86_64` as your architecture

{% hint style="success" %}
TIP: If you choose ARM processors, you can save some money.
{% endhint %}

<figure><img src="/files/kdrCM0Z2wxK7ORegyDwS" alt=""><figcaption><p>Create a function</p></figcaption></figure>

Now, let's upload our test code. You can choose a zip/jar or s3 location. We will do a simple zip from our template:

<figure><img src="/files/bfpMugaqlaTBE6b7LrEa" alt=""><figcaption><p>Upload Test Code</p></figcaption></figure>

<figure><img src="/files/Ho3i7mW5mJWjz9v6itmM" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/aWvGIqffYu6THkF9EXQC" alt=""><figcaption><p>Code Uploaded</p></figcaption></figure>

Now important, let's choose the AWS Lambda Runtime Handler in the `Edit runtime settings`

<figure><img src="/files/e0j1oKFKYNoVbPP7uFvZ" alt=""><figcaption></figcaption></figure>

And make sure you use the following handler address: `ortus.boxlang.runtime.aws.LambdaRunner::handleRequest` This is inside the runtime to execute our `Lambda.bx` function.

{% hint style="danger" %}
Please note that the RAM you chose for your lambda determines your CPU as well. So make sure you increase the RAM accordingly. We have seen great results with 4GB+.
{% endhint %}

### Testing in AWS

Now click on the `Test` tab and an event name `MyTestEvent`. You can also add anything you like in the `Event JSON` to test the input of your lambda. Then click on `Test` and watch it do its magic. Now go have some good fun!

<figure><img src="/files/AadHRDEAct960iIKvEss" alt=""><figcaption></figcaption></figure>

## Runtime Source Code

The AWS Runtime source code can be found here: <https://github.com/ortus-boxlang/boxlang-aws-lambda>

### Latest Runtime Features

The BoxLang AWS Lambda runtime includes several recent enhancements:

* **Maven Dependency Management**: Automatic resolution of runtime dependencies
* **Class Compilation Caching**: Improved cold start performance through class caching
* **Connection Pooling**: Database connection pooling for better performance
* **Performance Metrics**: Detailed performance monitoring in debug mode
* **Enhanced Error Handling**: Better error messages and stack traces
* **Configuration Flexibility**: Hierarchical configuration system
* **SAM Integration**: Full AWS SAM support for local development

### Performance Best Practices

For optimal performance with the BoxLang AWS Lambda runtime:

1. **Enable Class Caching**: Use `trustedCache=true` in your `boxlang.json` for production
2. **Configure Connection Pooling**: Set `BOXLANG_LAMBDA_CONNECTION_POOL_SIZE` for database workloads
3. **Memory Allocation**: Allocate sufficient memory (2GB+ recommended) for better CPU performance
4. **Static Initialization**: Use static blocks for expensive one-time setup
5. **Early Returns**: Validate input early and return immediately on errors

We welcome any pull requests, testing, documentation contributions, and feedback.


# CommandBox

The defacto enterprise servlet deployment for BoxLang - Power your mission-critical applications with CommandBox

<figure><img src="/files/tOAsGuQepRpuhteZOIpz" alt=""><figcaption></figcaption></figure>

[CommandBox](https://commandbox.ortusbooks.com/) is a standalone, native tool for Windows, Mac, and Linux that provides a Command-Line Interface (CLI) for developer productivity, tool interaction, package management, embedded JEE server, application scaffolding, and sweet ASCII art. **CommandBox is the defacto enterprise servlet deployment platform for BoxLang**, providing production-ready capabilities for mission-critical applications.

CommandBox seamlessly integrates to work with any of [Ortus Solutions](http://www.ortussolutions.com/products) \*Box products, but it is also open to extensibility for any BoxLang or CFML project. We have created a specialized servlet runtime for CommandBox that makes it the premier choice for deploying enterprise BoxLang applications with high-traffic and mission-critical requirements.

## 🚀 Enterprise Features & BoxLang Subscriptions

CommandBox becomes even more powerful with [CommandBox PRO](https://www.ortussolutions.com/products/commandbox-pro), which is included with [BoxLang+ and BoxLang++ subscriptions](https://boxlang.io/plans). When you have a **BoxLang +/++ subscription**, you automatically get access to all CommandBox PRO enterprise features:

* **🏢 Multi-site Support** - Host multiple applications on a single CommandBox instance
* **🔐 Multi-SSL Support** - Advanced SSL certificate management and SNI support
* **⚙️ Operating System Service Manager** - Run CommandBox as a system service
* **🛡️ CAC (Common Access Card) Support** - Enterprise authentication integration
* **☕ JDK Management** - Simplified Java version management
* **📊 Advanced Monitoring & Metrics** - Production-ready observability tools
* **🔧 Professional Support** - Direct access to Ortus Solutions engineering team

## 🐳 Docker Container Support

CommandBox also provides official Docker containers for containerized deployments:

```bash
# Pull the official CommandBox Docker image
docker pull ortussolutions/commandbox

# Run a BoxLang server in Docker
docker run -d \
  -p 8080:8080 \
  -v /path/to/your/app:/app \
  ortussolutions/commandbox
```

For more Docker deployment options, visit the [CommandBox Docker Hub repository](https://hub.docker.com/r/ortussolutions/commandbox).

<figure><img src="/files/hJb4PkRCyyoma5cPoK4I" alt="" width="156"><figcaption></figcaption></figure>

{% hint style="info" %}
**BoxLang Subscribers**: If you have a BoxLang+ or BoxLang++ subscription, you automatically get access to all CommandBox PRO features. Learn more at <https://boxlang.io/plans>

For standalone CommandBox Pro: <https://www.ortussolutions.com/products/commandbox-pro>
{% endhint %}

You can find out more about getting started with CommandBox or CommandBox Pro in our [CommandBox documentation](https://commandbox.ortusbooks.com/getting-started-guide).

## 📦 Installation & Setup

### Install the BoxLang Module

Once installed, CommandBox needs (for the moment) the `commandbox-boxlang` module to start BoxLang servers. So let's go ahead and install it:

```bash
install commandbox-boxlang
```

This will add the right file types and handlers to CommandBox for BoxLang.

{% hint style="danger" %}
This will no longer be needed on CommandBox 6.1+
{% endhint %}

## 🚀 Start up a Server

Starting a BoxLang server with CommandBox is simple and powerful. Navigate to your application's webroot and run:

```bash
server start cfengine=boxlang javaVersion=openjdk21_jdk
```

### Additional Server Options

CommandBox provides extensive server configuration options for enterprise deployments:

```bash
# Start with specific JVM settings
server start cfengine=boxlang javaVersion=openjdk21_jdk --jvmArgs="-Xmx2g -Xms1g"

# Start on a specific port with SSL
server start cfengine=boxlang port=8443 SSL=true

# Start with debug mode enabled
server start cfengine=boxlang --debug

# Start in production mode with optimizations
server start cfengine=boxlang profile=production
```

Enjoy your enterprise-grade BoxLang server!

## 🏠 Server Home

Like any other CommandBox server, the servers will be stored in your setup's CommandBox Home. The `boxlang.json`, class folders, and modules will all be installed here.

## 📦 Installing BoxLang Modules

Just like with any server, you can also install modules into the BoxLang server:

```bash
# Install individual modules
install bx-mysql,bx-derby

# Install modules with specific versions
install bx-mail@1.0.0,bx-redis@latest

# Install from different sources
install bx-compat-cfml
install github:ortus-boxlang/bx-elasticsearch
```

That's it. CommandBox knows where to put them and manage them automatically.

## ⚙️ Server Configuration

### server.json

You can make your CommandBox BoxLang server portable and enterprise-ready with a comprehensive `server.json` file:

```json
{
    "name": "MyBoxLang-Server",

    "app": {
        // The BoxLang Engine
        "cfengine": "boxlang",
        // Portable Home if you want, or ignore it to place it under the
        // CommandBox Home
        "serverHomeDirectory": ".boxlang"
    },

    "openBrowser": true,

    "web": {
        "rewrites": {
            "enable": true
        },
        "SSL": {
            "enable": false,
            "port": 8443
        }
    },

    "jvm": {
        "heapSize": "2048m"
    },

    // Any Environment variables
    "env": {
        // "BOXLANG_DEBUG" : true
    },

    // Install these modules on installation
    "scripts": {
        "onServerInitialInstall": "install bx-mail,bx-mysql,bx-derby,bx-compat-cfml"
    }
}
```

### Advanced Enterprise Configuration

For production and enterprise deployments, you can leverage additional CommandBox features:

```json
{
    "name": "BoxLang-Production-Server",

    "app": {
        "cfengine": "boxlang",
        "serverHomeDirectory": "/opt/boxlang-server"
    },

    "web": {
        "host": "0.0.0.0",
        "webroot": "./webroot",
        "rewrites": {
            "enable": true
        },
        "SSL": {
            "enable": true,
            "port": 8443,
            "certFile": "/etc/ssl/certs/server.crt",
            "keyFile": "/etc/ssl/private/server.key"
        }
    },

    "jvm": {
        "heapSize": "4096m",
        "args": [
            "-XX:+UseG1GC",
            "-XX:MaxGCPauseMillis=200",
            "-Dfile.encoding=UTF-8"
        ]
    },

    "env": {
        "BOXLANG_ENVIRONMENT": "production",
        "BOXLANG_DEBUG": false
    },

    "scripts": {
        "onServerInitialInstall": "install bx-mail,bx-mysql,bx-redis,bx-elasticsearch",
        "onServerStart": "echo 'BoxLang Enterprise Server Starting...'",
        "onServerStop": "echo 'BoxLang Enterprise Server Stopping...'"
    }
}
```

## 🌍 Environment Variables

The servlet/CommandBox runtime uses the same [environment variables](/getting-started/running-boxlang#environment-variables) as the core OS runtime. You can find detailed information about all available environment variables here.

{% content-ref url="/pages/wY9sF68XIhOh54m1B1WJ" %}
[Running BoxLang](/getting-started/running-boxlang)
{% endcontent-ref %}

## 🔧 Development & Debugging

### Custom boxlang.json Configuration

You can use your own custom `boxlang.json` file to startup the engine by using the `app.engineConfigFile` setting in your `server.json`:

```json
{
    "name": "MyBoxLang-Server",

    "app": {
        // The BoxLang Engine
        "cfengine": "boxlang",
        // Portable Home if you want, or ignore it to place it under the
        // CommandBox Home
        "serverHomeDirectory": ".engine/boxlang",
        // Custom boxlang.json file
        "engineConfigFile": ".boxlang.json"
    },

    "openBrowser": true,

    "web": {
        "rewrites": {
            "enable": true
        }
    },

    // Any Environment variables
    "env": {
        // "BOXLANG_DEBUG" : true
    },

    // Install these modules on installation
    "scripts": {
        "onServerInitialInstall": "install bx-mail,bx-mysql,bx-compat-cfml"
    }
}
```

### Debug Mode

You can enable debug mode for your BoxLang server using several approaches:

#### `--debug` flag via the `server start` command

```bash
server start --debug
```

#### `env.BOXLANG_DEBUG` environment variable

Set `env.BOXLANG_DEBUG` in your `server.json` file:

```json
"env": {
   "BOXLANG_DEBUG": true
}
```

#### `BOXLANG_DEBUG` in a .env file

Set `BOXLANG_DEBUG=true` in a .env file:

```bash
BOXLANG_DEBUG=true
```

#### `.cfconfig.json` `debugMode` setting

Or set `debuggingEnabled` in your `.cfconfig.json` server configuration file:

```json
{
    "debuggingEnabled": true
}
```

#### Custom `boxlang.json` file

Use the `app.engineConfigFile` to seed a custom `boxlang.json` file into the engine and use the normal settings in the `boxlang.json`.

## 📚 Additional Resources

### Runtime Source Code

The CommandBox servlet runtime source code can be found here: <https://github.com/ortus-boxlang/boxlang-servlet>

We welcome any pull requests, testing, documentation contributions, and feedback!

### Docker Hub

Official CommandBox Docker images: <https://hub.docker.com/r/ortussolutions/commandbox>

### Enterprise Support

For enterprise deployments and professional support:

* **BoxLang+ Subscribers**: Included CommandBox PRO features and support
* **BoxLang++ Subscribers**: Priority support with SLA guarantees
* **Standalone CommandBox PRO**: Available at [ortussolutions.com](https://www.ortussolutions.com/products/commandbox-pro)

{% hint style="success" %}
**Ready for Production**: CommandBox with BoxLang provides enterprise-grade servlet deployment capabilities, making it the preferred choice for mission-critical applications requiring high availability, scalability, and professional support.
{% endhint %}


# Chromebooks

Learn how to code with BoxLang on your Chromebook using Linux development environment!

<figure><img src="/files/bJqV1biIsF6zyO4ZOoj3" alt=""><figcaption></figcaption></figure>

We love Chromebooks! This comprehensive guide will help you run and develop BoxLang applications on both Intel-based and ARM-based Chromebooks. We'll install all prerequisites, set up BoxLang, configure VS Code with the BoxLang extension, and create your first application.

{% embed url="<https://www.google.com/chromebook/>" %}

<figure><img src="/files/YzKmvtlu5UFubYBKS4fJ" alt=""><figcaption><p><a href="https://www.google.com/chromebook/">https://www.google.com/chromebook/</a></p></figcaption></figure>

## Requirements

* **Hardware**: 4GB RAM Chromebook minimum (8GB+ recommended for better performance)
* **Operating System**: Chrome OS with Linux development environment enabled
* **Java Runtime**: OpenJDK 21 or higher
* **Storage**: At least 2GB free space for development tools

### Enabling Linux Development Environment

Chromebooks provide excellent development capabilities through their built-in Linux development environment (based on Debian). This allows you to run a full Linux container alongside Chrome OS seamlessly.

**To enable Linux development:**

1. Open **Settings** > **Advanced** > **Developers**
2. Turn on **Linux development environment**
3. Follow the setup wizard to configure your container
4. Choose appropriate storage size (4GB minimum, 8GB+ recommended)

<figure><img src="/files/0SD2XAngE6nO1Ft14mrs" alt=""><figcaption><p>Enable Linux Development Environment</p></figcaption></figure>

{% hint style="info" %}
**Pro Tip**: The Linux environment runs in a secure container that's isolated from Chrome OS, providing a safe development space while maintaining system security.
{% endhint %}

## 📋 Table of Contents

* [Requirements](#requirements)
* [Accessing the Linux Terminal](#accessing-the-linux-terminal)
* [Installing Java](#installing-java)
* [Installing BoxLang](#installing-boxlang)
* [Installing VS Code](#installing-vs-code)
* [Creating Your First App](#creating-your-first-app)
* [Troubleshooting](#troubleshooting)
* [Best Practices](#best-practices)

## Accessing the Linux Terminal

You'll interact with the Linux development environment through the **Terminal** application, which provides full command-line access to your Debian container.

**To open the terminal:**

1. Press **Alt + Shift + T** (keyboard shortcut)
2. Or search for "Terminal" in the launcher
3. Or use the **Everything** button and search for "Terminal"

<figure><img src="/files/6BU6QCtrHj4zYaJHYXkr" alt=""><figcaption><p>Terminal Application</p></figcaption></figure>

Click on the **Penguin** tab to access your Linux environment:

<figure><img src="/files/5BNWehdUR5b8EsXs76QS" alt=""><figcaption><p>Linux Terminal Environment</p></figcaption></figure>

## Setting Up the Development Environment

{% stepper %}
{% step %}

### System Updates and Essential Tools

Start by updating your system and installing essential development tools:

```bash
# Update package lists and upgrade system
sudo apt update && sudo apt full-upgrade -y

# Install essential development tools
sudo apt install -y \
    curl \
    wget \
    git \
    zip \
    unzip \
    build-essential \
    software-properties-common \
    apt-transport-https \
    ca-certificates \
    gnome-keyring
```

{% endstep %}

{% step %}

### Installing Java 21

Modern Debian distributions now include OpenJDK 21. Try the simple installation first:

```bash
# Try the easy installation first
sudo apt install -y openjdk-21-jdk

# Verify installation
java -version
```

If OpenJDK 21 isn't available in your distribution's repositories, install it manually:

#### Manual Java Installation

If the package manager installation didn't work, install Java manually:

```bash
# Determine your architecture
ARCH=$(dpkg --print-architecture)
echo "Architecture: $ARCH"

# Download OpenJDK 21 based on architecture
if [ "$ARCH" = "amd64" ]; then
    # For x64/Intel Chromebooks
    wget https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_x64_linux_hotspot_21.0.4_7.tar.gz
    TAR_FILE="OpenJDK21U-jdk_x64_linux_hotspot_21.0.4_7.tar.gz"
    JDK_DIR="jdk-21.0.4+7"
elif [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then
    # For ARM Chromebooks
    wget https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.4_7.tar.gz
    TAR_FILE="OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.4_7.tar.gz"
    JDK_DIR="jdk-21.0.4+7"
else
    echo "Unsupported architecture: $ARCH"
    exit 1
fi

# Extract and install
tar -xzf $TAR_FILE
sudo mkdir -p /usr/lib/jvm
sudo mv $JDK_DIR /usr/lib/jvm/

# Set up environment variables
echo "export JAVA_HOME=/usr/lib/jvm/$JDK_DIR" >> ~/.bashrc
echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> ~/.bashrc

# Add to sudo PATH
echo "Defaults secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/$JDK_DIR/bin\"" | sudo tee /etc/sudoers.d/java

# Reload environment
source ~/.bashrc

# Verify installation
java -version
```

{% hint style="success" %}
**Modern Note**: Most current Debian-based distributions now include OpenJDK 21 in their repositories, making the simple `apt install` method the preferred approach.
{% endhint %}
{% endstep %}

{% step %}

### Installing BoxLang

BoxLang installation is straightforward with the official installer script:

```bash
# Run the BoxLang installer
sudo /bin/bash -c "$(curl -fsSL https://downloads.ortussolutions.com/ortussolutions/boxlang/install-boxlang.sh)"
```

**Verify the installation:**

```bash
# Check BoxLang version
boxlang --version

# Test the REPL
boxlang
```

<figure><img src="/files/QOyeHHrEPKQXVd3iMIOs" alt=""><figcaption><p>BoxLang REPL on Chromebook</p></figcaption></figure>

The REPL (Read-Eval-Print Loop) opens, allowing you to start coding immediately, run BoxLang files, start web servers, and much more!
{% endstep %}

{% step %}

## Setting Up VS Code with BoxLang

{% endstep %}

{% step %}

### Installing Visual Studio Code

VS Code provides excellent BoxLang development support with syntax highlighting, debugging, and integrated development features.

**Download and install VS Code:**

1. Visit the [VS Code download page](https://code.visualstudio.com/download)
2. Choose the **Linux** version and select the **.deb** package appropriate for your architecture:
   * **Intel/AMD64**: Download the x64 .deb package
   * **ARM**: Download the ARM64 .deb package

{% hint style="info" %}
**Architecture Check**: If unsure about your Chromebook's processor type, run `dpkg --print-architecture` in the terminal to verify.
{% endhint %}

**Install the downloaded package:**

```bash
# Navigate to Downloads folder
cd ~/Downloads

# Install VS Code (replace with your downloaded filename)
sudo dpkg -i code_*.deb

# Fix any missing dependencies
sudo apt-get install -f
```

<figure><img src="/files/0VqH9ee1A4xkrniKwnRN" alt=""><figcaption><p>VS Code Installation</p></figcaption></figure>
{% endstep %}

{% step %}

### Installing the BoxLang Extension

1. **Open VS Code** from your applications menu
2. **Access Extensions**: Click the Extensions icon (⬜) or press `Ctrl+Shift+X`
3. **Search for BoxLang**: Type "BoxLang" in the search box
4. **Install the extension**: Click "Install" on the official BoxLang extension by Ortus Solutions

<figure><img src="/files/gQlSuw7QTKvOaZICwNT0" alt=""><figcaption><p>VS Code Extensions Marketplace</p></figcaption></figure>

<figure><img src="/files/QoirMTBv0pAQmHgZa3Gp" alt=""><figcaption><p>BoxLang Extension Installation</p></figcaption></figure>

The BoxLang extension provides:

* **Syntax Highlighting**: Full BoxLang syntax support
* **Code Completion**: Intelligent IntelliSense for BoxLang
* **Debugging Support**: Set breakpoints and debug your applications
* **Integrated Terminal**: Run BoxLang commands directly
* **Web Server Integration**: Start and manage BoxLang web servers
* **REPL Integration**: Interactive BoxLang development
  {% endstep %}

{% step %}

## Creating Your First BoxLang Application

{% endstep %}

{% step %}

### Your First BoxLang Class

Let's create your first BoxLang application to test everything is working correctly.

**Create a new file:**

1. **Create a project folder**:

   ```bash
   mkdir ~/boxlang-projects
   cd ~/boxlang-projects
   ```
2. **Open VS Code in this folder**:

   ```bash
   code .
   ```
3. **Create a new file** called `Hello.bx`

**Add the following code:**

```javascript
class {

    function main( args = [] ) {
        println( "🚀 Hello from Chromebook and BoxLang! " );
        println( "📅 Current time: #now()#" );
        println( "💻 System architecture: #createObject( 'java', 'java.lang.System' ).getProperty( 'os.arch' )#" );

        return "BoxLang is running perfectly on your Chromebook! 🎉";
    }

}
```

<figure><img src="/files/sXX1Qsz1x3y9HErv0ce7" alt=""><figcaption><p>BoxLang Hello World Class</p></figcaption></figure>

**Run your application:**

* **Method 1**: Right-click in the editor and select **"BoxLang: Run File"**
* **Method 2**: Use the command palette (`Ctrl+Shift+P`) and search for "BoxLang: Run File"
* **Method 3**: Use the terminal: `boxlang Hello.bx`

**Expected output:**

```
🚀 Hello from Chromebook and BoxLang!
📅 Current time: {ts '2024-05-23 18:27:33'}
💻 System architecture: aarch64
BoxLang is running perfectly on your Chromebook! 🎉
```

{% endstep %}

{% step %}

### Creating a Web Application

Now let's create a web application using BoxLang's templating system.

**Create a template file** called `index.bxm`:

```xml
<bx:output>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BoxLang on Chromebook</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 2rem;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            min-height: 100vh;
        }
        .container {
            background: rgba(255,255,255,0.1);
            padding: 2rem;
            border-radius: 10px;
            backdrop-filter: blur(10px);
        }
        h1 { color: #fff; text-align: center; }
        .info { background: rgba(255,255,255,0.1); padding: 1rem; margin: 1rem 0; border-radius: 5px; }
    </style>
</head>
<body>
    <div class="container">
        <h1>🚀 BoxLang Web Server on Chromebook!</h1>

        <div class="info">
            <h3>📅 Server Information</h3>
            <p><strong>Current Time:</strong> #now()#</p>
            <p><strong>BoxLang Version:</strong> #server.boxlang.version#</p>
            <p><strong>Server Host:</strong> #cgi.server_name#:#cgi.server_port#</p>
        </div>

        <div class="info">
            <h3>💻 System Details</h3>
            <p><strong>OS:</strong> #createObject( 'java', 'java.lang.System' ).getProperty( 'os.name' )#</p>
            <p><strong>Architecture:</strong> #createObject( 'java', 'java.lang.System' ).getProperty( 'os.arch' )#</p>
            <p><strong>Java Version:</strong> #createObject( 'java', 'java.lang.System' ).getProperty( 'java.version' )#</p>
        </div>

        <div class="info">
            <h3>🎯 Next Steps</h3>
            <ul>
                <li>Explore the <a href="https://boxlang.ortusbooks.com/" target="_blank">BoxLang Documentation</a></li>
                <li>Try building REST APIs with BoxLang</li>
                <li>Create dynamic web applications</li>
                <li>Integrate with databases and external services</li>
            </ul>
        </div>
    </div>
</body>
</html>
</bx:output>
```

{% endstep %}

{% step %}

### Starting the BoxLang Web Server

**Start the integrated web server:**

1. **Open Command Palette**: Press `Ctrl+Shift+P`
2. **Search for BoxLang**: Type "BoxLang" to see available commands
3. **Select "BoxLang: Start Web Server"**

<figure><img src="/files/lJBw9MuO0AHZDaEq0eUL" alt=""><figcaption><p>BoxLang VS Code Commands</p></figcaption></figure>

**You'll see output in the debug console:**

```
🚀 Starting BoxLang Server...
📁 Web Root: /home/username/boxlang-projects
🌐 Host: localhost
🔌 Port: 8080
🐛 Debug: false
⚙️  Config Path: null
🏠 Server Home: null
🚀 Starting BoxLang Runtime...
✅ Runtime Started in 2043ms
✅ BoxLang MiniServer started in 2135ms
🌐 BoxLang MiniServer available at: http://localhost:8080
Press Ctrl+C to stop the server.
```

**Access your web application:**

VS Code will automatically open your browser, or you can manually navigate to `http://localhost:8080`

<figure><img src="/files/nudGnBJeyos2PrdBWUy5" alt=""><figcaption><p>BoxLang Web Application Running</p></figcaption></figure>

Congratulations! 🎉 You've successfully created and deployed your first BoxLang web application on a Chromebook!
{% endstep %}
{% endstepper %}

## Next Steps and Development Tips

### Performance Optimization for Chromebooks

**Memory Management:**

* Close unused browser tabs when developing
* Use `boxlang --help` to see memory configuration options
* Monitor system resources in Chrome OS Task Manager

**Development Best Practices:**

* Use the integrated VS Code terminal for BoxLang commands
* Leverage VS Code's built-in Git support for version control
* Take advantage of VS Code's IntelliSense for BoxLang development

### Useful BoxLang Commands for Development

```bash
# Check BoxLang version and help
boxlang --version
boxlang --help

# Run BoxLang files directly
boxlang myScript.bx

# Start REPL for interactive development
boxlang

# Start web server with custom port
boxlang --server-port 9090

# Start server with debug mode
boxlang --server-debug true
```

### Additional Resources

* 📚 [**BoxLang Documentation**](https://boxlang.ortusbooks.com/) - Complete language reference
* 🌐 [**BoxLang GitHub**](https://github.com/ortus-boxlang/boxlang) - Source code and issues
* 💬 [**Community Discord**](https://discord.gg/ortussolutions) - Get help from the community
* 🎓 [**BoxLang Examples**](https://github.com/ortus-boxlang/boxlang-examples) - Sample applications and tutorials

### Troubleshooting Common Issues

**Java-related issues:**

```bash
# Verify Java installation
java -version
echo $JAVA_HOME

# If Java isn't found, source your profile
source ~/.bashrc
```

**BoxLang server issues:**

```bash
# Check if port is in use
netstat -tulpn | grep :8080

# Stop any running BoxLang processes
pkill -f boxlang
```

**VS Code extension issues:**

* Restart VS Code if BoxLang commands aren't working
* Check the Output panel for BoxLang extension logs
* Ensure the BoxLang binary is in your PATH

## Conclusion

You've successfully set up a complete BoxLang development environment on your Chromebook! This setup provides:

✅ **Full Java 21 development environment** ✅ **BoxLang runtime with REPL support** ✅ **VS Code with BoxLang extension** ✅ **Integrated web server capabilities** ✅ **Modern development workflow**

Your Chromebook is now ready for professional BoxLang development. Whether you're building web applications, APIs, or exploring the language features, you have everything needed to create amazing BoxLang applications.

{% hint style="success" %}
**Pro Tip**: This entire guide was written and tested on a Lenovo Duet 5 Chromebook, proving that Chromebooks are excellent development machines for BoxLang! 💻✨
{% endhint %}

Happy coding with BoxLang on your Chromebook! 🚀


# CLI Scripting

The core runtime allows you to build CLI scripting applications

<figure><img src="/files/0C66vcFOgKap5rrnRw2V" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Looking for a real BoxLang CLI app to study and practice with? Check out [BoxLings](https://github.com/ortus-boxlang/boxlings), an interactive learning tool built in BoxLang.
{% endhint %}

BoxLang is a modern, dynamic scripting language built for more than just simple automation—it empowers you to create full-fledged, high-performance CLI applications with ease. Designed to run seamlessly on the JVM, BoxLang provides powerful scripting capabilities, a rich standard library, and first-class support for modular development.

Whether you're automating repetitive tasks, building interactive command-line tools, or developing complex CLI-driven workflows, BoxLang offers the flexibility, expressiveness, and performance you need. With intuitive syntax, robust error handling, and seamless integration with Java and other JVM-based technologies, BoxLang makes CLI scripting more efficient and enjoyable.

## 📋 Table of Contents

* [BoxLang CLI Entry Points & Conventions](#boxlang-cli-entry-points--conventions)
* [Script Files](#execute-a-file-9)
* [Other Scopes](#other-scopes)
* [Executing Classes](#executing-classes)
* [Executing Scripts / Templates](#executing-scripts--templates)
* [SheBang Scripts](#shebang-scripts)
* [BoxLang CLI Options and Flags](#boxlang-cli-options-and-flags)
* [Action Commands](#action-commands)
* [Runtime Mode Detection](#runtime-mode-detection)
* [Inline Code Execution](#inline-code-execution)
* [Scheduler Files](#scheduler-files)
* [REPL Mode](#repl-mode)
* [CLI Built-In Functions](#cli-built-in-functions)
* [Parsed Arguments](#parsed-arguments)
* [Reading Input](#reading-input)
* [Producing Output](#producing-output)
* [Piping code](#piping-code-11)
* [Module CLI Apps](#module-cli-apps)
* [Embedding Modules in a CLI App](#embedding-modules-in-a-cli-app)
* [Additional Resources and Examples](#additional-resources-and-examples)

## BoxLang CLI Entry Points & Conventions

BoxLang supports multiple ways to execute code from the command line, making it a flexible tool for scripting, automation, and app development. Here’s a summary of the main entry points and conventions:

### File Execution

You can execute any supported file type directly:

* `*.bx` — BoxLang class with a `main()` method
* `*.bxs` — BoxLang script
* `*.bxm` — BoxLang template
* `*.cfs` / `*.cfm` — CFML script/template (requires `bx-compat-cfml` module)
* `*.sh` — Shebang script (with `#!/usr/bin/env boxlang`)

BoxLang will automatically detect and run the correct entry point, including shebang scripts and classes with a `main()` method.

## Script Files <a href="#execute-a-file-9" id="execute-a-file-9"></a>

With BoxLang, you can execute a few types of files right from any OS CLI by adding them as the second argument to our `boxlang`binary:

<table><thead><tr><th width="100">File</th><th width="100">OS<select><option value="3cJlLiaj5Xge" label="Windows" color="blue"></option><option value="HW3jPH5fCWIy" label="Mac + *Nix" color="blue"></option><option value="6Tg36nA4Yujw" label="All" color="blue"></option></select></th><th>Hint</th></tr></thead><tbody><tr><td>*.bx</td><td><span data-option="6Tg36nA4Yujw">All</span></td><td>BoxLang classes with a <code>main()</code>method</td></tr><tr><td>*.bxs</td><td><span data-option="6Tg36nA4Yujw">All</span></td><td>BoxLang scripts</td></tr><tr><td>*.bxm</td><td><span data-option="6Tg36nA4Yujw">All</span></td><td>BoxLang Templating Language</td></tr><tr><td>*.cfs</td><td><span data-option="6Tg36nA4Yujw">All</span></td><td>CFML scripts (If using the <code>bx-compat-cfml</code>module)</td></tr><tr><td>*.cfm</td><td><span data-option="6Tg36nA4Yujw">All</span></td><td>CFML templates (If using the <code>bx-compat-cfml</code>module)</td></tr><tr><td>*.sh</td><td><span data-option="HW3jPH5fCWIy">Mac + *Nix</span></td><td>Shebang scripts using <code>boxlang</code>as the environment</td></tr></tbody></table>

{% hint style="danger" %}
Please note that you will need the `bx-compat-cfml`module if you want to execute CFML scripts
{% endhint %}

Here are some examples of executing the files. Just pass in the file by relative or absolute path location.

{% tabs %}
{% tab title="Mac / \*Unix" %}

```bash
boxlang task.bx
boxlang myscript.bxs
boxlang mytemplate.bxm

boxlang /full/path/to/test.bxs
boxlang /full/path/to/Task.bx
```

{% endtab %}

{% tab title="Windows" %}

```powershell
boxlang.bat task.bx
boxlang.bat myscript.bxs
boxlang.bat mytemplate.bxm
```

{% endtab %}

{% tab title="Jar" %}

```ruby
java -jar boxlang-1.0.0.jar task.bx
java -jar boxlang-1.0.0.jar /full/path/to/test.bxs
```

{% endtab %}
{% endtabs %}

## Other Scopes

Please note that you have access to other persistent scopes when building CLI applications:

* `application`- This scope lives as long as your application lives as well, but it is technically attached to an `Application.bx`file that activates framework capabilities for your application.
* `request`- A scope that matches a specific request for your application. We also get one per CLI app since there is no concept of sessions or user state. There is always only one request. It would be up to you to create a session-like mechanism if you need to persist state across multiple executions.
* `server` - A scope that lives as long as the CLI app is running. This is useful for storing global state or configuration that should persist across multiple requests or executions.

For CLI applications, we recommend you use the `server`or `request` scope for singleton persistence. Also note that you can use all the [caches](/getting-started/configuration/caches) as well for persistence. You can use `application`scope if you have an `Application.bx.`

## Executing Classes

BoxLang allows you to execute any `*.bx`class as long as it has a method called `main()`by convention. All the arguments passed into the file execution will be collected and passed into the function via the `args`argument.

{% code title="task.bx" %}

```java
class {

    function main( args = [ ] ) {
        println( "Hola from my task! #now()#" );
        println( "The passed args are: " );
        println( args );
    }

}
```

{% endcode %}

The `args`argument is an array and it will contain all the arguments passed to the execution of the class.

```bash
boxlang task.bx hola --many options=test
```

If you execute this function above, the output will be:

```bash
Hola from my task! { ts '2025-02-11 22:15:44' }
The passed args are:
[
  hola,
  --many,
  options=test
]
```

Class executions are a great way to build tasks that have a deterministic approach to execution. We parse the arguments for you, and you can focus on building your task.

## Executing Scripts / Templates

In addition to executing classes, you can execute `*.bxs`scripts that can do your bidding. The difference is that this is a flat source code script that executes from the top down. It can contain functions, scope usage, imports, and create any class.

{% code title="hello.bxs" %}

```groovy
message = "Hola from my task! #now()#";
println( message );
println( "The passed args are: " );
println( CLIGetArgs( ) );
```

{% endcode %}

Then, if we execute it, we can see this output:

```bash
╰─ boxlang hello.bxs hola luis=majano --test

Hola from my task! { ts '2025-02-11 22:29:44' }
The passed args are:
{
  positionals : [
      hola,
    luis=majano
  ],
  options : {
    test : true
  }
}
```

What do you see that's different? We don't have the incoming arguments as an argument since it's a script. However, we can use the `CLIGetArgs()`BIF, and it will give you a structure of two keys:

* `positionals`- An array of positional values passed to the script
* `options`- Name value pairs detected as options

{% hint style="info" %}
You can also get the arguments via the `server.cli.parsed`variable, which already contains this structure.
{% endhint %}

```groovy
message = "Hola from my task! #now()#";
println( message );
println( "The passed args are: " );
println( server.cli.parsed );
```

Here is the output:

```bash
╰─ boxlang hello.bxs hola luis=majano --test

Hola from my task! { ts '2025-02-11 22:29:44' }
The passed args are:
{
  positionals : [
      hola,
    luis=majano
  ],
  options : {
    test : true
  }
}
```

{% hint style="warning" %}
Please note that executing templates is the same as scripts, but your template uses templating language instead, which can be helpful if you produce some markup (HTML, Markdown, etc.)
{% endhint %}

## SheBang Scripts

SheBang scripts are text files containing a sequence of commands for a computer operating system. The term "shebang" refers to the `#!` characters at the beginning of the script, which specify the interpreter that should be used to execute the script. These scripts are commonly used in Unix-like operating systems to automate tasks. You can run scripts directly from the command line using a shebang line without explicitly invoking the interpreter. BoxLang supports these scripts, so the OS sees them as just pure shell scripts, but you are coding in BoxLang scripting.

{% hint style="success" %}
A SheBang script is just basically a `*.bxs`script.
{% endhint %}

{% code title="hola.sh" %}

```bash
#!/usr/bin/env boxlang

println( "Hello World! #now()#" );
println( CLIGetArgs( ) );
```

{% endcode %}

As you can see from the sample above, the first line is what makes it a SheBang script the operating system can use. It passes it to the `boxlang`binary for interpretation. Also, note that you can pass arguments to these scripts like any other script and the `CLIGetArgs()`or the `server.cli.parsed` variables will be there for you to use.

```bash
# Execute the script
./hola.sh

# Execute it with a name argument and a simple option
./hola.sh --name=luis -d
```

## BoxLang CLI Options and Flags

BoxLang provides a comprehensive set of CLI options and flags for various development and execution scenarios. All BoxLang-specific options are prefixed with `--bx-` to avoid conflicts with other tools.

### Global Options

| Option               | Description                                                                       |
| -------------------- | --------------------------------------------------------------------------------- |
| `-h, --help`         | Show help message and exit                                                        |
| `--version`          | Show version information and exit                                                 |
| `--bx-debug`         | Enable debug mode with timing information                                         |
| `--bx-config <PATH>` | Use custom BoxLang configuration file                                             |
| `--bx-home <PATH>`   | Set BoxLang runtime home directory                                                |
| `--bx-code <CODE>`   | Execute inline BoxLang code directly                                              |
| `--bx-printAST`      | Print Abstract Syntax Tree (JSON) for a file, inline code (`--bx-code`), or stdin |
| `--bx-transpile`     | Transpile BoxLang code to Java                                                    |

### Environment Variables

You can also control BoxLang behavior using environment variables:

| Environment Variable               | Description                      |
| ---------------------------------- | -------------------------------- |
| `BOXLANG_DEBUG=true`               | Enable debug mode                |
| `BOXLANG_CONFIG=/path/config.json` | Override configuration file path |
| `BOXLANG_HOME=/path/to/home`       | Set runtime home directory       |
| `BOXLANG_TRANSPILE=true`           | Enable transpile mode            |
| `BOXLANG_PRINTAST=true`            | Enable AST printing              |

### `.env` Files

The BoxLang CLI automatically loads environment variables from two `.env` files on every startup, in this order:

| File         | Scope                                                            | Loaded When  |
| ------------ | ---------------------------------------------------------------- | ------------ |
| `~/.box.env` | User-level — applies to every CLI invocation for your account    | Always       |
| `.env`       | Project-level — located in the directory where you run `boxlang` | When present |

Project-level values take precedence over user-level values when the same key appears in both files.

```bash
# ~/.box.env  — personal defaults that follow you everywhere
DB_HOST=localhost
DB_PORT=5432
OPENAI_API_KEY=sk-...
```

```bash
# .env  — project-specific overrides (keep this next to your scripts)
DB_HOST=staging.example.com
APP_ENV=staging
```

All variables loaded from either file are accessible via `getSystemSetting()`:

```js
// Works for both user-level (~/.box.env) and project-level (.env) values
dbHost = getSystemSetting( "DB_HOST", "localhost" )
dbPort = getSystemSetting( "DB_PORT", 5432 )
apiKey = getSystemSetting( "OPENAI_API_KEY" )
```

{% hint style="info" %}
The `.env` format is `KEY=VALUE`, one per line. Lines starting with `#` are comments. Quoting values is optional. These files are loaded as Java system properties, so use `getSystemSetting()` rather than `server.system.environment` to access them portably.
{% endhint %}

{% hint style="warning" %}
Never commit `~/.box.env` or a project `.env` containing real secrets to version control. Add `.env` to your `.gitignore`.
{% endhint %}

### Examples of CLI Options

```bash
# Execute with debug mode enabled
boxlang --bx-debug myapp.bx

# Use custom configuration file
boxlang --bx-config ./custom.json myapp.bx

# Execute inline code
boxlang --bx-code "println( 'Hello BoxLang!' )"

# Print AST for inline code
boxlang --bx-printAST --bx-code "x = 1 + 2"

# Print AST for a file
boxlang --bx-printAST /path/to/MyClass.bx

# Pipe source code via stdin
echo 'result = 1 + 2' | boxlang --bx-printAST

# Integrate with build tools or editors
cat MyComponent.bx | boxlang --bx-printAST | jq '.body[0]'

# Combined options
boxlang --bx-debug --bx-config ./custom.json myapp.bx
```

## Action Commands

BoxLang includes several powerful action commands for development workflows:

### Compile Command

Pre-compile BoxLang templates to class files for improved performance:

```bash
# Get help for compile command
boxlang compile --help

# Compile source directory to target
boxlang compile --source ./src --target ./compiled
```

### CF Transpile Command

Transpile ColdFusion code to BoxLang syntax:

```bash
# Get help for cftranspile command
boxlang cftranspile --help

# Transpile legacy CF code to BoxLang
boxlang cftranspile --source ./legacy --target ./modern
```

### Formatter Command

Format BoxLang and CFML code, or enforce formatting in CI with check mode:

```bash
# Get help for format command
boxlang format --help

# Format project files in place
boxlang format --input ./

# Lint-style enforcement for CI
boxlang format --check --input ./
```

For full formatter configuration, migration guidance from cfformat, and IDE auto-format setup, see [BoxLang Formatter](/getting-started/ide-tooling/boxlang-formatter).

### Feature Audit Command

Audit your code for BoxLang feature compatibility:

```bash
# Get help for featureaudit command
boxlang featureaudit --help

# Audit code and generate report
boxlang featureaudit --source ./myapp --output report.json
```

## Runtime Mode Detection

BoxLang provides several ways to detect the runtime execution context:

### Server Scope Information

The `server` scope contains detailed information about the runtime environment:

```javascript
// Check if running in CLI mode
if ( server.boxlang.cliMode ) {
    println( "Running in CLI mode" );
}

// Check if running in web (servlet/MiniServer) mode — since 1.14.0
if ( server.boxlang.webMode ) {
    println( "Running in web mode" );
}

// Check if running from JAR
if ( server.boxlang.jarMode ) {
    println( "Running in JAR mode" );
}

// Get runtime home directory
println( "Runtime home: " & server.boxlang.runtimeHome );
```

### CLI-Specific Information

When running in CLI mode, additional CLI-specific information is available:

```javascript
// Access CLI execution details
println( "Execution path: " & server.cli.executionPath );
println( "Command: " & server.cli.command );
println( "Raw args: " & server.cli.args.toString( ) );
println( "Parsed args: " & server.cli.parsed.toString( ) );
```

## Inline Code Execution

You can execute BoxLang code directly from the CLI using the `--bx-code` flag:

```bash
boxlang --bx-code "println( 'Hello from BoxLang!' )"
```

## Scheduler Files

You can run BoxLang scheduler files using the `schedule` action command. The file must be a `.bx` component with scheduler definitions. The scheduler will run continuously until you press `Ctrl+C`.

```bash
boxlang schedule ./schedulers/MainScheduler.bx
```

{% hint style="info" %}
For more on schedulers, see the [Scheduler documentation](/boxlang-framework/asynchronous-programming/scheduled-tasks).
{% endhint %}

## REPL Mode

When no arguments are provided, BoxLang starts in **REPL mode** (Read-Eval-Print-Loop):

* Interactive environment for testing and development
* Type expressions and see results immediately
* Supports multi-line expressions and complex code
* Press `Ctrl+C` to exit REPL mode

```bash
# Start REPL mode
boxlang

# You'll see the REPL prompt
BoxLang> println( "Hello from REPL!" )
Hello from REPL!
BoxLang>
```

## CLI Built-In Functions

BoxLang also gives you several built-in functions for interacting with the CLI:

* `CLIClear( ):void` - Clears the console
* `CLIGetArgs( ):struct` - Return a structure of the parsed incoming arguments
* `CLIRead( [ prompt ] ):any`- Read input from the CLI and return the value
* `CLIExit( [ exitCode=0 ] )`- Do a `System.exit( )`with the passed-in exit code

{% hint style="warning" %}
Please note that you have a wealth of built-in functions and components that you can use to build your scripts.
{% endhint %}

## Parsed Arguments

BoxLang automatically parses incoming arguments into a structured format when using the `CLIGetArgs( )` BIF or by accessing the `server.cli.parsed` variable.

The parsed structure contains:

* `options` - A structure of the options (name-value pairs) used to invoke the script
* `positionals` - An array of the positional arguments used to invoke the script

### CLI Argument Formats

BoxLang supports standard CLI argument formats:

| Format             | Description                            | Example                   |
| ------------------ | -------------------------------------- | ------------------------- |
| `--option`         | Boolean option set to `true`           | `--debug`                 |
| `--option=value`   | Option with a value                    | `--config=myfile.json`    |
| `--option="value"` | Option with quoted value               | `--message="Hello World"` |
| `--option='value'` | Option with single quoted value        | `--message='Hello World'` |
| `-o=value`         | Shorthand option with value            | `-c=config.json`          |
| `-o`               | Shorthand boolean option set to `true` | `-v`                      |
| `--!option`        | Negation option set to `false`         | `--!verbose`              |
| `--no-{option}`    | Negation option set to `false`         | `--no-debug`              |

### Multi-Character Shorthand Options

You can combine multiple single-character options:

```bash
# This creates: a=true, b=true, c=true
boxlang myscript.bxs -abc
```

### Parsing Examples

For the following CLI command:

```bash
boxlang myscript.bxs --debug --!verbose --config=prod.json -o='/path/to/file' -v my/path/template
```

The parsed structure will be:

```json
{
  "options": {
    "debug": true,
    "verbose": false,
    "config": "prod.json",
    "o": "/path/to/file",
    "v": true
  },
  "positionals": [ "my/path/template" ]
}
```

### Accessing Parsed Arguments

```javascript
// In a script file (.bxs)
var cliArgs = CLIGetArgs( );
// or
var cliArgs = server.cli.parsed;

// Check for options
if ( cliArgs.options.debug ) {
    println( "Debug mode enabled" );
}

// Process positional arguments
cliArgs.positionals.each( function( arg ) {
    println( "Processing: " & arg );
} );
```

### Advanced CLI Information

The `server.cli` structure provides comprehensive CLI context:

```javascript
// Full CLI context information
var cliInfo = server.cli;

println( "Execution Path: " & cliInfo.executionPath );
println( "Full Command: " & cliInfo.command );
println( "Raw Arguments: " & cliInfo.args.toString( ) );
println( "Parsed Options: " & cliInfo.parsed.options.toString( ) );
println( "Positional Args: " & cliInfo.parsed.positionals.toString( ) );
```

### Ground Rules for CLI Arguments

* Options are prefixed with `--` (long form) or `-` (short form)
* Shorthand options can be combined (e.g., `-abc` = `-a -b -c`)
* Options can be negated with `--!` or `--no-` prefix
* Values can be assigned with `=` and optionally quoted
* Repeated options will override previous values
* Everything after options are treated as positional arguments

## Reading Input

You can easily read input from users by using our handy `CLIRead( )`bif. You can also pass in a `prompt`as part of the method call.

```groovy
var exit = cliRead( "Do you want to continue? (Y/N)" ).trueFalseFormat( );
if ( exit ) {
  cliExit( );
}
```

## Producing Output

As you navigate all the built-in functions and capabilities of BoxLang, let's learn how to produce output to the system console.

* `printLn( )` - Print with a line break to System out
* `print( )` - Print with no line break to System out
* `writeOutput( ), echo( )` - Writes to the output buffer (Each runtime decides what its buffer is. The CLI is the system output, the Web is the HTML response buffer, etc)
* `writeDump( )`- Takes any incoming output and will serialize to a nice string output representation. This will also do complex objects deeply.

```groovy
println( "Time is #now()#" );
```

I get the output:

```bash
╰─ boxlang test.bxs
Time is { ts '2024-05-22 22:09:56' }
```

Hooray! You have executed your first script using BoxLang. Now let's build a class with a `main( args=[ ] )` convention. This is similar to Java or Groovy.

```java
class {

        function main( args=[ ] ) {

               println( "Task called with " & arguments.toString( ) );

                writedump( args );

        }

}
```

You can now call it with zero or more arguments!

```bash
╰─ boxlang Task.bx
Task called with { ARGS=[ ] }

╰─ boxlang Task.bx boxlang rocks
Task called with { ARGS=[ boxlang, rocks ] }
```

## Piping code <a href="#piping-code-11" id="piping-code-11"></a>

You can also pipe statements into the BoxLang binary for execution as well. This assumes script, not tags.

```bash
echo "2+2" | java -jar boxlang-1.0.0.jar
echo "2+2" | boxlang
```

or

```bash
# on *nix
cat test.cfs | java -jar boxlang-1.0.0.jar
cat test.cfs | boxlang

# on Windows
type test.cfs | java -jar boxlang-1.0.0.jar
type test.cfs | boxlang.bat
```

## Module CLI Apps

BoxLang allows you to build CLI applications as modules, making it easy to package, share, and execute reusable command-line tools. To create a module CLI app, simply add a `main( args )` method to your module's `ModuleConfig.bx` file.

When you want to execute a module as a CLI app, use the following convention:

* `module:{name}` - This will execute the module's `ModuleConfig.main( args )` method, passing any CLI arguments to it.

For example, if you have a module named `mytools`, you can run its CLI entry point like this:

```bash
boxlang module:mytools arg1 --option=value
```

This will invoke the `main( args )` method in `ModuleConfig.bx` of the `mytools` module, with all CLI arguments available in the `args` array.

### Example: ModuleConfig.bx

```java
class {

    function main( args = [ ] ) {
        println( "Module CLI called with args:" );
        writedump( args );
        // Your CLI logic here
    }

}
```

This approach lets you build modular CLI utilities that can be distributed and executed just like standalone scripts or classes. You can leverage all BoxLang features, scopes, and built-in functions inside your module CLI apps.

{% hint style="info" %}
For more on modules and conventions, see the [BoxLang Modules documentation](/boxlang-framework/modularity).
{% endhint %}

## Embedding Modules in a CLI App

BoxLang also allows you to **embed modules inside your CLI application** for distribution and local usage. This is different from creating a CLI app that executes a module's `main()` method. Embedding modules means your CLI app can include and use additional BoxLang modules as dependencies, making your CLI tool more powerful and modular.

To embed modules, use the `boxlang_modules` folder convention in your CLI app directory. You can install modules locally into this folder using the `install-bx-module` installer script with the `--local` flag:

```bash
install-bx-module bx-pdf bx-image --local
```

When your CLI app runs, BoxLang will check the `boxlang_modules` folder first for available modules, then fall back to the OS home modules. This allows you to package all required modules with your CLI app for easy distribution and predictable behavior.

**Example directory structure:**

```
mycliapp/
  myscript.bxs
  boxlang_modules/
    bx-pdf/
    bx-image/
```

Your CLI scripts and classes can then use any embedded modules as if they were installed globally.

{% hint style="info" %}
For more on embedding and using modules, see the [BoxLang Modules documentation](/boxlang-framework/modularity).
{% endhint %}

## Additional Resources and Examples

### Modern Development Workflow

BoxLang's CLI capabilities make it ideal for modern development workflows:

```javascript
// example-workflow.bx
class {

    function main( args = [ ] ) {
        var cliArgs = CLIGetArgs( );

        // Environment detection
        var isDev = cliArgs.options.env == "development";
        var isDebug = cliArgs.options.debug ?: false;

        if ( isDebug ) {
            println( "🐛 Debug mode enabled" );
            println( "⚙️  Runtime Info:" );
            println( "   - CLI Mode: " & server.boxlang.cliMode );
            println( "   - JAR Mode: " & server.boxlang.jarMode );
            println( "   - Runtime Home: " & server.boxlang.runtimeHome );
        }

        // Process based on environment
        if ( isDev ) {
            runDevelopmentTasks( );
        } else {
            runProductionTasks( );
        }
    }

    private function runDevelopmentTasks( ) {
        println( "🔨 Running development tasks..." );
        // Development-specific logic
    }

    private function runProductionTasks( ) {
        println( "🚀 Running production tasks..." );
        // Production-specific logic
    }
}
```

Usage:

```bash
# Development mode with debug
boxlang --bx-debug example-workflow.bx --env=development --debug

# Production mode
boxlang example-workflow.bx --env=production
```

### Integration Examples

BoxLang CLI can integrate with various tools and workflows:

```bash
# CI/CD Pipeline Integration
boxlang --bx-code "
    println( 'Starting CI/CD Pipeline...' );
    var result = runTests( );
    if ( !result.success ) {
        cliExit( 1 );
    }
    deployApplication( );
    println( 'Pipeline completed successfully!' );
"

# Database Migrations
boxlang migrate.bx --action=up --env=production

# Code Generation
boxlang generate.bx --type=component --name=UserService

# Environment Setup
boxlang setup.bx --install-deps --configure-db
```

### Performance and Debug Information

When using `--bx-debug`, BoxLang provides detailed performance metrics:

```bash
boxlang --bx-debug myapp.bx
```

This outputs:

* Execution timing information
* Memory usage statistics
* Runtime initialization details
* AST parsing time
* Module loading performance

### Community Resources

* 📚 **Documentation**: <https://boxlang.ortusbooks.com/>
* 💬 **Community Forum**: <https://community.ortussolutions.com/c/boxlang/42>
* 💾 **GitHub Repository**: <https://github.com/ortus-boxlang>
* 🌐 **Official Website**: <https://boxlang.io>
* 🎯 **Examples Repository**: <https://github.com/ortus-boxlang/bx-demos>

## Dad Joke Script

Thanks to our evangelist Raymond Camden, we have a cool dad joke script you can find in our demos: <https://github.com/ortus-boxlang/bx-demos>

```java
class {
    variables.apiURL = "https://icanhazdadjoke.com/";

    /**
     * The first argument is a term to search dad jokes on, if not provided, a random dad joke will be fetched.
     * Example: boxlang DadJoke.bx dad
     * Example: boxlang DadJoke.bx
     */
    function main( args = [ ] ) {
        // Use elvis operator to check if a term was passed, else, use an empty string
        var term = ( args[ 1 ] ?: "" ).trim( );

        if ( !term.isEmpty( ) ) {
            apiURL &= "search?term=" & term.urlEncodedFormat( );
        }

        println( "Getting dad joke for term [#term#], please wait..." );
        bx:http url=apiURL result="result" {
            bx:httpparam type="header" name="Accept" value="application/json";
        }
        var data = JSONDeserialize( result.fileContent );

         // possible none were found, use safe navigation operator
         if ( data?.results?.len( ) == 0 ) {
            println( "No jokes found for term: #term#" );
            return cliExit( );
         }

        // If we searched for a term, we need to get a random joke from the results, otherwise, just .joke
        var joke = term.isEmpty( ) ? data.joke : data.results[ randRange( 1, data.results.len( ) ) ].joke;
        println( joke );
    }

}
```

Now you execute it

```bash
// Random joke
boxlang DadJoke.bx

// Term jokes
boxlang DadJoke.bx ice
```

Let's modify it now so that we can prompt the user for the term using the `CLIRead( )`BIF instead of passing it:

```java
var term = ( CLIRead( "What search term would you like to use? (Leave blank for random joke)" ) ).trim( );
```


# DigitalOcean App

Deploy a modern, cloud-native BoxLang application to DigitalOcean App Platform in minutes!

## 🥊 BoxLang Starter for DigitalOcean

**Deploy a modern, cloud-native BoxLang application to DigitalOcean App Platform in minutes!**

{% embed url="<https://github.com/ortus-boxlang/boxlang-starter-digitalocean>" %}

This starter kit provides everything you need to run a **production-ready BoxLang application** on [DigitalOcean's App Platform](https://www.digitalocean.com/?refcode=4d60357dfb31\&utm_campaign=Referral_Invite\&utm_medium=Referral_Program). Built with the powerful **BoxLang MiniServer**, this template showcases BoxLang's modern language features, beautiful UI components, and seamless cloud deployment workflow.

**✨ What You Get:**

* 🚀 Pre-configured BoxLang MiniServer with optimal settings
* 🎨 Beautiful, responsive landing page with Phosphor icons
* 🐳 Multi-stage Docker build for efficient deployments
* ⚡ Auto-compile and hot-reload in development
* 🔄 Automatic redeployment on code changes (when forked)
* 📦 Ready for DigitalOcean App Platform one-click deployment

**⚠️ Note:** Following these steps may result in charges for the use of DigitalOcean services.

### 📋 Requirements

* A DigitalOcean account. If you don't have one, [sign up here](https://cloud.digitalocean.com/registrations/new?refcode=4d60357dfb31).
* (Optional) A GitHub account to fork this repository for automatic deployments.

### 🚀 Deploy the App

Click the button below to deploy this app to DigitalOcean App Platform. If you're not logged in, you'll be prompted to authenticate.

[![Deploy to DigitalOcean](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/ortus-boxlang/boxlang-starter-digitalocean/tree/main\&refcode=4d60357dfb31)

#### 🍴 Fork for Automatic Redeployments (Recommended)

The one-click deploy button above deploys directly from our template repository, which means you won't get automatic redeployments when you make changes. **We recommend forking this repository** to your own GitHub account first.

**To fork this repository:**

1. Navigate to the [repository on GitHub](https://github.com/ortus-boxlang/boxlang-starter-digitalocean)
2. Click the **Fork** button in the top-right corner
3. Follow the on-screen instructions ([Learn more about forking](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo))

**To deploy your forked repository:**

1. Visit the [DigitalOcean Apps control panel](https://cloud.digitalocean.com/apps?refcode=4d60357dfb31)
2. Click **Create App**
3. Under **Service Provider**, select **GitHub**
4. Under **Repository**, select your forked repo (e.g., `<your-username>/boxlang-starter-digitalocean`)
5. Ensure **Branch** is set to `main` and **Autodeploy** is checked ✅
6. Click **Next**

#### ⚙️ Configuration Steps

After clicking the deploy button or connecting your forked repository:

1. **Configure your app** (Optional)
   * Add environment variables
   * Configure HTTP routes
   * Add databases or other services
   * For this starter, default settings work perfectly!
2. **Name and Region**
   * Provide a name for your app
   * Select your preferred deployment region
   * App Platform automatically selects the closest region
   * All apps are routed through a global CDN for optimal performance 🌍
3. **Review Settings**
   * Leave default fields as-is
   * Click **Next**
4. **Launch Your App** 🎉
   * Review your plan (Basic/Pro)
   * Confirm the number of containers
   * Click **Launch Basic/Pro App**

#### 📊 Monitor Your Deployment

After launching, you'll see a **"Building..."** progress indicator. Click **View Logs** to watch the build process in real-time.

The build typically takes **2-3 minutes**. Once complete:

* Click the **Live App** link in the header
* Your BoxLang application will open in a new tab! 🎊

### ✏️ Make Changes to Your App

If you forked the repository, you can now customize your BoxLang application:

1. Make changes to files in your forked repo (e.g., edit `/app/index.bxm`)
2. Commit and push to the `main` branch
3. App Platform automatically redeploys with **zero downtime** ⚡

No manual steps required—just push and watch it deploy!

### 📚 Learn More

Want to dive deeper into App Platform features?

* [DigitalOcean App Platform Documentation](https://www.digitalocean.com/docs/app-platform/?refcode=4d60357dfb31)
* [BoxLang Documentation](https://boxlang.ortusbooks.com)
* [BoxLang MiniServer Guide](https://boxlang.ortusbooks.com/getting-started/running-boxlang/miniserver)

### 🗑️ Delete the App

When you're done testing or no longer need this application:

1. Visit the [Apps control panel](https://cloud.digitalocean.com/apps)
2. Select your app
3. Go to the **Settings** tab
4. Click **Destroy**
5. Confirm the deletion

**⚠️ Important:** If you don't delete your app, charges for DigitalOcean services will continue to accrue.

### 🥊 BoxLang MiniServer App

This starter uses the **BoxLang MiniServer**—a lightweight, embedded web server perfect for containerized deployments and rapid development.

#### What's Included

**📦 Application Structure:**

```
boxlang-starter-digitalocean/
├── app/                      # Your BoxLang application
│   ├── Application.bx        # Application configuration
│   ├── index.bxm             # Main landing page
│   └── includes/             # Assets (images, CSS, JS)
├── boxlang.json              # BoxLang runtime configuration
├── miniserver.json           # MiniServer settings
├── Dockerfile                # Multi-stage Docker build
└── README.md                 # You are here!
```

**⚙️ MiniServer Configuration:**

* **Port:** 8080 (production), 9090 (local development)
* **Host:** 0.0.0.0 (container), 127.0.0.1 (local)
* **Web Root:** `./app` directory
* **Auto-compile:** Enabled for BoxLang files
* **Health Check:** Built-in health endpoint
* **URL Rewrites:** Enabled with fallback to `index.bxm`

#### 🏃 Running Locally

Want to test your BoxLang app on your local machine? Here's how:

**Prerequisites**

* [Docker](https://www.docker.com/get-started) installed on your machine
* OR [BoxLang](https://boxlang.ortusbooks.com/getting-started/installation) installed

**Option 1: Run with Docker (Recommended)**

```bash
# Clone or navigate to your project directory
cd boxlang-starter-digitalocean

# Build the Docker image
docker build -t boxlang-digitalocean .

# Run the container
docker run -p 9090:8080 boxlang-digitalocean

# Visit http://localhost:9090 in your browser 🎉
```

**Hot Reload Development Mode:**

```bash
# Mount your app directory for live changes
docker run -p 9090:8080 \
  -v $(pwd)/app:/app/app \
  boxlang-digitalocean

# Edit files in ./app and refresh your browser!
```

**Option 2: Run with BoxLang CLI**

```bash
# Install BoxLang CLI if you haven't already
# Visit: https://boxlang.ortusbooks.com/getting-started/installation

# Navigate to your project directory
cd boxlang-starter-digitalocean

# Start the MiniServer
boxlang miniserver

# Visit http://localhost:9090 in your browser 🎉
```

The MiniServer will automatically read `miniserver.json` and start with all configured settings.

#### 🔧 Customization Tips

**Update the Port:**

Edit `miniserver.json` to change the default port:

```json
{
  "port": 3000  // Change to your preferred port
}
```

**Environment Variables:**

Set environment-specific configurations in `boxlang.json`:

```json
{
  "runtime": {
    "debug": true,
    "timezone": "UTC"
  }
}
```

**Add BoxLang Modules:**

Install community modules using the BoxLang CLI:

```bash
boxlang module install <module-name>
```

#### 📖 Additional Resources

* [BoxLang Language Documentation](https://boxlang.ortusbooks.com/boxlang-language)
* [BoxLang Framework & Modules](https://boxlang.ortusbooks.com/boxlang-framework)
* [MiniServer Configuration](https://boxlang.ortusbooks.com/getting-started/running-boxlang/miniserver)
* [BoxLang on GitHub](https://github.com/ortus-boxlang/boxlang)

***

#### 💬 Need Help?

* **Community:** Join the [BoxLang Community](https://community.ortussolutions.com)
* **Documentation:** [BoxLang Docs](https://boxlang.ortusbooks.com)
* **Professional Support:** [BoxLang +/++](https://www.boxlang.io/plans)

**Happy Coding with BoxLang! 🥊**


# Demos

BoxLang has an extensive collection of runnable demos showcasing real-world applications and integrations.

Discover an extensive collection of demos at <https://github.com/ortus-boxlang/bx-demos/>. This repository offers a wide range of example projects and code snippets designed to illustrate various programming concepts, techniques, and real-world applications.

Whether you are a beginner looking to learn new skills or an experienced developer seeking advanced implementations, this resource provides valuable insights and practical demonstrations to help you enhance your understanding and expertise.

## 🚀 Demo Categories

The demo repository contains examples across multiple categories:

### 📱 **Web Applications**

* **Blog Systems** - Complete blog applications with database integration
* **Comic Book Reader** - File processing and web-based viewing applications
* **Calendar Applications** - Date/time handling and UI generation
* **File Search Tools** - Full-text search and indexing systems
* **API Integration Examples** - REST API consumption and data processing

### 📊 **Data & Integration**

* **Database Access** - MySQL, Derby, and database query examples
* **CSV Processing** - File parsing and data transformation
* **RSS Feed Aggregation** - Multi-source data collection and normalization
* **JSON Handling** - Data serialization and API responses
* **PDF Processing** - Document generation and manipulation

### 🔧 **Advanced Features**

* **Java Library Integration** - Using external JARs and Maven dependencies
* **Module Development** - Creating custom BoxLang modules with BIFs
* **Async Programming** - Background processing and concurrent operations
* **Web Scraping** - AgentQL integration and data extraction
* **AI/ML Integration** - Sentiment analysis and machine learning workflows

### 🎯 **Development Patterns**

* **MVC Applications** - Structured web application architecture
* **REST APIs** - Building and consuming web services
* **Template Systems** - Dynamic content generation
* **Custom Tags** - Reusable component development
* **CLI Tools** - Command-line application examples

## 🎮 Interactive Playground

Don't forget about [https://try.boxlang.io](https://try.boxlang.io/) - your online coding playground where you can experiment with BoxLang code directly in your browser without any local setup required.

<figure><img src="/files/NeCEx6rolvjH6mc7mBo1" alt="BoxLang Try Online Interface"><figcaption><p>BoxLang online coding playground at try.boxlang.io</p></figcaption></figure>

## 📝 Featured Examples

Some notable examples from the repository include:

### **Real-World Blog Application**

Complete blog system with:

* Database integration ( MySQL/Derby )
* Custom routing and templates
* Administration interface
* Multi-user support

### **Java Library Integration**

Demonstrates how to:

* Include external JAR files
* Use Maven-style dependencies
* Integrate with Java Optional patterns
* Handle complex Java objects

### **Module Development**

Shows how to create:

* Custom Built-In Functions ( BIFs )
* Modular components
* Library packaging
* Distribution and installation

### **API Development & Consumption**

Examples of:

* REST API creation with `remote` functions
* External API integration ( Jira, AgentQL, Pinecone )
* Data transformation and caching
* Error handling patterns

## 🔨 Getting Started with Demos

1. **Clone the Repository**:

   ```bash
   git clone https://github.com/ortus-boxlang/bx-demos.git
   ```
2. **Browse Categories**:
   * `webapps/` - Full web applications
   * `modules/` - Custom module examples
   * `misc/` - Utility scripts and tools
   * Individual demo folders contain README files with setup instructions
3. **Try Online First**:
   * Visit [try.boxlang.io](https://try.boxlang.io/) for immediate experimentation
   * Copy demo code snippets to test concepts
   * No local installation required

## 🎯 Learning Path Suggestions

### **Beginners**

Start with basic examples in `misc/` folder, then explore simple web applications

### **Web Developers**

Focus on `webapps/` examples, especially the blog and API demonstrations

### **Java Developers**

Check out Java integration examples and module development patterns

### **Advanced Users**

Explore AI integration, async programming, and complex data processing examples

{% hint style="info" %}
**Pro Tip**: Each demo folder typically contains its own README with specific setup instructions, dependencies, and usage examples. Always check the README first!
{% endhint %}

{% @github-files/github-code-block url="<https://github.com/ortus-boxlang/bx-demos/>" %}


# Desktop Applications

Build native cross-platform desktop applications with BoxLang, Electron, and Vite — ship a full JVM web server inside every installer.

<figure><img src="/files/cnvoCcdwM01Hkwd8CSoi" alt="BoxLang Desktop Applications with Electron"><figcaption><p>Build professional desktop apps with BoxLang and Electron</p></figcaption></figure>

BoxLang desktop applications combine three things you already know: BoxLang server-side logic running inside a local **MiniServer**, an **Electron** shell that owns the native window, tray, and menus, and a **Vite** build pipeline for modern frontend assets. The result is a cross-platform desktop app that ships a real HTTP server — not Electron's renderer process playing fetch tricks — so your BoxLang code runs exactly the same way it does on the web.

We provide a turnkey starter to get you moving immediately:

{% @github-files/github-code-block url="<https://github.com/ortus-boxlang/boxlang-starter-desktop-electron>" %}

Everything the starter gives you out of the box:

* BoxLang MiniServer running inside the desktop app on a local port
* Electron shell with app menu, system tray, global shortcuts, and native window lifecycle
* Vite build pipeline for JS and SCSS assets (Alpine.js + Bootstrap 5 included)
* SQLite datasource pre-configured via `Application.bx`
* Full packaging flow for macOS, Windows, and Linux

## 📋 Table of Contents

* [Architecture](#architecture)
* [Prerequisites](#prerequisites)
* [Quick Start](#quick-start)
* [Project Structure](#project-structure)
* [Configuration](#configuration)
* [BoxLang Web Layer](#boxlang-web-layer)
* [Frontend Layer](#frontend-layer)
* [Desktop Layer](#desktop-layer)
* [Development Workflow](#development-workflow)
* [Coding Your Application](#coding-your-application)
* [Electron Forge](#electron-forge)
* [Building and Distributing](#building-and-distributing)
* [Code Signing](#code-signing)
* [Auto Updates](#auto-updates)
* [Debugging](#debugging)
* [Publishers](#publishers)
* [Cross-Platform Considerations](#cross-platform-considerations)
* [Troubleshooting](#troubleshooting)
* [Resources](#resources)

## 🏗️ Architecture

The architecture separates three concerns that each own their layer:

| Layer              | Technology                    | Purpose                                               |
| ------------------ | ----------------------------- | ----------------------------------------------------- |
| Desktop shell      | Electron                      | Window, tray, menus, shortcuts, native OS integration |
| Application server | BoxLang MiniServer (Undertow) | BoxLang template and class execution                  |
| Frontend assets    | Vite + Alpine.js + Bootstrap  | JS, SCSS, HMR in dev / hashed bundles in production   |

### Architecture diagram

```mermaid
flowchart LR
    A[Electron Main.js] --> B[BoxLang.js Process Manager]
    B --> C[miniserver.json]
    B --> D[BoxLang MiniServer]
    D --> E[public/Application.bx]
    D --> F[public/index.bxm]
    F --> G[ViteHelper.bx]
    G --> H[Vite Dev Server or Built Assets]
    A --> I[BrowserWindow]
    I --> D
```

### Runtime flow

<figure><img src="/files/Acn6c1bd6Rp3kAD1XK55" alt="Loading BoxLang App"><figcaption><p>Loading BoxLang Desktop Application</p></figcaption></figure>

1. Electron starts from `app/electron/Main.js`.
2. `Main.js` wires the modular components: `BoxLang`, `AppMenu`, `TrayMenu`, and `Shortcuts`.
3. `BoxLang.js` spawns the MiniServer process using the settings in `miniserver.json`.
4. `BoxLang.js` polls the server URL until it is reachable, then tells the `BrowserWindow` to load the local server address.
5. Electron renders the BoxLang application inside the desktop window as if it were a browser tab, but with full native OS integration.

### Config relationship diagram

```mermaid
flowchart TD
    A[miniserver.json] -->|Boot MiniServer| B[BoxLang Runtime]
    C[.boxlang-dev.json] -->|Dev runtime behavior| B
    D[.boxlang.json] -->|Production runtime behavior| B
    B --> E["'/app' mapping → app/"]
    B --> F["'/public' mapping → public/"]
```

{% hint style="info" %}
Java 21+ must be installed on every machine that runs the desktop app. Only the BoxLang MiniServer binaries and libs are packaged inside the installer — no JRE is bundled.
{% endhint %}

## 📋 Prerequisites

* **Java 21+** — required on every machine that will run the app
* **BoxLang CLI** — install with the [Quick Installer](/getting-started/installation/boxlang-quick-installer) or the [BoxLang Version Manager (BVM)](/getting-started/installation/boxlang-version-manager-bvm)
* **Node.js 25+** — for Electron and Vite
* **CommandBox** — optional but useful for BoxLang dependency management (`box install`)

## ⚡ Quick Start

{% stepper %}
{% step %}

### Get the starter

The starter lives at <https://github.com/ortus-boxlang/boxlang-starter-desktop-electron>. You have two options:

**Option A — Use as a GitHub Template (recommended for new projects)**

Click the **"Use this template"** button on the GitHub repository page to create your own repository pre-populated with all the starter files, then clone your new repo:

```bash
git clone https://github.com/<your-org>/<your-repo>.git mydesktopapp
cd mydesktopapp
```

**Option B — Clone directly**

```bash
git clone https://github.com/ortus-boxlang/boxlang-starter-desktop-electron.git mydesktopapp
cd mydesktopapp
```

{% endstep %}

{% step %}

### Install dependencies

```bash
# BoxLang module dependencies (if any)
box install

# Node.js dependencies (Electron, Vite, etc.)
npm install
```

{% endstep %}

{% step %}

### Package the MiniServer runtime

The starter ships without a pre-built MiniServer. Run this once to download and extract it from the version pinned in `.bvmrc`:

```bash
npm run package:miniserver
```

This downloads MiniServer into `runtime/bin` and `runtime/lib`. The version is read from `.bvmrc`:

```
1.12.0
```

{% hint style="success" %}
Use `npm run package:miniserver:force` to re-download over an existing runtime.
{% endhint %}
{% endstep %}

{% step %}

### Start development mode

```bash
npm run dev
```

This launches Vite (with HMR on `127.0.0.1:3000`) and Electron in parallel. Electron waits for Vite to be ready before starting the MiniServer and loading the window.
{% endstep %}
{% endstepper %}

## 📁 Project Structure

```
mydesktopapp/
├── .bvmrc                          # Pinned MiniServer version
├── miniserver.json                 # Local MiniServer control (host, port, webRoot)
├── .boxlang-dev.json               # BoxLang development runtime config
├── .boxlang.json                   # BoxLang production runtime config
├── vite.config.mjs                 # Vite build configuration
├── package.json                    # Node scripts and dependencies
│
├── app/
│   └── electron/
│       ├── Main.js                 # Electron bootstrap, window lifecycle, logging
│       ├── BoxLang.js              # MiniServer process manager
│       ├── AppMenu.js              # Native application menu
│       ├── TrayMenu.js             # System tray behavior and status
│       └── Shortcuts.js            # Global keyboard shortcuts
│
├── public/                         # BoxLang web root (served by MiniServer)
│   ├── Application.bx              # App settings, mappings, datasource bootstrap
│   ├── index.bxm                   # Default landing page template
│   └── includes/
│       ├── helpers/
│       │   └── ViteHelper.bx       # Dev/prod asset URL resolution
│       ├── images/
│       └── resources/              # Built Vite assets (generated — do not commit)
│
├── resources/
│   └── assets/
│       ├── js/                     # Source JS (Alpine.js components, etc.)
│       └── scss/                   # Source SCSS
│
├── runtime/
│   ├── Package.bx                  # MiniServer packager script
│   ├── VERSION                     # Current packaged MiniServer version
│   ├── bin/                        # MiniServer executables (generated)
│   └── lib/                        # MiniServer JARs (generated)
│
└── tests/                          # BoxLang application tests
```

### Where developers usually edit

| What you want to change              | Where to look                         |
| ------------------------------------ | ------------------------------------- |
| UI pages and templates               | `public/`                             |
| BoxLang business logic and models    | `app/`                                |
| Frontend JS behavior and styles      | `resources/assets/`                   |
| Native window, tray, menu, shortcuts | `app/electron/`                       |
| Server config (port, rewrites, etc.) | `miniserver.json`                     |
| Runtime debugMode, cache, mappings   | `.boxlang-dev.json` / `.boxlang.json` |

## ⚙️ Configuration

### `miniserver.json` — server control

This is your primary runtime control file during development. It tells `BoxLang.js` how to start the MiniServer:

```json
{
    "port": 59700,
    "host": "127.0.0.1",
    "webRoot": "public",
    "serverHome": ".boxlang",
    "rewrites": true,
    "debug": false,
    "envFile": ".env"
}
```

| Setting      | Purpose                                                                            |
| ------------ | ---------------------------------------------------------------------------------- |
| `port`       | Port for the local MiniServer — pick something that won't conflict with other apps |
| `host`       | Bind to `127.0.0.1` so the server is only reachable from localhost                 |
| `webRoot`    | Folder served as the web root (`public/` by default)                               |
| `serverHome` | BoxLang home directory (modules, config, compiled classes)                         |
| `rewrites`   | Enable URL rewriting for clean URLs                                                |
| `envFile`    | Path to a `.env` file loaded into the MiniServer environment on boot               |

{% hint style="warning" %}
Keep `host` set to `127.0.0.1`. Binding to `0.0.0.0` would expose the local server to the network, which is not appropriate for a desktop application.
{% endhint %}

### `.boxlang-dev.json` vs `.boxlang.json`

The BoxLang runtime reads different config files for development and production so the two environments stay predictable.

**.boxlang-dev.json** — used during `npm run dev`:

```json
{
    "debugMode": true,
    "mappings": {
        "/app": {
            "path": "${user-dir}/app",
            "external": false
        },
        "/public": "${user-dir}/public"
    }
}
```

**.boxlang.json** — used in the packaged/distributed app:

```json
{
    "debugMode": false,
    "mappings": {
        "/app": {
            "path": "${user-dir}/app",
            "external": false
        },
        "/public": "${user-dir}/public"
    }
}
```

The `/app` and `/public` mappings are present in both files. They let your BoxLang code reference classes and templates by mapping path regardless of where the app is installed on the user's machine.

{% hint style="success" %}
Keep both files under version control. They define the application's class resolution and runtime behavior and should ship with the project.
{% endhint %}

### `.bvmrc` — MiniServer version pin

A single-line file containing the MiniServer version to download:

```
1.12.0
```

Update this when you want to upgrade. Then re-run `npm run package:miniserver:force` to fetch the new version.

## 🌐 BoxLang Web Layer

Everything inside `public/` is served by the MiniServer. This is where you write BoxLang templates, classes, and helpers.

### `public/Application.bx`

This is the BoxLang application descriptor. It runs once when the app boots and defines application-level settings, mappings, and datasources:

```js
class {

    this.name                 = "My BoxLang Desktop Application"
    this.sessionManagement    = true
    this.sessionTimeout       = createTimespan( 0, 1, 0, 0 )
    this.timezone             = "UTC"
    this.whiteSpaceManagement = "smart"

    // Mapping to the public/ folder itself
    this.mappings[ "/root" ] = getDirectoryFromPath( getCurrentTemplatePath() )

    // SQLite datasource — stored inside the project folder
    this.datasource = "boxlangDB"
    this.datasources[ "boxlangDB" ] = {
        "driver"  : "sqlite",
        "protocol": "directory",
        "database": "./.database/boxlangDB"
    }

    public boolean function onApplicationStart(){
        // Make ViteHelper available to all templates via application scope
        application.viteHelper = new includes.helpers.ViteHelper()
        return true
    }

    public boolean function onRequestStart( string targetPage ){
        return true
    }
}
```

Change `this.name`, datasource config, mappings, and lifecycle methods here as your application grows.

### `public/index.bxm`

The default landing page. It uses Bootstrap 5 and Alpine.js and calls `ViteHelper` to include the correct asset URLs:

```html
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
    <meta charset="UTF-8">
    <title>My Desktop App</title>
    <bx:output>#application.viteHelper.styles( "app" )#</bx:output>
</head>
<body>
    <h1>Hello from BoxLang!</h1>
    <bx:output>#application.viteHelper.scripts( "app" )#</bx:output>
</body>
</html>
```

### `public/includes/helpers/ViteHelper.bx`

Resolves asset URLs based on the runtime environment:

* **Development** (`ENVIRONMENT=development`): points directly to the Vite dev server on `127.0.0.1:3000` for Hot Module Replacement.
* **Production**: reads the Vite manifest (`public/includes/resources/.vite/manifest.json`) and returns the correct hashed file URLs.

You never call this directly beyond what is already in `Application.bx`. `onApplicationStart` instantiates it once into `application.viteHelper`.

## 🎨 Frontend Layer

Source files live in `resources/assets/`:

```
resources/assets/
├── js/
│   └── app.js      # Alpine.js components, app initialization
└── scss/
    └── app.scss    # Bootstrap 5 import + overrides
```

Build output goes to `public/includes/resources/` (git-ignored — generated by Vite).

### Vite development

When you run `npm run dev`, Vite starts on `127.0.0.1:3000` with HMR. The `ViteHelper.bx` detects the `ENVIRONMENT=development` flag injected by `concurrently` and points asset tags at Vite directly.

### Production build

```bash
npm run build
```

Outputs hashed bundles into `public/includes/resources/` and writes `manifest.json`. The `ViteHelper.bx` reads the manifest in production to serve the correct file names.

{% hint style="info" %}
Bootstrap 5 and Alpine.js are installed as regular npm packages and bundled by Vite — you are never loading them from a CDN, which keeps the desktop app fully offline.
{% endhint %}

## 🖥️ Desktop Layer

All desktop behavior lives in `app/electron/`. Each module has a single responsibility:

### `Main.js` — bootstrap and window lifecycle

Starts Electron, sets up logging to the OS log directory, creates and manages the `BrowserWindow`, and wires together all modular components:

```js
import { app, BrowserWindow } from "electron";
import { BoxLang } from './BoxLang.js';
import { AppMenu } from './AppMenu.js';
import { TrayMenu } from './TrayMenu.js';
import { Shortcuts } from './Shortcuts.js';

app.whenReady().then( async () => {
    boxLang  = new BoxLang( globalSettings );
    appMenu  = new AppMenu( globalSettings );
    trayMenu = new TrayMenu( globalSettings );
    shortcuts = new Shortcuts( globalSettings );

    await boxLang.start();
    createWindow();
} );
```

**Electron resources:**

* [app lifecycle API](https://www.electronjs.org/docs/latest/api/app)
* [BrowserWindow API](https://www.electronjs.org/docs/latest/api/browser-window)
* [NativeImage API](https://www.electronjs.org/docs/latest/api/native-image)

### `BoxLang.js` — MiniServer process manager

Handles the full lifecycle of the MiniServer child process: startup, readiness polling, crash recovery, restart, and graceful shutdown.

Key behaviors:

* Prefers the packaged `runtime/bin/boxlang-miniserver` executable; falls back to global `boxlang-miniserver` on `PATH`.
* On Unix/macOS: automatically sets execute permissions if they are missing.
* Polls the server URL at 500 ms intervals until it responds or the 30-second timeout expires.
* On crash: waits 5 seconds then restarts (suppressed if `isQuitting` is true).
* Graceful stop is triggered on `app.before-quit`.

**Node.js resources:**

* [child\_process API](https://nodejs.org/docs/latest/api/child_process.html)
* [process signals](https://nodejs.org/docs/latest/api/process.html)

### `AppMenu.js` — native application menu

Defines the menu bar shown on macOS and inside the window on Windows/Linux. Extend this to add your own menu items and keyboard accelerators.

**Electron resources:**

* [Menu API](https://www.electronjs.org/docs/latest/api/menu)
* [MenuItem API](https://www.electronjs.org/docs/latest/api/menu-item)
* [Accelerator keys](https://www.electronjs.org/docs/latest/api/accelerator)

### `TrayMenu.js` — system tray

Creates the status icon in the system tray (macOS menu bar, Windows notification area, Linux status bar) with a context menu to show, hide, restart, or quit the app.

**Electron resources:**

* [Tray API](https://www.electronjs.org/docs/latest/api/tray)
* [Tray tutorial](https://www.electronjs.org/docs/latest/tutorial/tray)

### `Shortcuts.js` — global keyboard shortcuts

Registers global shortcuts that fire even when the app window is not focused.

**Electron resources:**

* [globalShortcut API](https://www.electronjs.org/docs/latest/api/global-shortcut)

## 💻 Development Workflow

### Scripts reference

| Script                             | What it does                                                     |
| ---------------------------------- | ---------------------------------------------------------------- |
| `npm run dev`                      | Start Vite + Electron in development mode (HMR enabled)          |
| `npm run start`                    | Start Electron only (assumes Vite dev server is already running) |
| `npm run build`                    | Build frontend assets into `public/includes/resources/`          |
| `npm run prod`                     | Build assets then start Electron in production mode              |
| `npm run preview`                  | Preview the Vite production build in a local server              |
| `npm run lint`                     | Lint JS files with ESLint                                        |
| `npm run lint:fix`                 | Auto-fix lint errors                                             |
| `npm run generate:icons`           | Regenerate app icons from a source PNG                           |
| `npm run package:miniserver`       | Download MiniServer from `.bvmrc` into `runtime/`                |
| `npm run package:miniserver:force` | Force re-download even if already present                        |
| `npm run package`                  | Build assets and run `electron-forge make` for all platforms     |
| `npm run package:mac`              | Build macOS distributions only (`--platform darwin`)             |
| `npm run package:win`              | Build Windows distributions only (`--platform win32`)            |
| `npm run package:linux`            | Build Linux distributions only (`--platform linux`)              |
| `npm run package:linux:docker`     | Build Linux distributions via Docker (for cross-platform builds) |
| `npm run package:full`             | Package MiniServer then build all distributions                  |

### Typical development loop

```bash
# Terminal 1 (or just use npm run dev which runs both)
npm run dev
```

1. Edit BoxLang templates in `public/` — changes are picked up immediately since MiniServer re-processes templates on every request.
2. Edit SCSS or JS in `resources/assets/` — Vite HMR pushes changes to the Electron window instantly.
3. Edit Electron modules in `app/electron/` — you need to restart Electron (`Ctrl+C` then `npm run dev` again) for JS changes to take effect.

{% hint style="success" %}
BoxLang templates have no compile-restart cycle. Save the file and refresh — that is all.
{% endhint %}

## ✏️ Coding Your Application

### Adding pages and templates

Create `.bxm` files anywhere under `public/`. The MiniServer serves them as BoxLang templates:

```
public/
└── dashboard.bxm
```

```html
<bx:script>
    var stats = queryExecute(
        "SELECT count(*) as total FROM records",
        {},
        { datasource: "boxlangDB" }
    )
</bx:script>

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Dashboard</title>
    <bx:output>#application.viteHelper.styles( "app" )#</bx:output>
</head>
<body>
    <h1>Total Records: <bx:output>#stats.total#</bx:output></h1>
    <bx:output>#application.viteHelper.scripts( "app" )#</bx:output>
</body>
</html>
```

With rewrites enabled, `http://127.0.0.1:59700/dashboard` maps to `/dashboard.bxm`.

### Adding BoxLang classes

Place classes in `app/` or `public/includes/`. The `/app` mapping makes everything under `app/` reachable:

```
app/
└── models/
    └── RecordService.bx
```

```js
// app/models/RecordService.bx
class {

    function getAll() {
        return queryExecute(
            "SELECT * FROM records ORDER BY createdAt DESC",
            {},
            { datasource: "boxlangDB" }
        )
    }

    function save( required struct data ) {
        queryExecute(
            "INSERT INTO records ( title, body ) VALUES ( :title, :body )",
            {
                title : { value: data.title, sqltype: "varchar" },
                body  : { value: data.body,  sqltype: "varchar" }
            },
            { datasource: "boxlangDB" }
        )
    }
}
```

Create it in a template with `new /app/models/RecordService()` or add it to the application scope in `onApplicationStart`:

```js
public boolean function onApplicationStart(){
    application.viteHelper    = new includes.helpers.ViteHelper()
    application.recordService = new /app/models/RecordService()
    return true
}
```

### Using the SQLite datasource

The starter wires up a local SQLite database at `.database/boxlangDB` (the folder is created automatically). Use `queryExecute` anywhere in your templates or classes:

```js
// Create a table
queryExecute(
    "CREATE TABLE IF NOT EXISTS notes (
        id        INTEGER PRIMARY KEY AUTOINCREMENT,
        title     TEXT NOT NULL,
        body      TEXT,
        createdAt TEXT DEFAULT (datetime('now'))
    )",
    {},
    { datasource: "boxlangDB" }
)

// Insert a row
queryExecute(
    "INSERT INTO notes ( title, body ) VALUES ( :title, :body )",
    {
        title : { value: "Hello BoxLang", sqltype: "varchar" },
        body  : { value: "My first note", sqltype: "varchar" }
    },
    { datasource: "boxlangDB" }
)

// Query rows
var notes = queryExecute(
    "SELECT * FROM notes ORDER BY createdAt DESC",
    {},
    { datasource: "boxlangDB" }
)
```

### Customizing the native menu

Edit `app/electron/AppMenu.js`. Add your own items using Electron's `Menu.buildFromTemplate()` API:

```js
{ label: 'My Feature', accelerator: 'CmdOrCtrl+Shift+F', click: () => {
    mainWindow.loadURL( 'http://127.0.0.1:59700/my-feature' )
} }
```

### Adding a global keyboard shortcut

Edit `app/electron/Shortcuts.js`. Register with `globalShortcut.register`:

```js
globalShortcut.register( 'CmdOrCtrl+Shift+D', () => {
    mainWindow.loadURL( 'http://127.0.0.1:59700/dashboard' )
} )
```

### Customizing the tray menu

Edit `app/electron/TrayMenu.js`. Add items to the `contextMenu` template array:

```js
{ label: 'Open Dashboard', click: () => {
    mainWindow.show()
    mainWindow.loadURL( 'http://127.0.0.1:59700/dashboard' )
} }
```

### Application name and app ID

Edit `forge.config.cjs` in the `packagerConfig` section:

```js
packagerConfig: {
    name  : "My Desktop App",
    appId : "com.example.mydesktopapp",
    // ...
}
```

Also update `this.name` in `public/Application.bx`.

## ⚙️ Electron Forge

The starter uses [Electron Forge](https://www.electronforge.io/) as its build and packaging toolchain. Forge replaced the older `electron-builder` workflow and provides:

* A single `electron-forge make` command that packages, makes, and signs artifacts in the correct order
* First-class maker plugins for every platform (DMG, Squirrel, DEB, RPM, Flatpak, ZIP)
* A built-in publisher system for uploading artifacts to GitHub, S3, and more
* Hooks for injecting custom post-build logic at any step

The config lives in `forge.config.cjs` (CommonJS format — required by Forge):

```js
// forge.config.cjs (simplified)
module.exports = {
    packagerConfig: {
        name          : "BoxLang Starter Desktop",
        appId         : "io.boxlang.starter",
        asar          : false,   // CRITICAL — must stay false (MiniServer binary)
        icon          : "./public/includes/icon",
        osxSign       : {},      // macOS code signing (when identity is set)
        osxNotarize   : { ... }  // macOS notarization (when credentials are set)
    },
    makers : [ /* platform makers — see below */ ],
    hooks  : { postMake },       // bundles unsigned-build helpers into ZIP artifacts
    outDir : "dist/electron"
};
```

{% hint style="warning" %}
`asar` must remain `false`. `BoxLang.js` spawns `runtime/bin/boxlang-miniserver` as a real filesystem executable — enabling asar archiving would break that path lookup entirely.
{% endhint %}

### Platform makers

The starter ships makers for every supported platform:

| Maker            | Platform      | Output                   | Notes                                                                         |
| ---------------- | ------------- | ------------------------ | ----------------------------------------------------------------------------- |
| `maker-dmg`      | macOS         | `.dmg`                   | Primary macOS distribution format                                             |
| `maker-pkg`      | macOS         | `.pkg`                   | Alternate installer; only included when `MAC_SIGNING_IDENTITY` env var is set |
| `maker-squirrel` | Windows       | `.exe` + `win-unpacked/` | No-admin, no-prompt Squirrel installer                                        |
| `maker-zip`      | All platforms | `.zip`                   | Universal fallback; used for auto-update distribution and CI archiving        |
| `maker-deb`      | Linux         | `.deb`                   | Debian / Ubuntu                                                               |
| `maker-rpm`      | Linux         | `.rpm`                   | RHEL / Fedora (Linux hosts only)                                              |
| `maker-flatpak`  | Linux         | Flatpak bundle           | Sandboxed; skipped when `SKIP_FLATPAK=1`                                      |

### `postMake` hook

After every build, the `postMake` hook automatically copies three helper files into each ZIP artifact:

| File                        | Purpose                                                    |
| --------------------------- | ---------------------------------------------------------- |
| `scripts/mac-open.sh`       | Shell script to bypass macOS Gatekeeper on unsigned builds |
| `scripts/win-unblock.ps1`   | PowerShell script to unblock unsigned Windows apps         |
| `scripts/UNSIGNED-BUILD.md` | Instructions for users who receive an unsigned build       |

{% hint style="info" %}
These helpers ensure users always have the workaround at hand when distributing unsigned CI artifacts, without having to find them in docs.
{% endhint %}

## 📦 Building and Distributing

### Build assets only

```bash
npm run build
```

Produces hashed JS and SCSS bundles in `public/includes/resources/` and writes the Vite manifest. This step is required before packaging.

### Package for all platforms

```bash
npm run package:full
```

This runs in sequence:

1. `npm run package:miniserver` — downloads and extracts the BoxLang MiniServer into `runtime/`.
2. `npm run build` — compiles frontend assets.
3. `electron-forge make` — packages and signs the app for the current host platform.

### Package for a specific platform

```bash
# macOS only
npm run package:mac

# Windows only
npm run package:win

# Linux only
npm run package:linux

# Linux via Docker (for cross-platform builds from macOS or Windows)
npm run package:linux:docker
```

Installers land in `dist/electron/`:

| Platform | Outputs                                                   |
| -------- | --------------------------------------------------------- |
| macOS    | `.dmg`, `.pkg` (if `MAC_SIGNING_IDENTITY` is set), `.zip` |
| Windows  | `.exe` (Squirrel installer), `.zip`                       |
| Linux    | `.deb`, `.rpm`, Flatpak bundle, `.zip`                    |

{% hint style="warning" %}
Electron Forge produces platform-specific artifacts. To build a macOS `.dmg` you must be on macOS. Use CI with a matrix build — for example, GitHub Actions with `macos-latest`, `windows-latest`, and `ubuntu-latest` runners — to produce all three platforms from a single pipeline.
{% endhint %}

### Updating the MiniServer version

1. Edit `.bvmrc` to the desired version number.
2. Run `npm run package:miniserver:force`.
3. Rebuild with `npm run package:full`.

## 🔐 Code Signing

Unsigned applications trigger security warnings on both macOS (Gatekeeper) and Windows (SmartScreen). Electron Forge handles signing and notarization at the correct build step automatically once credentials are configured.

{% hint style="warning" %}
Code signing is a **prerequisite for auto-updates on macOS**. Without a valid signing identity, macOS blocks auto-update payloads entirely.
{% endhint %}

### macOS

macOS requires two layers: **code signing** (certifies the author's identity) and **notarization** (Apple's automated malware scan, mandatory since macOS 10.15 Catalina).

#### Prerequisites

1. Purchase a membership in the [Apple Developer Program](https://developer.apple.com/programs/).
2. Obtain a **Developer ID Application** certificate (for distribution outside the Mac App Store).
3. Install it into your keychain via Xcode.
4. Verify it is installed: `security find-identity -p codesigning -v`

#### Configuring `forge.config.cjs`

Add `osxSign` and `osxNotarize` to `packagerConfig`. Both are already stubbed in the starter — supply credentials via environment variables:

```js
packagerConfig: {
    osxSign: {},  // empty object enables signing with auto-detected keychain identity
    osxNotarize: {
        appleId        : process.env.APPLE_ID,
        appleIdPassword: process.env.APPLE_PASSWORD,
        teamId         : process.env.APPLE_TEAM_ID
    }
}
```

{% hint style="danger" %}
Never store credentials in plaintext in `forge.config.cjs`. Always supply them as environment variables or use a stored keychain profile.
{% endhint %}

Alternative `osxNotarize` authentication options:

```js
// Option 2 — App Store Connect API key
osxNotarize: {
    appleApiKey    : process.env.APPLE_API_KEY,
    appleApiKeyId  : process.env.APPLE_API_KEY_ID,
    appleApiIssuer : process.env.APPLE_API_ISSUER
}

// Option 3 — stored keychain profile (created via `notarytool store-credentials`)
osxNotarize: {
    keychainProfile: "my-keychain-profile"
}
```

The starter's `forge.config.cjs` already conditionally includes `maker-pkg` (for `.pkg` output) when `MAC_SIGNING_IDENTITY` is set as an environment variable in CI.

{% embed url="<https://www.electronforge.io/guides/code-signing/code-signing-macos>" %}

### Windows

Windows signing is applied to the installer artifact at the Make step.

#### Prerequisites

1. Obtain a Windows Authenticode certificate (`.pfx`) from a vendor such as [DigiCert](https://www.digicert.com/dc/code-signing/microsoft-authenticode.htm) or [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing).

{% hint style="info" %}
Since June 2023, private keys must be stored on FIPS 140 Level 2+ hardware storage modules. Software-based OV certificates are no longer available for purchase.
{% endhint %}

2. Install Visual Studio (free [Community Edition](https://visualstudio.microsoft.com/vs/community/) is sufficient) to get `signtool.exe`.

#### Configuring `forge.config.cjs`

The `maker-squirrel` config already accepts certificate settings via environment variables:

```js
{
    name   : "@electron-forge/maker-squirrel",
    config : {
        certificateFile    : process.env.WIN_CERT_FILE || undefined,
        certificatePassword: process.env.WIN_CERT_PASS || undefined
    }
}
```

Set `WIN_CERT_FILE` (path to your `.pfx` file) and `WIN_CERT_PASS` in your CI environment or a local `.env` file that is excluded from version control.

#### Azure Trusted Signing (modern cloud alternative)

[Azure Trusted Signing](https://azure.microsoft.com/en-us/products/trusted-signing) is Microsoft's cloud-based signing service and the most cost-effective option for eliminating SmartScreen warnings. Available to US/Canada organizations with 3+ years of verifiable business history.

{% embed url="<https://www.electronforge.io/guides/code-signing/code-signing-windows>" %}

## 🔄 Auto Updates

Electron Forge integrates with Electron's built-in auto-update API. The recommended approach depends on your distribution model.

{% hint style="warning" %}
A **signed application** is required for auto-updates on macOS. Configure code signing before enabling auto-updates.
{% endhint %}

### Open source apps (GitHub)

Open source desktop apps hosted on GitHub can use the free [update.electronjs.org](https://update.electronjs.org) service:

1. Configure the [GitHub Publisher](#publishers) in `forge.config.cjs`.
2. Install the `update-electron-app` package:

```bash
npm install update-electron-app
```

3. Call it at startup in `app/electron/Main.js`:

```js
import { updateElectronApp } from "update-electron-app"
updateElectronApp()
```

### Static storage (S3)

If you use the S3 publisher, refer to its documentation for configuring the app to auto-update from uploaded artifacts.

### Self-hosted update server

For private apps where you need more control (percentage rollouts, multiple release channels):

| Server                                                                            | Publisher to use                    |
| --------------------------------------------------------------------------------- | ----------------------------------- |
| [Nucleus](https://github.com/atlassian/nucleus)                                   | `@electron-forge/publisher-nucleus` |
| [Nuts](https://github.com/GitbookIO/nuts)                                         | GitHub publisher                    |
| [electron-release-server](https://github.com/ArekSredzki/electron-release-server) | Electron Release Server publisher   |
| [Hazel](https://github.com/vercel/hazel)                                          | GitHub publisher                    |

{% embed url="<https://www.electronforge.io/advanced/auto-update>" %}

## 🐛 Debugging

Electron apps have two separate processes, each with its own debugging approach.

### Renderer process (Chromium DevTools)

Open DevTools from inside the running app:

* **Keyboard shortcut**: `Ctrl+Shift+I` (Windows/Linux) or `Cmd+Option+I` (macOS)
* **App menu**: View → Developer Tools (registered by `AppMenu.js`)

### Main process — command line

Use the `--inspect-electron` flag when starting via Forge:

```bash
npm run dev -- --inspect-electron
```

Then open [chrome://inspect](chrome://inspect/) in any Chromium-based browser and click **inspect** next to your app to attach a debugger. Use `--inspect-brk-electron` to pause at the very first line of execution.

### Main process — VS Code

Add a launch configuration to `.vscode/launch.json`:

```json
{
    "configurations": [
        {
            "type"             : "node",
            "request"          : "launch",
            "name"             : "Electron Main",
            "runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.sh",
            "windows": {
                "runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.cmd"
            },
            "cwd"    : "${workspaceFolder}",
            "console": "integratedTerminal"
        }
    ]
}
```

Open the **Run and Debug** view (`Ctrl+Shift+D`), select **Electron Main**, and press **F5** to start debugging with full breakpoint support.

### BoxLang template debugging

* Enable `"debugMode": true` in `.boxlang-dev.json` for stack traces in BoxLang template output.
* Check the MiniServer log piped to the Electron terminal for request errors.

{% embed url="<https://www.electronforge.io/advanced/debugging>" %}

## 📤 Publishers

Publishers take the artifacts produced by `electron-forge make` and upload them to a distribution service. Configure them in the `publishers` array of `forge.config.cjs`:

```js
module.exports = {
    // ...
    publishers: [
        {
            name  : "@electron-forge/publisher-github",
            config: {
                repository: { owner: "your-org", name: "your-repo" },
                prerelease: false
            }
        }
    ]
};
```

Run publishing with:

```bash
npx electron-forge publish
```

### Available publishers

| Publisher               | Package                                             | Best for                                                              |
| ----------------------- | --------------------------------------------------- | --------------------------------------------------------------------- |
| GitHub Releases         | `@electron-forge/publisher-github`                  | Open source; pairs with `update.electronjs.org` for free auto-updates |
| Amazon S3               | `@electron-forge/publisher-s3`                      | Private distribution + S3-hosted auto-updates                         |
| Electron Release Server | `@electron-forge/publisher-electron-release-server` | Self-hosted update server                                             |
| Nucleus                 | `@electron-forge/publisher-nucleus`                 | Full-featured self-hosted update + release management                 |
| Bitbucket               | `@electron-forge/publisher-bitbucket`               | Bitbucket-hosted distribution                                         |

{% hint style="info" %}
All publishers default to publishing artifacts for all platforms. Add a `platforms` key to restrict which platform artifacts a specific publisher uploads.
{% endhint %}

{% embed url="<https://www.electronforge.io/config/publishers>" %}

## 🌍 Cross-Platform Considerations

| Topic                      | Notes                                                                                                                               |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| **Java 21+**               | Must be installed separately on every target machine — the installer does not bundle a JRE                                          |
| **Executable permissions** | On macOS/Linux, `BoxLang.js` automatically runs `chmod +x` on the MiniServer binary at startup if needed                            |
| **Paths**                  | Always use `path.join()` in Electron code — never string concatenate paths directly                                                 |
| **Icons**                  | Supply `.icns` (macOS), `.ico` (Windows), and `.png` (Linux) variants; use `npm run generate:icons` to regenerate from a source PNG |
| **App ID**                 | Use a reverse-domain identifier (e.g. `com.example.myapp`) for proper OS registration                                               |
| **Port**                   | Pick a port above 49152 for the local MiniServer to avoid conflicts with system services                                            |

## 🔧 Troubleshooting

### Server fails to start

* Run `npm run package:miniserver` to ensure `runtime/bin` and `runtime/lib` exist.
* If using global fallback, verify `boxlang-miniserver` is on your `PATH` with `which boxlang-miniserver`.
* Confirm the port in `miniserver.json` is not in use: `lsof -i :59700`.

### Permission denied on macOS/Linux

* Run `npm run package:miniserver:force` to re-extract with correct permissions.
* Manually fix with `chmod +x runtime/bin/boxlang-miniserver`.

### Missing production assets

* Run `npm run build` and confirm `public/includes/resources/.vite/manifest.json` exists.
* Check the Vite build for errors in the terminal output.

### App works in dev but fails after packaging

* Confirm Java 21+ is installed on the target machine.
* Open the packaged app's log file (macOS: `~/Library/Logs/<AppName>/main.log`; Windows: `%APPDATA%\<AppName>\logs\main.log`) for startup errors.
* Verify that `asar: false` is set in `forge.config.cjs` so the runtime files are accessible to the child process.

### BoxLang template errors

* Enable debug mode in `.boxlang-dev.json` (`"debugMode": true`) to see stack traces in the BoxLang output.
* Open Electron DevTools with `Ctrl+Shift+I` (or the **View → Developer Tools** menu item) to inspect the page.

## 📚 Resources

### BoxLang

* [BoxLang Documentation](https://boxlang.ortusbooks.com)
* [BoxLang MiniServer](/getting-started/running-boxlang/miniserver)
* [BoxLang Web Development](https://github.com/ortus-boxlang/boxlang-docs/tree/v1.x/boxlang-framework/getting-started.md)
* [Application.bx Reference](/boxlang-framework/applicationbx)
* [JDBC / Database Access](/boxlang-framework/jdbc)

### Electron

* [Electron Documentation](https://www.electronjs.org/docs/latest)
* [BrowserWindow API](https://www.electronjs.org/docs/latest/api/browser-window)
* [app lifecycle API](https://www.electronjs.org/docs/latest/api/app)
* [Menu and MenuItem API](https://www.electronjs.org/docs/latest/api/menu)
* [Tray API](https://www.electronjs.org/docs/latest/api/tray)
* [globalShortcut API](https://www.electronjs.org/docs/latest/api/global-shortcut)
* [NativeImage API](https://www.electronjs.org/docs/latest/api/native-image)
* [Electron Forge](https://www.electronforge.io/)
* [Code Signing (macOS)](https://www.electronforge.io/guides/code-signing/code-signing-macos)
* [Code Signing (Windows)](https://www.electronforge.io/guides/code-signing/code-signing-windows)
* [Auto Update](https://www.electronforge.io/advanced/auto-update)
* [Debugging](https://www.electronforge.io/advanced/debugging)
* [Publishers](https://www.electronforge.io/config/publishers)

### Frontend

* [Vite](https://vite.dev/)
* [Alpine.js](https://alpinejs.dev/)
* [Bootstrap 5](https://getbootstrap.com/docs/5.3/)


# Docker

Containerize all things with BoxLang - Professional Docker images for development and production

<figure><img src="/files/VYSAp0ee96xga1S1kwJ5" alt="BoxLang Docker"><figcaption><p>Professional BoxLang Docker images for modern containerized deployments</p></figcaption></figure>

BoxLang provides professional Docker images designed for both development and production use. Our containers are built on enterprise-grade base images with security patches, optimized for performance, and include comprehensive tooling for modern containerized applications.

## 📦 Available Images

You can find all our published images and tags here: <https://hub.docker.com/r/ortussolutions/boxlang>.

### **Core Image Types**

* **CLI Images**: [ortussolutions/boxlang:cli](https://hub.docker.com/r/ortussolutions/boxlang/tags?page=1\&name=cli) - Full BoxLang CLI runtime
* **MiniServer Images**: [ortussolutions/boxlang:miniserver](https://hub.docker.com/r/ortussolutions/boxlang/tags?page=1\&name=miniserver) - Lightweight web server
* **MiniServer + Nginx**: [ortussolutions/boxlang:miniserver-nginx](https://hub.docker.com/r/ortussolutions/boxlang/tags?page=1\&name=miniserver-nginx) - Production-ready with reverse proxy

### **Base Variants**

Each image type is available in multiple variants:

* **Debian Linux** (default) - Full-featured, enterprise-ready
* **Alpine Linux** (`-alpine` suffix) - Minimal, security-focused
* **Snapshot versions** (`-snapshot` suffix) - Latest development builds

## 🖥️ CLI Images

The CLI images contain the complete BoxLang CLI runtime, allowing you to run scripts, CLI applications, schedulers, and OS integrations. Perfect for development, CI/CD pipelines, and automated tasks.

### **Available CLI Tags**

* `ortussolutions/boxlang:cli` - Latest stable CLI on Debian Linux
* `ortussolutions/boxlang:cli-alpine` - Latest stable CLI on Alpine Linux
* `ortussolutions/boxlang:cli-snapshot` - Development snapshot on Debian Linux
* `ortussolutions/boxlang:cli-alpine-snapshot` - Development snapshot on Alpine Linux

### **CLI Usage Examples**

```bash
# Pull the latest BoxLang CLI image
docker pull ortussolutions/boxlang:cli

# Check BoxLang version
docker run --rm -it ortussolutions/boxlang:cli boxlang --version

# Run the BoxLang REPL
docker run --rm -it ortussolutions/boxlang:cli boxlang

# Execute a quick code snippet
docker run --rm -it ortussolutions/boxlang:cli boxlang --bx-code "println( 'Hello, BoxLang!' )"

# Run a Task.bx script from your local directory
docker run --rm -it -v $(pwd):/app ortussolutions/boxlang:cli boxlang /app/Task.bx

# Run a Scheduler.bx script
docker run --rm -it -v $(pwd):/app ortussolutions/boxlang:cli boxlang /app/Scheduler.bx

# Development with volume mounting
docker run --rm -it -v $(pwd):/app -w /app ortussolutions/boxlang:cli boxlang your-script.bx
```

## 🌐 MiniServer Images

The MiniServer images contain the BoxLang MiniServer - a lightweight, high-performance web server designed for running BoxLang web applications, APIs, and microservices. Perfect for development, testing, and production deployments.

### **Available MiniServer Tags**

* `ortussolutions/boxlang:miniserver` - Latest stable MiniServer on Debian Linux
* `ortussolutions/boxlang:miniserver-alpine` - Latest stable MiniServer on Alpine Linux
* `ortussolutions/boxlang:miniserver-snapshot` - Development snapshot on Debian Linux
* `ortussolutions/boxlang:miniserver-alpine-snapshot` - Development snapshot on Alpine Linux

### **Key Features**

* **Auto-serving**: The MiniServer loads `/app` as the webroot directory
* **Default files**: Automatically serves `index.bxm` files
* **URL Rewrites**: Enabled by default with configurable rewrite files
* **Health checks**: Built-in health monitoring for container orchestration
* **Hot reload**: Development mode with automatic code reloading
* **MiniServer JSON Config**: Supports a `miniserver.json` configuration file for full server configuration

### **MiniServer Usage Examples**

```bash
# Pull the latest BoxLang MiniServer image
docker pull ortussolutions/boxlang:miniserver

# Run a basic web server (browse to http://localhost:8080)
docker run --rm -it -p 8080:8080 ortussolutions/boxlang:miniserver

# Mount your application directory
docker run --rm -it -p 8080:8080 -v $(pwd):/app ortussolutions/boxlang:miniserver

# Run in debug mode with environment variables
docker run --rm -it -p 8080:8080 \
  -e BOXLANG_DEBUG=true \
  -e JAVA_OPTS="-Xmx1g -Xms512m" \
  -v $(pwd):/app ortussolutions/boxlang:miniserver

# Load a custom boxlang.json configuration
docker run --rm -it -p 8080:8080 \
  -v $(pwd):/app \
  -v $(pwd)/boxlang.json:/root/.boxlang/config/boxlang.json \
  ortussolutions/boxlang:miniserver

# Use a miniserver.json config file auto-detected from /app (place it there and it loads automatically)
docker run --rm -it -p 8080:8080 -v $(pwd):/app ortussolutions/boxlang:miniserver

# Use a miniserver.json at a custom/explicit path
docker run --rm -it -p 8080:8080 \
  -e MINISERVER_JSON=/app/config/miniserver.json \
  -v $(pwd):/app \
  ortussolutions/boxlang:miniserver

# Production deployment with custom memory settings
docker run -d --name boxlang-app \
  -p 80:8080 \
  -e MAX_MEMORY=2g \
  -e MIN_MEMORY=1g \
  -v /path/to/app:/app \
  ortussolutions/boxlang:miniserver
```

### **Health Check**

All MiniServer images include built-in health checks that monitor the server's status:

* **Interval**: 20 seconds
* **Timeout**: 30 seconds
* **Retries**: 15 attempts before marking as unhealthy
* **Endpoint**: Configurable via `HEALTHCHECK_URI` (default: `http://127.0.0.1:8080/`)

## 📦 Module Installation

The images include an automated module installer via the `BOXLANG_MODULES` environment variable. Modules are downloaded and installed at container startup.

### **Docker Compose Example**

```yaml
version: "3.8"

services:
  boxlang-app:
    image: ortussolutions/boxlang:miniserver
    environment:
      - BOXLANG_DEBUG=true
      - BOXLANG_MODULES=bx-compat-cfml,bx-esapi,bx-mysql,bx-redis
      - MAX_MEMORY=1g
      - MIN_MEMORY=512m
    volumes:
      - ./src:/app
      - ./config/boxlang.json:/root/.boxlang/config/boxlang.json
    ports:
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "--fail", "http://localhost:8080/"]
      interval: 30s
      timeout: 10s
      retries: 3
```

### **Available Modules**

Common modules you can install:

* `bx-compat-cfml` - ColdFusion/CFML compatibility layer
* `bx-mysql` - MySQL database connectivity
* `bx-esapi` - Enterprise Security API
* `bx-redis` - Redis cache and session storage
* `bx-mail` - Email functionality
* `bx-derby` - Derby database (development)

## ⚙️ Environment Variables

The following environment variables can be used to configure the BoxLang Docker images:

### **Core Configuration**

* `BOXLANG_CONFIG_PATH` - Path to BoxLang configuration file (default: `/root/.boxlang/config/boxlang.json`)
* `BOXLANG_DEBUG` - Enable debugging mode (default: `false`)
* `BOXLANG_HOME` - BoxLang installation home directory (default: `/root/.boxlang`)
* `BOXLANG_HOST` - Server host binding (default: `0.0.0.0`)
* `BOXLANG_MODULES` - Comma-separated list of modules to install (example: `bx-compat-cfml,bx-mysql`)
* `BOXLANG_PORT` - Server port binding (default: `8080`)

### **Server & Performance**

* `DEBUG` - Legacy debug mode flag (default: `false`)
* `JAVA_OPTS` - JVM options (default: `-Djava.awt.headless=true`)
* `HEALTHCHECK_URI` - Health check endpoint (default: `http://127.0.0.1:${PORT}/`)
* `HOST` - Server host (alias for BOXLANG\_HOST)
* `MAX_MEMORY` - Maximum heap size (default: `512m`, example: `2g`)
* `MIN_MEMORY` - Minimum heap size (default: `512m`, example: `1g`)
* `PORT` - Server port (alias for BOXLANG\_PORT)

### **Web Server Features**

* `REWRITES` - Enable URL rewrites (default: `true`)
* `REWRITE_FILE` - Rewrite target file (default: `index.bxm`)
* `MINISERVER_JSON` - Path to a `miniserver.json` configuration file. If set, it is passed as the first argument to `boxlang-miniserver`. If not set, the server auto-detects a `miniserver.json` in `/app` (default: \`\`)

### **BoxLang Environment Override**

{% hint style="info" %} BoxLang supports overriding any configuration setting via environment variables using the `BOXLANG_` prefix. For complete documentation, see [Environment Variable Substitution](https://boxlang.ortusbooks.com/getting-started/configuration#environment-variable-substitution).

Examples:

* `BOXLANG_DEBUGMODE=true`
* `BOXLANG_RUNTIME_CLASSGENERATION_ENABLED=false`
* `BOXLANG_RUNTIME_CUSTOMTAGSPATHS=/custom/tags` {% endhint %}

## 🚀 Production: MiniServer with Nginx

For production deployments, we provide an experimental image combining BoxLang MiniServer with Nginx as a reverse proxy. This setup provides static file serving, SSL termination, and production-grade performance optimizations.

{% hint style="warning" %} **Experimental Feature**: The Nginx integration is currently experimental and not recommended for critical production workloads. Use with caution and thorough testing. {% endhint %}

### **Available Tags**

* `ortussolutions/boxlang:miniserver-nginx` - Nginx + MiniServer on Debian Linux

### **Nginx Configuration**

* **HTTP Port**: 80 (configurable via `NGINX_PORT`)
* **HTTPS Port**: 443 (configurable via `NGINX_SSL_PORT`)
* **SSL Certificate**: Self-signed certificate included
* **Custom SSL**: Mount your certificates to `/etc/nginx/ssl/`
* **Optimizations**: Production-tuned Nginx configuration for BoxLang

### **Custom SSL Certificates**

```bash
# Generate custom self-signed certificate
openssl req -x509 -nodes -newkey rsa:2048 \
    -days 365 \
    -subj "/CN=yourdomain.com" \
    -keyout ./ssl/server.key \
    -out ./ssl/server.crt

# Run with custom SSL
docker run -d -p 80:80 -p 443:443 \
  -v $(pwd):/app \
  -v $(pwd)/ssl:/etc/nginx/ssl \
  ortussolutions/boxlang:miniserver-nginx
```

### **Nginx Environment Variables**

* `NGINX_PORT` - HTTP port for Nginx (default: `80`)
* `NGINX_SSL_PORT` - HTTPS port for Nginx (default: `443`)

## 🔧 Source Code & Contributing

### **Docker Images Repository**

The complete source code for all BoxLang Docker images is available at: <https://github.com/ortus-boxlang/boxlang-docker>

This repository contains:

* **Dockerfiles** for all image variants
* **Build scripts** and automation
* **Nginx configurations** for production deployments
* **Testing infrastructure** and examples
* **Documentation** and contribution guidelines

### **Image Build Process**

* **Base Images**: Eclipse Temurin JRE 21 (Debian Noble & Alpine)
* **Security**: Regular security updates and dependency patching
* **Installation**: Uses BoxLang's official quick installer
* **Optimization**: Multi-stage builds for minimal image sizes
* **Testing**: Automated testing for all image variants

### **Contributing**

We welcome contributions to improve the Docker images:

1. **Issues**: Report bugs or request features in the GitHub repository
2. **Pull Requests**: Follow the contributing guidelines in the repo
3. **Documentation**: Help improve documentation and examples
4. **Testing**: Test images in different environments and report feedback

{% hint style="success" %}
**Professional Support**: For enterprise Docker deployments, BoxLang+ and BoxLang++ subscribers receive priority support, custom image builds, and deployment assistance. Visit [boxlang.io/plans](https://boxlang.io/plans) for more information.
{% endhint %}


# GitHub Actions

Run BoxLang in your GitHub Actions seamlessly with the official setup action.

🚀 **Automate your BoxLang setup** - This GitHub Action sets up the BoxLang Dynamic JVM Language runtime for CI/CD workflows with optional CommandBox CLI and module installation (<https://github.com/marketplace/actions/setup-boxlang-cli>)

{% embed url="<https://github.com/marketplace/actions/setup-boxlang-cli>" %}

## ⌨️ Action Inputs

Configure your BoxLang setup using these input parameters:

<table><thead><tr><th width="184.050537109375">Input</th><th width="88.269775390625">Type</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td><code>boxlang_home</code></td><td>string</td><td><code>${GITHUB_WORKSPACE}/.boxlang</code></td><td>Custom directory for BoxLang installation. Defaults to a writable directory in the workspace to avoid read-only filesystem issues.</td></tr><tr><td><code>commandbox_version</code></td><td>string</td><td><code>latest</code></td><td>The CommandBox version to install. Only used if <code>with-commandbox</code> is true.</td></tr><tr><td><code>commandbox_modules</code></td><td>string</td><td>---</td><td>If added, a comma-delimited list of CommandBox packages to install. Only used if <code>with-commandbox</code> is true.</td></tr><tr><td><code>forgeboxAPIKey</code></td><td>string</td><td>---</td><td>If added, it will configure the ForgeBox API Key in CommandBox. Only used if <code>with-commandbox</code> is true.</td></tr><tr><td><code>modules</code></td><td>string</td><td>---</td><td>If added, a space-delimited list of modules to install upon installation of the binary for you.</td></tr><tr><td><code>with-commandbox</code></td><td>boolean</td><td><code>false</code></td><td>If true, it will install the latest CommandBox as well.</td></tr><tr><td><code>version</code></td><td>semver</td><td><code>latest</code></td><td>The BoxLang version to install, if not passed we use the latest stable.</td></tr></tbody></table>

{% hint style="info" %}
**Version Options**:

* `latest` - Latest stable release
* `snapshot` - Latest development build
* `1.2.0` - Specific version number
* `1.x` - Latest in major version series
  {% endhint %}

## 🔳 Usage Examples

### Simple Setup

```yaml
- name: Setup BoxLang
  uses: ortus-boxlang/setup-boxlang@main
```

### 📦 With BoxLang Modules

```yaml
- name: Setup BoxLang
  uses: ortus-boxlang/setup-boxlang@main
  with:
    modules: bx-ai bx-orm bx-pdf
```

### 🎯 Specific Version

```yaml
- name: Setup BoxLang with specific version
  uses: ortus-boxlang/setup-boxlang@main
  with:
    version: snapshot
```

### 📦 With CommandBox

```yaml
- name: Setup BoxLang with CommandBox
  uses: ortus-boxlang/setup-boxlang@main
  with:
    with-commandbox: true
```

### 🔧 CommandBox with Specific Version

```yaml
- name: Setup BoxLang with specific CommandBox version
  uses: ortus-boxlang/setup-boxlang@main
  with:
    with-commandbox: true
    commandbox_version: 6.0.0
```

### 🛠️ CommandBox with Modules

```yaml
- name: Setup BoxLang with CommandBox and modules
  uses: ortus-boxlang/setup-boxlang@main
  with:
    with-commandbox: true
    commandbox_modules: commandbox-cfconfig,commandbox-dotenv
```

### ⚙️ Full Configuration Example

```yaml
- name: Setup BoxLang with CommandBox (full setup)
  uses: ortus-boxlang/setup-boxlang@main
  with:
    with-commandbox: true
    commandbox_version: 6.0.0
    commandbox_modules: commandbox-cfconfig,commandbox-dotenv,commandbox-fusionreactor
```

### 🔑 With ForgeBox API Key

```yaml
- name: Setup BoxLang with CommandBox and ForgeBox API Key
  uses: ortus-boxlang/setup-boxlang@main
  with:
    with-commandbox: true
    forgeboxAPIKey: ${{ secrets.FORGEBOX_API_KEY }}
```

### 🎯 Specific Version with Modules

```yaml
- name: Setup BoxLang with specific version
  uses: ortus-boxlang/setup-boxlang@main
  with:
    version: 1.2.0
    modules: bx-compat-cfml bx-mail
```

## 📦 Action Outputs

This action provides the following outputs for use in subsequent workflow steps:

* `boxlang-version`: The version of BoxLang that was installed
* `installation-path`: The path where BoxLang was installed

## 🔧 Complete CI/CD Examples

### Quick Start Example

```yaml
name: BoxLang CI/CD

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v6

    - name: Set up BoxLang
      uses: ortus-boxlang/setup-boxlang@main
      with:
        version: latest
        modules: "bx-compat-cfml bx-mail"

    - name: Run BoxLang Tests
      run: boxlang test-runner.bx

    - name: Run BoxLang Application
      run: boxlang app.bx
```

### Web Application Testing

```yaml
name: BoxLang Web App CI

on:
  push:
    branches: [ main, development ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        boxlang-version: [latest, snapshot]

    steps:
    - name: Checkout repository
      uses: actions/checkout@v6

    - name: Setup BoxLang ${{ matrix.boxlang-version }}
      uses: ortus-boxlang/setup-boxlang@main
      with:
        version: ${{ matrix.boxlang-version }}
        modules: "bx-compat-cfml bx-mysql bx-mail bx-esapi"

    - name: Verify BoxLang Installation
      run: |
        boxlang --version
        boxlang --bx-code "println( 'BoxLang is ready!' )"

    - name: Run Unit Tests
      run: boxlang tests/runner.bx

    - name: Run Integration Tests
      run: boxlang tests/integration-suite.bx
      env:
        DB_HOST: localhost
        DB_NAME: testdb
```

### Module Development Workflow

```yaml
name: BoxLang Module Development

on:
  push:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout module source
      uses: actions/checkout@v6

    - name: Setup BoxLang with Development Dependencies
      uses: ortus-boxlang/setup-boxlang@main
      with:
        version: snapshot
        modules: "bx-compat-cfml"

    - name: Install Module Dependencies
      run: |
        # Install any required dependencies for your module
        boxlang install-module.bx

    - name: Run Module Tests
      run: boxlang test-runner.bx

    - name: Verify Module API
      run: boxlang api-tests.bx

    - name: Package Module
      run: boxlang build-module.bx

    - name: Upload Module Artifacts
      uses: actions/upload-artifact@v3
      with:
        name: boxlang-module-${{ github.sha }}
        path: dist/
```

### Multi-Platform Testing

```yaml
name: Cross-Platform BoxLang Testing

on: [push, pull_request]

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        boxlang-version: [latest, "1.4.0"]

    runs-on: ${{ matrix.os }}

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup BoxLang on ${{ matrix.os }}
      uses: ortus-boxlang/setup-boxlang@main
      with:
        version: ${{ matrix.boxlang-version }}
        modules: "bx-compat-cfml bx-mail"

    - name: Run Platform-Specific Tests
      run: boxlang tests/platform-tests.bx
      shell: bash  # Ensures consistent shell across platforms
```

### Enterprise CommandBox Deployment

```yaml
name: Enterprise BoxLang Deployment

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout application
      uses: actions/checkout@v4

    - name: Setup BoxLang with CommandBox
      uses: ortus-boxlang/setup-boxlang@main
      with:
        version: latest
        with-commandbox: true
        modules: "bx-compat-cfml bx-orm bx-mysql bx-redis"

    - name: Verify CommandBox Installation
      run: |
        box version
        boxlang --version

    - name: Build Application Package
      run: |
        box package build
        box server start --dryRun

    - name: Run Application Tests
      run: |
        box testbox run
        boxlang integration-tests.bx
```

## 🐛 Troubleshooting

### Common Issues

**Action fails with Java not found:**

* The action automatically installs OpenJDK 21. If you see Java errors, try updating to the latest action version.

**Module installation timeout:**

* Large modules may take time to install. Consider caching or installing only necessary modules.

**Permission errors on Windows:**

* Ensure your workflow has proper permissions set for the Windows runner.

### Debug Mode

Enable debug output for troubleshooting:

```yaml
- name: Setup BoxLang with Debug
  uses: ortus-boxlang/setup-boxlang@main
  with:
    version: latest
    modules: "bx-compat-cfml"
  env:
    ACTIONS_RUNNER_DEBUG: true
```


# Google Cloud Functions

Run BoxLang on Google Cloud Functions with the official starter and runtime

Run BoxLang handlers on Google Cloud Functions Gen 2 using the Java 21 runtime and the BoxLang GCF bridge entry point: `ortus.boxlang.runtime.gcp.FunctionRunner`.

This page matches the current starter project and runtime behavior.

## 🚀 What You Get

* BoxLang handler files in `src/main/bx`
* Convention-based routing from URI to handler class
* Local HTTP server via the Google Functions Java Invoker
* Deployable ZIP with handlers, config, modules, and runtime JAR

## 🏛️ Runtime + Starter Architecture

This experience is intentionally a combination of two projects:

* **Starter project** (`boxlang-starter-google-functions`): your app shell, handlers, tests, and Gradle tasks
* **Runtime project** (`boxlang-google-functions`): the Java bridge that adapts GCF HTTP requests to BoxLang execution

The runtime entry point is:

* `ortus.boxlang.runtime.gcp.FunctionRunner`

At execution time, the runtime handles:

* HTTP request mapping into a BoxLang-friendly `event` struct
* route resolution from URI to `.bx` handler file
* class compilation/loading and warm-invocation class caching
* method dispatch (default `run()` or `x-bx-function` override)
* response mapping from BoxLang `response` struct to GCF HTTP output

This split lets you keep all business logic in BoxLang files while using Java only as the serverless runtime bridge.

## 🔬 Runtime Execution Flow

```
HTTP Request
    -> Google Cloud Functions Gen 2 (java21)
    -> FunctionRunner (HttpFunction)
    -> RequestMapper (HttpRequest -> event struct)
    -> Route resolution (first URI segment -> PascalCase -> .bx file)
    -> Handler compilation/load (cached on warm invocations)
    -> Method resolution (x-bx-function header or run)
    -> BoxLang handler method execution
    -> ResponseMapper (response struct -> HttpResponse)
```

## ⚡ Cold Start, Warm Start, and Debug Mode

* **Cold start:** runtime initializes in the container before first request handling.
* **Warm invocations:** compiled handler classes are reused to avoid repeated compilation work.
* **Debug mode (`BOXLANG_GCP_DEBUGMODE=true`):** class caching is disabled so handler edits are picked up quickly during development.
* **Production guidance:** keep debug mode off for best performance.

## 🔁 Portability Notes

The runtime keeps the handler contract familiar across serverless targets. In practice, many handler patterns can be shared between BoxLang AWS Lambda and BoxLang GCF with minimal changes.

## ✅ Requirements

| Requirement                 | Version          |
| --------------------------- | ---------------- |
| Java                        | 21               |
| Google Cloud SDK (`gcloud`) | Latest           |
| Gradle                      | Wrapper included |

## 📦 Starter Project Setup

Use the official starter:

```bash
git clone https://github.com/ortus-boxlang/boxlang-starter-google-functions.git
cd boxlang-starter-google-functions
```

Run tests once to verify your environment:

```bash
./gradlew clean test
```

## 🧪 Launch Locally

Start the local function server:

```bash
./gradlew runFunction
```

By default it runs on port `9099` and uses `src/main/bx` as the function root.

Try a request:

```bash
curl http://localhost:9099/
```

Call a specific method via header:

```bash
curl -H "x-bx-function: anotherLambda" http://localhost:9099/
```

Send JSON payload:

```bash
curl -X POST http://localhost:9099/ \
  -H "Content-Type: application/json" \
  -d @workbench/sampleRequests/event-local.json
```

### Local overrides

```bash
./gradlew runFunction -PtestPort=8080
./gradlew runFunction -PdebugMode=true
./gradlew runFunction -PfunctionRoot=/absolute/path/to/bx/files
```

### Local `runFunction` Runner Details

The starter's `runFunction` Gradle task uses the official Google Functions Java Invoker and wires it to the BoxLang runtime entry point.

What it does:

* launches `com.google.cloud.functions.invoker.runner.Invoker`
* passes `ortus.boxlang.runtime.gcp.FunctionRunner` as the target
* sets `BOXLANG_GCP_ROOT` to your function root (default: `src/main/bx`)
* sets `BOXLANG_GCP_DEBUGMODE` from `-PdebugMode` or defaults
* runs on `-PtestPort` (default `9099`)

Expected startup banner:

```
================================================================
 BoxLang GCF Function Invoker
 Listening on  : http://localhost:9099
 Function root : .../src/main/bx
 Debug mode    : true|false
 Press Ctrl+C to stop.
================================================================
```

Runner troubleshooting:

* **Port in use:** start with `-PtestPort=8080`
* **Wrong handlers loaded:** point to the right folder with `-PfunctionRoot=...`
* **Code changes not reflected:** use `-PdebugMode=true` during development
* **Missing default route:** ensure `Lambda.bx` exists in the configured function root

## 🧩 Handler Contract

Each handler method receives:

* `event`: HTTP request data mapped into a struct
* `context`: function metadata (name, revision, project, request id)
* `response`: mutable response struct (`statusCode`, `headers`, `body`, `cookies`)

Default method is `run()`.

### Event Struct Shape

The runtime maps each incoming HTTP request into an `event` struct designed for serverless portability.

```js
{
    method: "GET",
    path: "/products/42",
    rawPath: "/products/42",
    headers: {
        "content-type": "application/json"
    },
    queryStringParameters: {
        page: "1"
    },
    body: "",
    requestContext: {
        http: {
            method: "GET",
            path: "/products/42"
        }
    }
}
```

### Context Struct Shape

The `context` struct contains runtime metadata:

* `functionName`
* `functionVersion`
* `projectId`
* `requestId`

### Response Struct Shape

The runtime provides a mutable `response` struct:

```js
{
    statusCode: 200,
    headers: {
        "Content-Type": "application/json"
    },
    body: "",
    cookies: []
}
```

Response behavior:

* Returning a struct or array from your method will be JSON serialized.
* Returning a plain string writes that string as the response body.
* Writing to `response.body` gives explicit control over output.

### Example handler

```js
class {

    function run( event, context, response ) {
        response.statusCode = 200
        response.body = {
            "error": false,
            "messages": [],
            "data": "====> Incoming event " & event.toString()
        }
    }

    function anotherLambda( event, context, response ) {
        return "Hola!!"
    }

}
```

## 🛣️ Convention-Based Routing

The runtime supports multi-routing by resolving the first URI path segment into a PascalCase `.bx` handler file.

Routing algorithm:

1. Read the first path segment from the request URI.
2. Convert it to PascalCase.
3. Look for `<Segment>.bx` under `BOXLANG_GCP_ROOT`.
4. Fall back to `Lambda.bx` if no file is found.

### URI to Handler Mapping

| Request URI      | Resolved Handler  |
| ---------------- | ----------------- |
| `/`              | `Lambda.bx`       |
| `/customers`     | `Customers.bx`    |
| `/customers/123` | `Customers.bx`    |
| `/products`      | `Products.bx`     |
| `/user-profiles` | `UserProfiles.bx` |
| `/api_endpoints` | `ApiEndpoints.bx` |
| `/unknown`       | `Lambda.bx`       |

### Multi-Handler Layout

```
src/main/bx/
  Application.bx
  Lambda.bx        # fallback and root route
  Customers.bx     # handles /customers/**
  Products.bx      # handles /products/**
  UserProfiles.bx  # handles /user-profiles/**
```

The first segment selects the class. Remaining URI segments are still available via `event.path` for your own parsing.

### Multi-Routing Handler Example

```js
class {

    function run( event, context, response ) {
        response.statusCode = 200
        response.body = {
            "error": false,
            "resource": "customers",
            "path": event.path,
            "method": event.method
        }
    }

    function findById( event, context, response ) {
        response.statusCode = 200
        response.body = {
            "error": false,
            "action": "findById",
            "path": event.path
        }
    }

}
```

## 🔀 Method Routing with x-bx-function

After URI routing resolves the handler class, method routing can choose which function to invoke.

* Without header, runtime calls `run()`.
* With header, runtime attempts the named method.

```bash
# Lambda.bx::run()
curl http://localhost:9099/

# Lambda.bx::anotherLambda()
curl -H "x-bx-function: anotherLambda" http://localhost:9099/

# Customers.bx::findById() when /customers resolves class
curl -H "x-bx-function: findById" http://localhost:9099/customers/123
```

This gives you two dispatch layers:

* URI path selects the handler class
* `x-bx-function` selects the method in that class

## ⚙️ Runtime Environment Variables

| Variable                | Purpose                                          |
| ----------------------- | ------------------------------------------------ |
| `BOXLANG_GCP_ROOT`      | Root directory for `.bx` handlers                |
| `BOXLANG_GCP_CLASS`     | Override default handler path                    |
| `BOXLANG_GCP_DEBUGMODE` | Enable verbose logging and disable class caching |
| `BOXLANG_GCP_CONFIG`    | Custom `boxlang.json` path                       |
| `K_SERVICE`             | Function name (set by GCF)                       |
| `K_REVISION`            | Function revision (set by GCF)                   |
| `GOOGLE_CLOUD_PROJECT`  | Project ID (set by GCF)                          |

## 🏗️ Build Deployable Artifacts

Build the GCF package:

```bash
./gradlew clean shadowJar buildLambdaZip
```

Output ZIP:

* `build/distributions/boxlang-google-function-project-<version>.zip`

The ZIP includes:

* `.bx` handlers at ZIP root
* `boxlang.json`
* `boxlang_modules/`
* `lib/` with runtime and dependencies

## ☁️ Deploy to Google Cloud Functions Gen 2

Authenticate and select project:

```bash
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
```

Deploy:

```bash
gcloud functions deploy YOUR_FUNCTION_NAME \
  --gen2 \
  --runtime=java21 \
  --region=us-central1 \
  --entry-point=ortus.boxlang.runtime.gcp.FunctionRunner \
  --trigger-http \
  --allow-unauthenticated \
  --source=build/distributions/boxlang-google-function-project-1.0.0.zip
```

If you changed `version` in `gradle.properties`, update the ZIP filename in `--source`.

## 🧪 Testing

Run tests:

```bash
./gradlew test
```

Run the integration test class:

```bash
./gradlew test --tests "com.myproject.FunctionRunnerTest"
```

Open report:

* `build/reports/tests/test/index.html`

### Unit and Integration Tests Shipped in the Starter

The starter currently ships one primary integration test class and two GCF HTTP mock classes:

| File                                                      | Purpose                                                         |
| --------------------------------------------------------- | --------------------------------------------------------------- |
| `src/test/java/com/myproject/FunctionRunnerTest.java`     | End-to-end tests of request -> BoxLang handler -> HTTP response |
| `src/test/java/com/myproject/mocks/MockHttpRequest.java`  | Fluent test request builder implementing GCF `HttpRequest`      |
| `src/test/java/com/myproject/mocks/MockHttpResponse.java` | Captures status/body/headers implementing GCF `HttpResponse`    |

`FunctionRunnerTest` validates:

* missing handler path error behavior
* default `run()` execution and JSON response assertions
* `x-bx-function` method routing (`anotherLambda`)
* response headers (`Content-Type`)
* empty headers and large-body handling
* query parameter handling
* concurrent invocation behavior
* core accessor behavior (`getDefaultFunctionPath`, `inDebugMode`, `getRuntime`)

Run only the shipped integration test:

```bash
./gradlew test --tests "com.myproject.FunctionRunnerTest"
```

## 📝 Notes

* The starter currently keeps handlers in `src/main/bx`, not `src/main/resources`.
* Local launch uses `-PtestPort` and `-PdebugMode` flags.
* For this starter, deployment source is the generated ZIP in `build/distributions`.


# JSR-223 Scripting

Integrate BoxLang into Java applications using JSR-223 Scripting

<figure><img src="/files/DLk88olCuBXtFmQjITQH" alt=""><figcaption></figcaption></figure>

## 🚀 Getting Started for Java Developers

JSR 223, also known as "**Scripting for the Java Platform,**" enables seamless integration between Java applications and scripting languages like BoxLang. This guide shows Java developers how to embed BoxLang's dynamic capabilities directly into their applications.

{% embed url="<https://www.oracle.com/technical-resources/articles/javase/scripting.html>" %}

## 📋 Table of Contents

* [Getting Started for Java Developers](#getting-started-for-java-developers)
* [Adding BoxLang to Your Project](#adding-boxlang-to-your-project)
* [Quick Start Example](#quick-start-example)
* [Architecture Overview](#architecture-overview)
* [Common Use Cases for Java Developers](#common-use-cases-for-java-developers)
* [Core Scripting Classes](#core-scripting-classes)
* [BoxLang Home Configuration](#boxlang-home-configuration)
* [Production Considerations](#production-considerations)
* [Integration Patterns](#integration-patterns)

## 📦 Adding BoxLang to Your Project

### Maven Dependency

Add BoxLang to your Maven project's `pom.xml`:

```xml
<dependency>
    <groupId>io.boxlang</groupId>
    <artifactId>boxlang</artifactId>
    <version>1.10.1</version>
</dependency>
```

### Gradle Dependency

For Gradle projects, add to your `build.gradle`:

```groovy
dependencies {
    implementation 'io.boxlang:boxlang:1.10.1'
}
```

### Direct JAR Download

Download the latest BoxLang JAR from:

* **Releases**: <https://github.com/ortus-boxlang/BoxLang/releases>
* **Snapshots**: <https://s3.amazonaws.com/downloads.ortussolutions.com/boxlang/>

Add the JAR to your project's classpath:

```bash
# Compile with BoxLang
javac -cp "boxlang-1.10.0.jar:." MyApp.java

# Run with BoxLang
java -cp "boxlang-1.10.0.jar:." MyApp
```

### System Requirements

* **Java 21+** (BoxLang requires JDK 21 or later)
* **JSR-223 Support** (included in standard Java installations)

## 🏗️ Quick Start Example

Here's a complete Java application demonstrating BoxLang integration:

```java
import javax.script.*;
import ortus.boxlang.runtime.scripting.BoxScriptingFactory;

public class BoxLangExample {
    public static void main( String[] args ) throws ScriptException {
        // Get BoxLang engine
        ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );

        // Pass data to BoxLang
        Bindings bindings = engine.createBindings();
        bindings.put( "name", "Java Developer" );
        bindings.put( "items", java.util.Arrays.asList( "Spring", "Maven", "BoxLang" ) );

        // Execute BoxLang code
        Object result = engine.eval( """
            message = "Hello " & name & "!"
            itemCount = items.len()
            return {
                greeting: message,
                totalItems: itemCount,
                technologies: items.map( ( item ) => item.uCase() )
            }
        """, bindings );

        System.out.println( "Result: " + result );
    }
}
```

{% embed url="<https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform>" %}

## 🔧 Architecture Overview

BoxLang offers complete JSR-223 compliance for seamless integration with JVM applications. Understanding the core components helps Java developers leverage BoxLang effectively.

{% embed url="<https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0/ortus/boxlang/runtime/scripting/package-summary.html>" %}
API Documentation
{% endembed %}

## 💡 Common Use Cases for Java Developers

### Configuration & Rules Engine

```java
// Load business rules from external files
ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );

Bindings context = engine.createBindings();
context.put( "order", orderObject );
context.put( "customer", customerData );

Boolean eligible = ( Boolean ) engine.eval( """
    // Business logic in BoxLang - easier for business users to modify
    if ( order.total > 1000 && customer.tier == "GOLD" ) {
        return true
    }

    if ( customer.loyaltyPoints > 5000 ) {
        return true
    }

    return false
""", context );
```

### Template Processing

```java
// Process templates with BoxLang's powerful string handling
ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );

Bindings data = engine.createBindings();
data.put( "user", userObject );
data.put( "notifications", notificationList );

String html = ( String ) engine.eval( """
    template = "
        <h1>Welcome #{user.name}!</h1>
        <div class='notifications'>
        #notifications.map( ( n ) => '<p>' & n.message & '</p>' ).join( '' )#
        </div>
    "

    // Use proper string replacement instead of evaluate() BIF
    result = template
    result = result.replace( "#{user.name}", user.name )
    // Add more replacements as needed

    return result
""", data );
```

### Data Transformation

```java
// Transform JSON/XML with BoxLang's built-in functions
ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );

Bindings bindings = engine.createBindings();
bindings.put( "jsonData", rawJsonString );

Map result = ( Map ) engine.eval( """
    data = deserializeJSON( jsonData )

    return {
        processedAt: now(),
        recordCount: data.records.len(),
        summary: data.records
            .filter( ( r ) => r.active == true )
            .groupBy( "category" )
            .map( ( category, items ) => {
                category: category,
                count: items.len(),
                totalValue: items.sum( "value" )
            } )
    }
""", bindings );
```

## 📚 Core Scripting Classes

The BoxLang scripting package can be found here: `ortus.boxlang.runtime.scripting`. The classes that will assist you are:

* `BoxCompiledScript` - Implements the JSR `CompiledScript` interface (<https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/CompiledScript.html>)
* `BoxScopeBindings` - Implements the JSR `Bindings` interface (<https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/Bindings.html>)
* `BoxScriptingContext` - Implements the JSR `ScriptContext` interface (<https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/ScriptContext.html>)
* `BoxScriptingEngine` - Implements the JSR `ScriptEngine` and `Compilable` <https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/ScriptEngine.html> [https://docs.oracle.com/en/java/javase/17/docs/api//java.scripting/javax/script/Compilable.html](https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/Compilable.html)
* `BoxScriptingFactory` - implements the JSR `ScriptEngineFactory` <https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/ScriptEngineFactory.html>

### Definitions

* **Script Factory** - creates scripting engines and gets metadata about scripting engines.
* **Script Engine** - provides a way to create bindings, scripts, and run statements.
* **Invocable** - Our BoxLang engine also implements the scripting `Invocable` [interface](https://docs.oracle.com/en/java/javase/21/docs/api/java.scripting/javax/script/Invocable.html) so you can declare functions and classes (coming soon) and then execute them from the calling language.
* **Bindings** - these are like scopes to BoxLang. The bridge between Java and BoxLang
* **Scripting Context** - Like the BoxLang context object, it provides scope lookups and access to bindings.

### Bindings

Bindings are under the hood `HashMaps`. They are used to bind your Java code to the BoxLang code. By default, in BoxLang, we provide three scopes you can bind bindings to:

* `Engine Scope` - The **default** scope which maps to the BoxLang `variables` scope
* `Request Scope` - The JSR request scope maps to the BoxLang `request` scope
* `Global Scope` - The JSR global scope maps to the BoxLang `server` scope

### Discovering Engines

To find out what engines are available in your platform you can run the following:

```java
ScriptEngineManager mgr = new ScriptEngineManager();
List<ScriptEngineFactory> factories = mgr.getEngineFactories();
```

### BoxLang ScriptEngine

To get started, you need to get an instance of the BoxLang Scripting Engine. You can do so by using the Java `ScriptEngineManager()` class or importing our `BoxScriptingEngine` class.

{% code lineNumbers="true" %}

```java
import javax.script.*;

ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );

// Or directly via our BoxScriptingFactory class

import ortus.boxlang.runtime.scripting.BoxScriptingFactory;

ScriptEngine engine = new BoxScriptingFactory().getScriptEngine();
```

{% endcode %}

You can also cast it to our class to get enhanced methods and functionality:

```java
BoxScriptingEngine engine = (BoxScriptingEngine) new BoxScriptingFactory().getScriptEngine();
```

#### Debug Mode

If you ever need to send debugging information to the console from the BoxRuntime in the scripting engine, you can create a new script engine and pass the `debug` flag to it.

```java
import ortus.boxlang.runtime.scripting.BoxScriptingFactory;

ScriptEngine engine = new BoxScriptingFactory().getScriptEngine( true );
```

This will start up the `BoxRuntime` in debug mode.

## 🏠 BoxLang Home Configuration

### Default BoxLang Home

When you create a BoxLang scripting engine, it initializes a BoxLang runtime instance that uses a home directory for configuration and modules. By default, BoxLang uses:

```
{user.home}/.boxlang/
```

For example:

* **Linux/macOS**: `/home/username/.boxlang/` or `/Users/username/.boxlang/`
* **Windows**: `C:\Users\username\.boxlang\`

### Custom Home Directory

You can configure a custom BoxLang home directory using system properties or environment variables:

```java
// Option 1: Set system property before creating engine
System.setProperty( "boxlang.home", "/custom/boxlang/home" );
ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );

// Option 2: Set environment variable (BOXLANG_HOME)
// Set environment variable before running your Java application
// export BOXLANG_HOME=/custom/boxlang/home
```

### Runtime Configuration

The BoxLang home directory contains:

* **`config/boxlang.json`** - Runtime configuration file
* **`lib/`** - Custom modules and libraries
* **`logs/`** - Runtime log files (if file logging is enabled)

You can customize the runtime behavior by modifying the `boxlang.json` configuration file:

```java
// Access runtime configuration through the engine
BoxScriptingEngine boxEngine = ( BoxScriptingEngine ) engine;
BoxRuntime runtime = boxEngine.getRuntime();
// Configuration is automatically loaded from {BOXLANG_HOME}/config/boxlang.json
```

### Multiple Runtime Instances

For applications requiring isolated BoxLang environments, you can create separate instances:

```java
// Create first instance with custom home
System.setProperty( "boxlang.home", "/app1/boxlang" );
ScriptEngine engine1 = new ScriptEngineManager().getEngineByName( "BoxLang" );

// Note: BoxRuntime is singleton-based, so use separate JVMs or custom factory for true isolation
// For most use cases, separate bindings provide sufficient isolation
```

### Configuration Override

You can also override specific configuration settings using system properties or environment variables by prefixing with `boxlang.` or `BOXLANG_`:

```java
// Override specific settings
System.setProperty( "boxlang.runtime.debugMode", "true" );
System.setProperty( "boxlang.runtime.classGenerationDirectory", "/tmp/boxlang-classes" );

// These will override values in boxlang.json
ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );
```

### Eval() BoxLang Code

Once you access the script engine, you can use the plethora of `eval()` methods to execute the BoxLang source and bind with specific dynamic bindings. You can execute scripts from strings or reader objects. You can also compile a script/class into a `CompiledScript` and then execute it at a later point in time via the `compile()` methods.

```java
boxlang.eval( "println( 'hello world' )" )
```

You can use eval with the following signatures

```java
/**
 * Evaluate a script in the context of the ScriptContext
 *
 * @param script  The script to evaluate
 * @param context The context to evaluate the script in
 *
 * @return The result of the script evaluation
 */
public Object eval( String script, ScriptContext context ) throws ScriptException

/**
 * Evaluate a script in the context of the ScriptContext
 *
 * @param reader  The reader to read the script from
 * @param context The context to evaluate the script in
 *
 * @return The result of the script evaluation
 */
public Object eval( Reader reader, ScriptContext context ) throws ScriptException

/**
 * Evaluate a script bound only to the top-level BoxRuntime context
 *
 * @param reader The reader to read the script from
 *
 * @return The result of the script evaluation
 */
public Object eval( Reader reader ) throws ScriptException

/**
 * Evaluate a script using the given Bindings
 *
 * @param script The script to evaluate
 * @param n      The Bindings to use
 *
 * @return The result of the script evaluation
 */
@Override
public Object eval( String script, Bindings n ) throws ScriptException

@Override
public Object eval( Reader reader, Bindings n ) throws ScriptException

/**
 * Evaluate a script bound only to the top-level BoxRuntime context
 *
 * @param script The script to evaluate
 *
 * @return The result of the script evaluation
 */
public Object eval( String script ) throws ScriptException
```

### Bindings - Passing Data to the Scripts

Data can be passed into the engine by defining a *Bindings* object and passing it as a second parameter to the *eval* function. You will do so by using the `createBindings()` method. If you casted the engine to our `BoxScriptingEngine` class, you will also get a `createBindings( Map m )` so you can quickly create bindings from a map of data.

{% code lineNumbers="true" %}

```java
Bindings bindings = boxlang.createBindings();
bindings.put( "count", 3 );
bindings.put( "name", "luis" );
bindings.put( "age", 1 );

// Or if you have already a map of data
Bindings bindings = boxlang.createBindings( myMap );

// Script and evaluate the last result
result = engine.eval( """
  println( 'Hello, ' & name & '!' )
  newAge = age + 1
  totalAge = newAge + 1
  request.nameTest = name
  server.nameTest = name
""", bindings );

// We cannot use the same bindings, these are just to send
// We need to get the bounded bindings now via the `getBindings()` method
Bindings resultBindings = engine.getBindings();
// The result of the script is the last expression
assertThat( result ).isEqualTo( "World" );
// Test the bindings
assertThat( resultBindings.get( "newAge" ) ).isEqualTo( 2 );
assertThat( engine.getRequestBindings().get( "nameTest" ) ).isEqualTo( "World" );
assertThat( engine.getServerBindings().get( "nameTest" ) ).isEqualTo( "World" );
```

{% endcode %}

{% hint style="warning" %}
Once you bind the engine with bindings before execution, you must get the modified bindings via the `engine.getBindings()` method. If you don't do this, you will only have access to the simple hashmap to bind the engine.
{% endhint %}

### Calling Functions From Java to BoxLang

You can also use the `eval()` method to define functions, closures, or lambdas in BoxLang and execute them in your host language. We do so by evaluating the script, casting the engine to `Invocable,` and using the `invokeFunction()` method.

```java
engine.eval( """
    function sayHello( name ) {
        return 'Hello, ' & name & '!'
    }
""");

Invocable	invocable	= ( Invocable ) engine;
Object		result		= invocable.invokeFunction( "sayHello", "World" );
assertThat( result ).isEqualTo( "Hello, World!" );
```

### Objects, Functions, Closures, Lambdas, Member Methods

You can also use the `invokeMethod( object, name, args )` function, which allows you to target a specific object, such as a BoxLang class, member method, struct, lambda, closure or collection of functions.

```java
// Create a struct
engine.eval( "myStr = { foo : 'bar' }" );
// Make it invocable
Invocable invocable = ( Invocable ) engine;
// Invoke the struct's count() member method
Object result = invocable.invokeMethod( engine.get( "myStr" ), "count" );
assertThat( result ).isEqualTo( 1 );
```

This is indeed truly powerful as you can not only invoke functions on objects, but also member methods in any valid BoxLang type.

### Compiling Scripts

Apart from executing strings, you can also compile BoxLang scripts and evaluate them using the `compileScript( String ) or compileScript( Reader )` methods. You will get a `Box CompiledScript` class, which you can then use the `eval()` methods and binding methods at a later point in time.

{% code lineNumbers="true" %}

```java
CompiledScript script = engine
		    .compile( """
			import ortus.boxlang.runtime.scopes.Key;

			name = [ 'John', 'Doe',  Key.of( 'test' ) ]
			name.reverse()
		    """ );

// Execute it
Object results	= script.eval();
assertThat( ( Array ) results ).containsExactly( Key.of( "test" ), "Doe", "John" );
```

{% endcode %}

### Dynamic Interfaces

JSR223 also allows you to dynamically create interface proxies for any functions or classes you map in the dynamic language. Let's say you want to create a nice BoxLang function that maps to a Java Runnable. In our example, we will create the `run` function and then map that via JSR223 to the `Runnable` interface so we can execute it as a runnable object.

```java
engine.eval("""
	function run() {
		print('Hello, world! I am running from a thread.');
	}
""");

Invocable invocable = ( Invocable ) engine;
// Map our function to a Runnable class
Runnable runnable = invocable.getInterface( Runnable.class );
runnable.run();
```

As you can see from the sample above, you can use the `getInterface( class<?> )` method to map the evaluated code to any interface of your choosing. Here are the two methods you can use for interfaces:

* `getInterface( Class<T> )` - Build a dynamic proxy from the evaluated function and the passed in class
* `getInterface( Object, Class<T> )` - Build a dynamic proxy from the passed in `Object` and the passed in class.

Let's finish this section with another example. Using a struct and anonymous functions, let's build a BoxLang virtual object and treat it as a `Runnable` interface.

```java
// Define a BoxLang struct with a `run` key that points to an
// anonymous function
engine.eval("""
  methods = {
    run : function() {
	print('Hello, world!');
    }
  }
""");
// cast it to invocable
Invocable invocable = ( Invocable ) engine;
// Get the interface from that object that map to a Runnable
Runnable runnable = invocable.getInterface( engine.get( "methods" ), Runnable.class );
// Run Forest Run!
runnable.run();
```

### Capturing Output

We have also added the capability for your host language to seed your own String Writers into the engine so you can capture output. BoxLang can produce two types of output

1. **System output** - Bifs and components that send output to the `System.out`
2. **Buffer output -** A BoxLang request has an output String buffer that can be used to produce output which can be sent to console, web, etc.

```java
Writer oldWriter = engine.getContext().getWriter();
// Create my own writer
StringWriter	stringWriter	= new StringWriter();
// Talk to the engine's context and seed in the new writer
engine.getContext().setWriter( stringWriter );

// Execute some code that outputs to the system out
engine.eval("""
  println('Hello, world!')
""");

// Now let's get that output!
assertThat( stringWriter.toString().trim() ).isEqualTo( "Hello, world!" );

// Replace the old writer back!
engine.getContext().setWriter( oldWriter );
```

### Runtime Source Code

The runtime source code can be found here: <https://github.com/ortus-boxlang/BoxLang/tree/development/src/main/java/ortus/boxlang/runtime/scripting>

We welcome any pull requests, testing, docs, etc.

## 🏭 Production Considerations

### Performance Optimization

```java
// Compile once, execute multiple times
ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );
CompiledScript compiled = ( ( Compilable ) engine ).compile( """
    function processOrder( order ) {
        // Complex business logic here
        return {
            processed: true,
            total: order.items.sum( "price" ),
            timestamp: now()
        }
    }
""" );

// Reuse compiled script for better performance
for ( Order order : orders ) {
    Bindings context = engine.createBindings();
    context.put( "order", order );

    Map result = ( Map ) compiled.eval( context );
    // Process result...
}
```

### Thread Safety

```java
// BoxLang scripting engines are thread-safe for compilation
// but each execution should use separate bindings
public class BoxLangProcessor {
    private final CompiledScript processor;

    public BoxLangProcessor() throws ScriptException {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName( "BoxLang" );
        this.processor = ( ( Compilable ) engine ).compile( loadScript() );
    }

    public Object process( Map<String, Object> data ) throws ScriptException {
        // Create fresh bindings for each execution
        Bindings bindings = processor.getEngine().createBindings();
        bindings.putAll( data );

        return processor.eval( bindings );
    }
}
```

### Error Handling

```java
try {
    Object result = engine.eval( boxlangCode, bindings );
    // Handle success
} catch ( ScriptException e ) {
    // BoxLang compilation or runtime error
    logger.error( "BoxLang script failed: " + e.getMessage(), e );

    // Get detailed error information
    if ( e.getCause() != null ) {
        logger.error( "Root cause: " + e.getCause().getMessage() );
    }

    // Line number information (if available)
    if ( e.getLineNumber() >= 0 ) {
        logger.error( "Error at line: " + e.getLineNumber() );
    }
}
```

## 🔗 Integration Patterns

### Spring Framework Integration

```java
@Configuration
public class BoxLangConfig {

    @Bean
    @Scope( "prototype" ) // New engine per injection
    public ScriptEngine boxLangEngine() {
        return new ScriptEngineManager().getEngineByName( "BoxLang" );
    }

    @Bean
    public BoxLangService boxLangService() {
        return new BoxLangService( boxLangEngine() );
    }
}

@Service
public class BoxLangService {
    private final ScriptEngine engine;

    public BoxLangService( ScriptEngine engine ) {
        this.engine = engine;
    }

    public Object executeTemplate( String template, Map<String, Object> variables ) {
        try {
            Bindings bindings = engine.createBindings();
            bindings.putAll( variables );
            return engine.eval( template, bindings );
        } catch ( ScriptException e ) {
            throw new RuntimeException( "Template execution failed", e );
        }
    }
}
```

### Maven Build Integration

```xml
<!-- pom.xml -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        <execution>
            <id>run-boxlang-scripts</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>java</goal>
            </goals>
            <configuration>
                <mainClass>com.mycompany.BoxLangScriptRunner</mainClass>
                <arguments>
                    <argument>${project.basedir}/scripts/generate-config.bx</argument>
                </arguments>
            </configuration>
        </execution>
    </executions>
</plugin>
```

### Gradle Build Integration

```groovy
// build.gradle
task runBoxLangScripts( type: JavaExec ) {
    classpath = sourceSets.main.runtimeClasspath
    main = 'com.mycompany.BoxLangScriptRunner'
    args = [ 'scripts/data-processing.bx' ]
}

// Run BoxLang scripts during build
compileJava.dependsOn runBoxLangScripts
```


# MiniServer

The BoxLang MiniServer runtime is a lightweight, lightning-fast web server powered by Undertow!

<figure><img src="/files/Qv12vblyUOc0bf4aeniR" alt=""><figcaption></figcaption></figure>

The **BoxLang MiniServer** runtime is a **lightweight,** **lightning-fast** web server powered by Undertow. It's ideal for fast applications, desktop apps (Electron/JavaFX), embedded web servers, and development. For those who want a more robust, feature-rich servlet server implementation, we offer our open-source, FREE [CommandBox server](/getting-started/running-boxlang/commandbox) and [CommandBox PRO](https://boxlang.io/plans) with a BoxLang Subscription.

{% hint style="success" %}
**Tip:** Please note that the BoxLang MiniServer is NOT a servlet server. **There is no servlet container;** the web server is just a simple, fast, and pure-Java Undertow server.
{% endhint %}

{% hint style="danger" %}
CommandBox is our open-source servlet server implementation. However, with a [Boxlang +/++ subscription](https://boxlang.io/plans), it becomes a powerhouse for mission-critical applications. Check out all that you get with CommandBox Pro: <https://www.ortussolutions.com/products/commandbox-pro>
{% endhint %}

## 📋 Table of Contents

* [Start a Server](#start-a-server)
* [JSON Configuration](#json-configuration)
* [Security Features](#security-features)
* [Health Check Endpoints](#health-check-endpoints)
* [Environment Files](#environment-files)
* [WebSocket Support](#websocket-support)
* [Default Welcome Files](#default-welcome-files)
* [URL Rewrites](#url-rewrites)
* [Folder Aliases](#folder-aliases)
* [Server Management](#server-management)
* [Performance Features](#performance-features)
* [Reverse Proxy Setup](#reverse-proxy-setup)

## ▶️ Start a Server <a href="#starting-a-web-server-12" id="starting-a-web-server-12"></a>

The BoxLang core OS runtime doesn't know about a web application. Our web support runtime provides this functionality, a crucial part of the MiniServer and the Servlet (JEE, Jakarta, CommandBox) runtime. This runtime enhances the core boxlang runtime, making it multi-runtime and web deployable.

If you use our Windows installer or our [Quick Installer](/getting-started/installation/boxlang-quick-installer), you will have the `boxlang-miniserver` binary installed in your operating system. You will use this to start servers. Just navigate to any folder that you want to start a server in and run `boxlang-miniserver`.

{% hint style="success" %}
Please note that our [VSCode BoxLang Extension](/getting-started/ide-tooling) can also assist you in managing and starting/stopping servers.
{% endhint %}

{% tabs %}
{% tab title="Mac/Unix" %}

```bash
# Mac / *unix
cd mySite
boxlang-miniserver
```

{% endtab %}

{% tab title="Windows" %}

```powershell
# Windows
cd mySite
boxlang-miniserver.bat
```

{% endtab %}

{% tab title="JAR Execution" %}

```bash
# Native Jar execution
cd mySite
java -jar /usr/local/lib/boxlang-miniserver-1.0.0.jar
```

{% endtab %}
{% endtabs %}

Once you run the command, the following output will appear in your console:

```bash
+ Loaded environment variables from: /path/to/webroot/.env
+ Starting BoxLang Server...
  - Web Root: /home/lmajano/Sites/temp
  - Host: 0.0.0.0
  - Port: 8080
  - Debug: null
  - Config Path: null
  - Server Home: null
  - Health Check: false
  - Health Check Secure: false
+ Starting BoxLang Runtime...
  - BoxLang Version: 1.9.0-snapshot+0 (Built On: 2025-08-01 16:03:36)
  - Runtime Started in 652ms
+ Security protection enabled - blocking access to hidden files (starting with .)
+ WebSocket Server started
+ BoxLang MiniServer started in 818ms at: http://localhost:8080
Press Ctrl+C to stop the server.
```

As you can see from the output, this is the result of the command:

* Use the current **working directory** as the web root.
* Bind to `0.0.0.0:8080` by default (accessible from any network interface)
* **Automatic .env file loading** - Environment variables from `.env` files in the webroot are loaded into the system properties
* **Built-in security protection** - Blocks access to hidden files and directories (starting with `.`) for security
* **WebSocket support** is enabled by default at `/ws` endpoint
* This configures the web server to serve default welcome files and to perform no rewrites.
* BoxLang will process any BoxLang or CFML files (bx,bxs,bxm,cfc,cfm)
* Uses the user's BoxLang home as the default for configuration and modules: `~/.boxlang`

{% hint style="warning" %}
**ALERT:** The BoxLang Core knows nothing of web or HTTP, so the `form`, `url`, `cookie`, and `cgi` scopes will only exist when running the BoxLang web server (but not in the REPL, etc).
{% endhint %}

That's practically it. This is a very lightweight server that can get the job done. You can also start up servers using our VSCode IDE by opening the command palette and clicking **Start** a BoxLang web server.

<figure><img src="/files/AQWS1UBHGwN6JTbLi6UY" alt=""><figcaption><p>Command Palette</p></figcaption></figure>

<figure><img src="/files/AIlqh7dhNexeXbNE8d9k" alt=""><figcaption><p>Manage your Servers</p></figcaption></figure>

## 📋 JSON Configuration

The BoxLang MiniServer supports loading configuration from a JSON file. This allows you to store all server settings in one place rather than passing them as command-line arguments each time.

### Automatic Loading

If you run `boxlang-miniserver` with no arguments, it will automatically look for a `miniserver.json` file in the current directory:

```bash
boxlang-miniserver
// Searches for a miniserver.json from where the command was ran
```

### Explicit Path

You can also specify the path to a JSON configuration file:

```bash
boxlang-miniserver /path/to/config.json
```

### Override with CLI

Command-line arguments always override JSON configuration:

```bash
boxlang-miniserver miniserver.json --port 9090 --debug
```

### Configuration Options

All the following options are supported in the JSON configuration file:

| Option              | Type    | Default           | Description                                                                        |
| ------------------- | ------- | ----------------- | ---------------------------------------------------------------------------------- |
| `aliases`           | object  | {}                | URL-prefix to filesystem-path mappings (struct or array form)                      |
| `configPath`        | string  | null              | Path to BoxLang configuration file                                                 |
| `debug`             | boolean | false             | Enable debug mode                                                                  |
| `envFile`           | string  | null              | Path to custom environment file (relative or absolute)                             |
| `healthCheck`       | boolean | false             | Enable health check endpoints                                                      |
| `healthCheckSecure` | boolean | false             | Restrict detailed health info to localhost only                                    |
| `host`              | string  | "0.0.0.0"         | The host to bind to                                                                |
| `passPredicate`     | string  | *(see below)*     | Undertow predicate expression that determines which requests are routed to BoxLang |
| `port`              | number  | 8080              | The port to listen on                                                              |
| `rewriteFileName`   | string  | "index.bxm"       | Rewrite target file                                                                |
| `rewrites`          | boolean | false             | Enable URL rewrites                                                                |
| `serverHome`        | string  | null              | BoxLang server home directory                                                      |
| `socketOptions`     | object  | {}                | XNIO socket-level options keyed by `Options` constant names                        |
| `undertowOptions`   | object  | *(see below)*     | Undertow server-level options keyed by `UndertowOptions` constant names            |
| `useProxyHeaders`   | boolean | false             | Trust forwarded headers from a reverse proxy for the client IP, protocol, and host |
| `warmupUrl`         | string  | null              | Single URL path to request on server startup (shorthand for one URL)               |
| `warmupUrls`        | array   | \[]               | Array of URL paths to request on server startup for application initialization     |
| `webRoot`           | string  | current directory | Path to the webroot directory                                                      |
| `workerOptions`     | object  | {}                | XNIO worker-level options keyed by `Options` constant names                        |

### `.boxlang.json` Project Convention

When the MiniServer starts, it automatically looks for a **`.boxlang.json`** file in the current working directory. If found, it is merged with the base BoxLang configuration (`boxlang.json`) — providing a portable, project-level configuration override without touching the global runtime settings.

```json
// .boxlang.json (in your project root)
{
  "runtime": {
    "enforceUDFTypeChecks": false,
    "defaultDatasource": "mydb",
    "debugMode": true
  }
}
```

```bash
# The .boxlang.json is loaded automatically — no extra flags needed
cd myProject
boxlang-miniserver
```

This is ideal for:

* **Containerized deployments** — bundle a project-specific config without baking it into the image
* **Team environments** — commit `.boxlang.json` to source control for consistent per-project settings
* **Multiple projects** — each project can override runtime settings independently

{% hint style="info" %}
The `.boxlang.json` file is merged on top of the global `boxlang.json`. Any settings not specified in `.boxlang.json` fall back to the global config.
{% endhint %}

### Undertow, Worker & Socket Options

For fine-grained control over the underlying Undertow HTTP server, XNIO worker, and TCP socket layers, you can specify `undertowOptions`, `workerOptions`, and/or `socketOptions` objects in your `miniserver.json`. Keys must match the constant names used in Undertow and XNIO (upper-case, e.g. `MAX_ENTITY_SIZE`). Keys are case-insensitive in the JSON — they are normalized to `UPPER_CASE` automatically.

```json
{
  "port": 8080,
  "webRoot": "./www",
  "undertowOptions": {
    "MAX_ENTITY_SIZE": 52428800,
    "MULTIPART_MAX_ENTITY_SIZE": 209715200,
    "IDLE_TIMEOUT": 30000
  },
  "workerOptions": {
    "WORKER_TASK_MAX_THREADS": 200,
    "WORKER_IO_THREADS": 8
  },
  "socketOptions": {
    "TCP_NODELAY": true,
    "BACKLOG": 10000
  }
}
```

**`undertowOptions`** — applied via `builder.setServerOption()`. Keys match [`io.undertow.UndertowOptions`](https://github.com/undertow-io/undertow/blob/main/core/src/main/java/io/undertow/UndertowOptions.java) constants.

The following defaults replace Undertow's built-in 2 MB limits:

| Key                         | Default | Description                                            |
| --------------------------- | ------- | ------------------------------------------------------ |
| `MAX_ENTITY_SIZE`           | 25 MB   | Maximum HTTP entity body size (JSON, form posts, etc.) |
| `MULTIPART_MAX_ENTITY_SIZE` | 100 MB  | Maximum `multipart/form-data` upload size              |

Other commonly useful options:

| Key                     | Type    | Description                                           |
| ----------------------- | ------- | ----------------------------------------------------- |
| `MAX_HEADER_SIZE`       | int     | Max HTTP request header size in bytes (default: 1 MB) |
| `IDLE_TIMEOUT`          | int     | Idle connection timeout in milliseconds               |
| `REQUEST_PARSE_TIMEOUT` | int     | Max time to parse a request in milliseconds           |
| `MAX_PARAMETERS`        | int     | Max query/POST parameters (default: 1000)             |
| `MAX_HEADERS`           | int     | Max request headers (default: 200)                    |
| `ENABLE_HTTP2`          | boolean | Enable HTTP/2 for HTTPS connections                   |

**`workerOptions`** — applied via `builder.setWorkerOption()`. Keys match [`org.xnio.Options`](https://github.com/xnio/xnio/blob/3.x/api/src/main/java/org/xnio/Options.java) constants.

| Key                        | Type | Description                             |
| -------------------------- | ---- | --------------------------------------- |
| `WORKER_IO_THREADS`        | int  | Number of I/O threads                   |
| `WORKER_TASK_CORE_THREADS` | int  | Core worker thread pool size            |
| `WORKER_TASK_MAX_THREADS`  | int  | Maximum worker thread pool size         |
| `WORKER_TASK_KEEPALIVE`    | int  | Milliseconds to keep idle threads alive |

**`socketOptions`** — applied via `builder.setSocketOption()`. Keys match [`org.xnio.Options`](https://github.com/xnio/xnio/blob/3.x/api/src/main/java/org/xnio/Options.java) constants.

| Key               | Type    | Description                                 |
| ----------------- | ------- | ------------------------------------------- |
| `TCP_NODELAY`     | boolean | Disable Nagle's algorithm for lower latency |
| `RECEIVE_BUFFER`  | int     | TCP receive buffer size in bytes            |
| `SEND_BUFFER`     | int     | TCP send buffer size in bytes               |
| `KEEP_ALIVE`      | boolean | Enable TCP keep-alive                       |
| `BACKLOG`         | int     | Accept backlog (max queued connections)     |
| `REUSE_ADDRESSES` | boolean | Reuse addresses in TIME\_WAIT state         |

{% hint style="warning" %}
These are advanced tuning options. In most cases the defaults are appropriate. Only change these if you understand the implications for concurrency, memory, and throughput.
{% endhint %}

### Example Configuration Files

<details>

<summary>Example Configuration Files</summary>

#### Basic Configuration

```json
{
  "port": 8080,
  "webRoot": "./www"
}
```

#### Development Configuration

```json
{
  "port": 8080,
  "host": "127.0.0.1",
  "webRoot": "./src/webapp",
  "debug": true,
  "rewrites": true,
  "rewriteFileName": "index.bxm"
}
```

#### Production Configuration

```json
{
  "port": 80,
  "host": "0.0.0.0",
  "webRoot": "/var/www/myapp",
  "debug": false,
  "rewrites": true,
  "rewriteFileName": "index.bxm",
  "healthCheck": true,
  "healthCheckSecure": true,
  "useProxyHeaders": true,
  "serverHome": "/opt/boxlang",
  "envFile": "/etc/boxlang/.env.production"
}
```

#### Complete Configuration

```json
{
  "port": 8080,
  "host": "0.0.0.0",
  "webRoot": "./www",
  "debug": true,
  "configPath": "/path/to/boxlang.json",
  "serverHome": "/opt/boxlang",
  "rewrites": true,
  "rewriteFileName": "index.bxm",
  "healthCheck": true,
  "healthCheckSecure": false,
  "envFile": ".env.production",
  "passPredicate": "regex( '^(/.+?\\.cfml|/.+?\\.cf[cms]|.+?\\.bx[ms]{0,1})(/.*)?$' )",
  "warmupUrls": [
    "/api/warmup",
    "/cache/initialize",
    "/app/preload"
  ],
  "aliases": {
    "/docs": "/var/www/documentation",
    "/shared": "../shared-assets"
  },
  "undertowOptions": {
    "MAX_ENTITY_SIZE": 52428800,
    "MULTIPART_MAX_ENTITY_SIZE": 209715200
  },
  "workerOptions": {
    "WORKER_TASK_MAX_THREADS": 200
  },
  "socketOptions": {
    "TCP_NODELAY": true
  }
}
```

</details>

### Configuration Priority

Configuration values are loaded in the following order (later sources override earlier ones):

1. **Default values** - Built-in defaults
2. **Environment variables** - `BOXLANG_*` environment variables
3. **JSON configuration** - Values from the JSON file
4. **Command-line arguments** - Explicit CLI flags

For example, if you have:

* Environment variable: `BOXLANG_PORT=3000`
* JSON file: `"port": 8080`
* CLI argument: `--port 9090`

The server will start on port **9090** (CLI overrides all).

### Configuration Notes

* The JSON file must be valid JSON (no comments allowed in the actual file)
* All fields are optional - you only need to specify the ones you want to change
* Null values in the JSON file will be treated as "not set."
* Boolean values must be lowercase (`true` or `false`)
* String paths can be relative or absolute

### Environment File Loading

The `envFile` option allows you to specify a custom environment file to load instead of the default `.env` file in the webroot:

* If `envFile` is not specified, the server looks for `.env` in the webroot directory (default behavior)
* If `envFile` is specified, it loads that file instead
* The path can be relative (resolved from the **current** directory) or absolute
* Environment variables are loaded as system properties and can be used throughout the application

Example:

```json
{
  "envFile": ".env.local"
}
```

or

```json
{
  "envFile": "/etc/myapp/.env.production"
}
```

### 🔧 Arguments <a href="#web-server-args-13" id="web-server-args-13"></a>

These are the supported arguments you can pass into the binary to configure the server.

| Argument                                                                                | Value                                                                                                                                                                                                                                                                                                                                                                     |
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><code>--configPath path/boxlang.json</code><br><code>-c path/boxlang.json</code></p> | Relative/Absolute location of the `boxlang.json` to use. By default it uses the `~/.boxlang/boxlang.json`                                                                                                                                                                                                                                                                 |
| <p><code>--debug</code><br><code>-d</code></p>                                          | Put the runtime into debug mode. This will also render detailed error messages in the browser. By default we use `false`                                                                                                                                                                                                                                                  |
| <p><code>--help</code><br><code>-h</code></p>                                           | Display comprehensive help information and exit                                                                                                                                                                                                                                                                                                                           |
| `--host ip\|domain`                                                                     | Bind the hostname to the mini server. By default we use `0.0.0.0` (all network interfaces)                                                                                                                                                                                                                                                                                |
| <p><code>--port 8080</code><br><code>-p 8080</code></p>                                 | The port to bind the mini server to. By default we use port `8080`                                                                                                                                                                                                                                                                                                        |
| <p><code>--rewrites \[index.bxm]</code><br><code>-r \[index.bxm]</code></p>             | Enable rewrites for applications using `index.bxm` as the file to use. You can also pass the name of the file to use: `--rewrites myfile.bxm`                                                                                                                                                                                                                             |
| `--health-check`                                                                        | Enable health check endpoints at `/health`, `/health/ready`, and `/health/live`. These provide detailed server status, readiness, and liveness information in JSON format.                                                                                                                                                                                                |
| `--health-check-secure`                                                                 | Restrict detailed health check information to localhost only. When enabled, non-localhost requests receive basic status only, while localhost gets full system details including JVM metrics and memory usage.                                                                                                                                                            |
| <p><code>--serverHome path/</code><br><code>-s path/</code></p>                         | <p>The location of the BoxLang home for the miniserver. This is where it will look for the <code>boxlang.json</code>, place to put the log files, the compiled classes, load modules, and much more.<br><br>By default, we use the OS home via the <code>BOXLANG\_HOME</code> environment variable which usually points to the user's home: <code>\~/.boxlang/</code></p> |
| <p><code>--version</code><br><code>-v</code></p>                                        | Display version information and exit                                                                                                                                                                                                                                                                                                                                      |
| <p><code>--webroot path/</code><br><code>-w path/</code></p>                            | The webserver root. By default, we use the directory from where you started the command.                                                                                                                                                                                                                                                                                  |

```bash
# Get version information
boxlang-miniserver --version
boxlang-miniserver -v

# Get help information
boxlang-miniserver --help
boxlang-miniserver -h

# Custom port and webroot
boxlang-miniserver --port 80 --webroot /var/www

# Custom port and server home
boxlang-miniserver --port 80 --serverHome /var/www/servers/myServer

# Custom port and rewrites enabled
boxlang-miniserver --port 80 --rewrites

# Enable health check endpoints for monitoring
boxlang-miniserver --health-check

# Enable secure health checks (detailed info only on localhost)
boxlang-miniserver --health-check --health-check-secure

# Production server with security and monitoring
boxlang-miniserver --port 8080 --host 0.0.0.0 --health-check-secure
```

### 🛡️Environment Variables

The `boxlang-miniserver` binary will also scan for several environment variables as overrides to the execution process.

| Env Variable                            | Purpose                                                           |
| --------------------------------------- | ----------------------------------------------------------------- |
| `BOXLANG_CONFIG = PATH`                 | Override the `boxlang.json`                                       |
| `BOXLANG_DEBUG = boolean`               | Enable or disable debug mode                                      |
| `BOXLANG_HOME = directory`              | Override the server HOME directory                                |
| `BOXLANG_HOST = ip or domain`           | Override the `0.0.0.0` default to whatever IP or domain you like. |
| `BOXLANG_PORT = 8080`                   | Override the default port                                         |
| `BOXLANG_REWRITES = boolean`            | Enable or disable URL rewrites                                    |
| `BOXLANG_REWRITE_FILE = file.bxm`       | Choose the rewrite file to use. By default, it uses `index.bxm`   |
| `BOXLANG_WEBROOT = path`                | Override the location of the web root                             |
| `BOXLANG_HEALTH_CHECK = boolean`        | Enable or disable health check endpoints                          |
| `BOXLANG_HEALTH_CHECK_SECURE = boolean` | Enable secure health checks (detailed info only on localhost)     |
| `BOXLANG_MINISERVER_OPTS = jvmOptions`  | A list of Java options to pass to the startup command             |

{% hint style="danger" %}
Environment variables are scanned first, then the command arguments. Thus, the command arguments take precedence.
{% endhint %}

## 🔒 Security Features

The BoxLang MiniServer includes built-in security features to protect your applications:

### Hidden File Protection

The server automatically blocks access to hidden files and directories (those starting with a dot `.`). This security feature protects sensitive files such as:

* `.env` files containing environment variables
* `.git` directories and configuration
* `.htaccess` and other web server configuration files
* Any custom hidden files or directories

When a request is made for a hidden file, the server returns a `404 Not Found` response for security reasons, without revealing whether the file actually exists.

{% hint style="info" %}
**Security Note:** This protection is enabled by default and cannot be disabled. It's a fundamental security feature designed to prevent accidental exposure of sensitive configuration files.
{% endhint %}

## 🩺 Health Check Endpoints

The MiniServer provides comprehensive health monitoring capabilities through dedicated endpoints:

### Basic Health Checks

Enable health checks with the `--health-check` flag:

```bash
boxlang-miniserver --health-check
```

This enables three endpoints:

* **`/health`** - Complete health information including system metrics, JVM details, and runtime status
* **`/health/ready`** - Readiness probe for load balancers (simple UP/DOWN status)
* **`/health/live`** - Liveness probe for container orchestration (simple UP/DOWN status)

### Secure Health Checks

For production environments, use the `--health-check-secure` flag:

```bash
boxlang-miniserver --health-check --health-check-secure
```

When secure mode is enabled:

* **Localhost requests** receive full detailed health information
* **Remote requests** receive only basic status information
* This prevents sensitive system information from being exposed to external networks

### Health Check Response Format

{% hint style="info" %}
**BoxLang v1.14+** — The `/health` endpoint now includes Undertow worker pool statistics, listener metrics, request timing data, and WebSocket session counts.
{% endhint %}

The `/health` endpoint returns comprehensive JSON information:

```json
{
  "status": "UP",
  "timestamp": "2026-05-21T16:49:36.072938Z",
  "uptime": "1m 8s",
  "uptimeMs": 68318,
  "version": "1.14.0-snapshot+4432",
  "buildDate": "2026-05-21 11:50:35",
  "javaVersion": "21.0.10",
  "memoryUsed": 54973848,
  "memoryMax": 17179869184,
  "activeRequests": 1,
  "workerPool": {
    "core": 128,
    "max": 128,
    "current": 1,
    "busy": -1,
    "ioThreadCount": 16,
    "queueSize": 0
  },
  "listeners": [
    {
      "name": "http",
      "requestCount": 14,
      "errorCount": 0,
      "bytesSent": 912159,
      "bytesReceived": 9000,
      "activeConnections": 1,
      "activeRequests": 1
    }
  ],
  "requestMetrics": {
    "totalRequests": 13,
    "totalErrors": 1,
    "totalRequestTime": 535,
    "maxRequestTime": 418,
    "minRequestTime": 0
  },
  "websocket": {
    "activeConnections": 0,
    "openConnections": 0
  }
}
```

The health check provides:

#### Core Metrics

| Field            | Description                                  |
| ---------------- | -------------------------------------------- |
| `status`         | Current server status (`UP` / `DOWN`)        |
| `timestamp`      | Current server time in ISO 8601 format       |
| `uptime`         | Human-readable server uptime                 |
| `uptimeMs`       | Server uptime in milliseconds                |
| `version`        | BoxLang version information                  |
| `buildDate`      | When BoxLang was built                       |
| `javaVersion`    | JVM version information                      |
| `memoryUsed`     | Current JVM memory usage in bytes            |
| `memoryMax`      | Maximum available JVM memory in bytes        |
| `activeRequests` | Number of requests currently being processed |

#### Worker Pool (`workerPool`)

Undertow XNIO worker thread pool statistics:

| Field           | Description                                       |
| --------------- | ------------------------------------------------- |
| `core`          | Core thread pool size                             |
| `max`           | Maximum thread pool size                          |
| `current`       | Current number of threads in the pool             |
| `busy`          | Number of busy threads (`-1` if unavailable)      |
| `ioThreadCount` | Number of I/O threads handling network operations |
| `queueSize`     | Number of tasks waiting in the worker queue       |

#### Listeners (`listeners`)

Per-listener Undertow statistics (array — one entry per configured listener):

| Field               | Description                                         |
| ------------------- | --------------------------------------------------- |
| `name`              | Listener name (e.g., `"http"`, `"https"`)           |
| `requestCount`      | Total number of requests handled by this listener   |
| `errorCount`        | Total number of errors returned by this listener    |
| `bytesSent`         | Total bytes sent to clients                         |
| `bytesReceived`     | Total bytes received from clients                   |
| `activeConnections` | Currently open TCP connections                      |
| `activeRequests`    | Requests currently being processed on this listener |

#### Request Metrics (`requestMetrics`)

Aggregate request timing statistics:

| Field              | Description                                      |
| ------------------ | ------------------------------------------------ |
| `totalRequests`    | Total number of requests processed since startup |
| `totalErrors`      | Total number of error responses returned         |
| `totalRequestTime` | Cumulative request processing time (ms)          |
| `maxRequestTime`   | Slowest single request time (ms)                 |
| `minRequestTime`   | Fastest single request time (ms)                 |

#### WebSocket (`websocket`)

WebSocket session counts:

| Field               | Description                            |
| ------------------- | -------------------------------------- |
| `activeConnections` | Currently active WebSocket connections |
| `openConnections`   | Total open WebSocket sessions          |

## 🌍 Environment Files

The MiniServer automatically loads environment variables from `.env` files located in your webroot directory:

### Automatic .env Loading

When you start the server, it will automatically look for and load a `.env` file in the webroot:

```bash
# If webroot contains a .env file, you'll see:
+ Loaded environment variables from: /path/to/webroot/.env
```

### .env File Format

Your `.env` file should contain key-value pairs:

```bash
# .env file example
DATABASE_URL=jdbc:mysql://localhost:3306/mydb
API_KEY=your-secret-api-key
DEBUG_MODE=true
CUSTOM_SETTING=value
```

### Accessing Loaded Variables

Environment variables loaded from `.env` files are:

1. **Added to Java System Properties** - Accessible via `System.getProperty("key")`
2. **Available in BoxLang** - Accessible through the `server.system.properties` struct
3. **Available to your applications** - Can be used in BoxLang code for configuration

Note that these variables will not be available as "proper" environment variables because BoxLang's runtime loads them differently. The structure, `server.system.environment`, contains system-level environment variables and will not reflect the values set in your `.env` file.

Using `server.system.properties` would work locally, but not in production, as the value would most likely instead be in the `environment` structure. Luckily, BoxLang provides a simple BIF that can work with either `getSystemSetting()`. Given the example `.env` file above, using `getSystemSetting("API_KEY")` would work both locally, using the value loaded from the file, and in production, using a value loaded as an environment variable.

```javascript
getSystemSetting( "My_API_KEY" )
```

{% hint style="info" %}
**Privacy Note:** Environment variables are NOT exposed through health check endpoints. Health checks return server metrics (JVM, Undertow worker pool, listener stats, request timing, WebSocket sessions) but never application data, secrets, or environment variables. Use `--health-check-secure` in production to restrict detailed metrics to localhost only.
{% endhint %}

## 🌩 Warmup URLs

The MiniServer supports warmup URLs, which automatically request specific URLs when the server starts up. This is useful for pre-loading applications, initializing caches, or warming up services before accepting production traffic.

### Why Use Warmup URLs?

Warmup URLs help with:

* **Faster first requests** - Pre-load application code and dependencies before users arrive
* **Cache initialization** - Populate caches with frequently accessed data
* **Service initialization** - Initialize database connections, external API clients, etc.
* **Application preloading** - Load and compile BoxLang templates ahead of time
* **Reduce cold start latency** - Ensure the application is fully ready before serving traffic

### Configuring Warmup URLs

Add the `warmupURLs` array to your JSON configuration file:

```json
{
  "port": 8080,
  "webRoot": "./www",
  "warmupURLs": [
    "/api/warmup",
    "/cache/initialize",
    "/app/preload"
  ]
}
```

### How Warmup Works

When the server starts:

1. **Server initialization** completes first
2. **Warmup requests** are sent to each URL in the array (in order)
3. **Sequential execution** - each URL completes before the next starts
4. **Error handling** - failures are logged, but don't stop server startup
5. **Server ready** - after all warmup URLs are complete, the server is fully ready

### Warmup URL Examples

#### Basic Application Preload

```json
{
  "warmupURLs": [
    "/index.bxm"
  ]
}
```

#### Multiple Initialization Endpoints

```json
{
  "warmupURLs": [
    "/api/health",
    "/cache/warmup",
    "/db/connect",
    "/modules/initialize"
  ]
}
```

#### Production Warmup Strategy

```json
{
  "port": 8080,
  "webRoot": "/var/www/myapp",
  "warmupURLs": [
    "/api/warmup/database",
    "/api/warmup/cache",
    "/api/warmup/services",
    "/health/ready"
  ]
}
```

### Creating Warmup Endpoints

Create dedicated warmup endpoints in your BoxLang application:

```js
// /api/warmup.bxm
bx:header statusCode=200;

// Initialize application services
application.cacheService = new CacheService();
application.dbPool = new DatabasePool();

// Preload frequently accessed data
application.config = loadConfig();
application.routes = loadRoutes();

// Return success
writeOutput( serializeJSON( {
    "status": "ready",
    "initialized": now(),
    "services": [
        "cache",
        "database",
        "config"
    ]
} ) );
```

### Warmup Best Practices

1. **Keep warmup URLs lightweight** - Focus on initialization, not heavy processing
2. **Use dedicated endpoints** - Create specific `/warmup/*` endpoints for initialization
3. **Sequential dependencies** - Order URLs so dependencies load first (e.g., database before cache)
4. **Error handling** - Ensure warmup endpoints handle errors gracefully
5. **Return quickly** - Warmup should complete in seconds, not minutes
6. **Health checks** - Include a health check endpoint as the final warmup URL to verify readiness

### Console Output

When warmup URLs are configured, you'll see output during server startup:

```bash
+ Starting BoxLang Runtime...
  - BoxLang Version: 1.10.0 (Built On: 2026-02-02 10:30:15)
  - Runtime Started in 652ms
+ Executing warmup URLs...
  - GET /api/warmup [200 OK] in 145ms
  - GET /cache/initialize [200 OK] in 89ms
  - GET /app/preload [200 OK] in 203ms
+ Warmup completed in 437ms
+ BoxLang MiniServer started in 1105ms at: http://localhost:8080
```

### Error Handling

If a warmup URL fails, the error is logged, but server startup continues:

```bash
+ Executing warmup URLs...
  - GET /api/warmup [200 OK] in 145ms
  - GET /cache/initialize [500 Internal Server Error] in 52ms
    WARNING: Warmup URL failed but server startup will continue
  - GET /app/preload [200 OK] in 203ms
+ Warmup completed with errors in 400ms
```

{% hint style="success" %}
**Tip:** Use warmup URLs in production deployments to ensure your application is fully initialized before accepting user traffic. This is especially important in containerized environments or auto-scaling scenarios where new instances are frequently created.
{% endhint %}

{% hint style="info" %}
**Performance Note:** Warmup URLs are executed sequentially during server startup. Keep individual warmup operations fast to minimize total startup time. For complex initialization, consider using asynchronous initialization within your warmup endpoints.
{% endhint %}

## 🔌 WebSocket Support

<details>

<summary>WebSocket Support / SocketBox</summary>

The BoxLang MiniServer includes built-in WebSocket support for real-time communication:

### WebSocket Endpoint

WebSocket connections are available at the `/ws` endpoint:

{% hint style="info" %}
**New in 1.6.0**: The MiniServer now properly returns STOMP heartbeat responses, ensuring reliable WebSocket connections with STOMP protocol support.
{% endhint %}

```javascript
// JavaScript client example
const socket = new WebSocket('ws://localhost:8080/ws');

socket.onopen = function(event) {
    console.log('Connected to BoxLang WebSocket server');
};

socket.onmessage = function(event) {
    console.log('Message from server:', event.data);
};

socket.onclose = function(event) {
    console.log('Disconnected from server');
};
```

### SocketBox - BoxLang WebSocket Library

For enhanced WebSocket functionality in your BoxLang applications, we recommend using **SocketBox** - our companion library specifically designed for BoxLang WebSocket development:

{% hint style="success" %}
**SocketBox** is available on ForgeBox: <https://forgebox.io/view/socketbox>
{% endhint %}

SocketBox provides:

* **Core WebSocket lifecycle hooks** (`onConnect`, `onMessage`, `onClose`)
* **Low-level channel messaging** with `sendMessage()` and `broadcastMessage()`
* **Connection inspection** via `getAllConnections()`
* **Optional STOMP broker mode** for subscriptions, routing, auth, and heartbeats
* **Integration with BoxLang and CFML runtimes**

{% hint style="info" %}
SocketBox core keeps the API intentionally simple: handle lifecycle events with a `channel`, send targeted replies with `sendMessage()`, broadcast with `broadcastMessage()`, and inspect active connections with `getAllConnections()`.
{% endhint %}

#### Installing SocketBox

```bash
# Install via CommandBox
box install socketbox

# Or download from ForgeBox
# https://forgebox.io/view/socketbox
```

#### SocketBox Example

```javascript
// WebSocket.cfc (or equivalent) using SocketBox core support
class extends="modules.socketbox.models.WebSocketCore" {

    // Called for every new remote connection
    function onConnect( required channel ) {
        broadcastMessage( "A client connected" )
    }

    // Called whenever a text message is received
    function onMessage( required message, required channel ) {
        if ( arguments.message == "Ping" ) {
            sendMessage( "Pong", arguments.channel )
            return
        }

        // Echo to all connected clients
        broadcastMessage( "Client says: #arguments.message#" )
    }

    // Called when a connection closes
    function onClose( required channel ) {
        broadcastMessage( "A client disconnected" )
    }
}
```

If you need topic subscriptions, destination routing, and protocol-level auth/authorization, use SocketBox's STOMP mode by extending `WebSocketSTOMP` instead of core `WebSocketCore`.

### WebSocket Features

* **Real-time bidirectional communication** between client and server
* **Automatic connection management** with built-in error handling
* **STOMP protocol support** with proper heartbeat responses for connection reliability
* **Integration with BoxLang runtime** for server-side message processing
* **Low latency** communication for interactive applications
* **Enhanced functionality** with SocketBox library for production applications

The WebSocket server is automatically started when the MiniServer launches, as indicated by the console message:

```bash
+ WebSocket Server started
```

{% hint style="info" %}
**WebSocket Note:** The WebSocket endpoint is always enabled and cannot be disabled. This provides a consistent real-time communication channel for all BoxLang applications. For production applications, consider using SocketBox for enhanced features and easier development.
{% endhint %}

</details>

## 🏠 Default Welcome Files

The BoxLang MiniServer automatically serves welcome files when a request is made to a directory. The server looks for these files in the following order:

1. `index.bxm` - BoxLang Markup (preferred)
2. `index.bxs` - BoxLang Script
3. `index.cfm` - CFML Markup (legacy compatibility)
4. `index.cfs` - CFML Script (legacy compatibility)
5. `index.htm` - HTML
6. `index.html` - HTML

### Welcome File Behavior

When a request is made to a directory (e.g., `http://localhost:8080/`), the server will:

1. **Check for welcome files** in the order listed above
2. **Serve the first match** found in the directory
3. **Enable directory listing** if no welcome file is found (showing folder contents)
4. **Process BoxLang/CFML files** through the runtime before serving
5. **Serve static files** (HTML) directly without processing

### Example Directory Structure

```
webroot/
├── index.bxm          # ✅ Will be served for /
├── index.html         # ❌ Will be ignored (index.bxm takes precedence)
├── subfolder/
│   ├── index.cfm      # ✅ Will be served for /subfolder/
│   └── page.bxm       # ✅ Available at /subfolder/page.bxm
└── static/
    └── styles.css     # ✅ Available at /static/styles.css
```

{% hint style="success" %}
**Tip:** Use `index.bxm` for your main pages to take advantage of BoxLang's modern syntax and features while maintaining compatibility with legacy CFML files.
{% endhint %}

## 🔀 URL Rewrites

<details>

<summary>URL Rewrites</summary>

The BoxLang MiniServer supports URL rewrites for creating clean, SEO-friendly URLs and building single-page applications (SPAs):

### Enabling URL Rewrites

Enable URL rewrites with the `--rewrites` flag:

```bash
# Enable rewrites with default file (index.bxm)
boxlang-miniserver --rewrites

# Enable rewrites with custom file
boxlang-miniserver --rewrites app.bxm

# Using environment variable
BOXLANG_REWRITES=true boxlang-miniserver
```

### How URL Rewrites Work

When URL rewrites are enabled:

1. Any request that does not match an asset will route through your specified rewrite file (default: `index.bxm`)
2. This includes requests to JavaScript, CSS, images and BXM, BXS, or BX files.

### URL Rewrite Examples

```javascript
// In your index.bxm (rewrite handler)
switch( cgi.path_info ) {
    case "/":
        // Home page
        include "views/home.bxm";
        break;

    case "/products":
        // Products listing
        include "views/products.bxm";
        break;

    case "/products/":
        // Individual product (extract ID from URL)
        productId = listLast( cgi.path_info, "/" );
        request.productId = productId;
        include "views/product-detail.bxm";
        break;

    default:
        // 404 page
        bx:header statusCode=404;
        include "views/404.bxm";
}
```

### Use Cases for URL Rewrites

* **Single Page Applications (SPAs)** - Route all requests to your main app file
* **Clean URLs** - `/products/123` instead of `/product.bxm?id=123`
* **Custom routing** - Implement your own URL routing logic
* **Framework applications** - Perfect for ColdBox, FW/1, or custom frameworks

### Console Output

When rewrites are enabled, you'll see:

```bash
+ Enabling rewrites to /index.bxm
```

{% hint style="info" %}
**Rewrite Note:** URL rewrites work best for dynamic applications and frameworks. Static websites typically don't need URL rewriting enabled.
{% endhint %}

</details>

## 🗂️ Folder Aliases

Folder aliases map URL path prefixes to arbitrary directories on disk, letting the MiniServer serve static **and** executable BoxLang/CFML content from locations outside the webroot.

### Configuration

Aliases are defined under the `aliases` key in `miniserver.json`. Both a struct and an array form are supported — pick whichever is more readable for your config.

**Struct form** (concise):

```json
{
  "webRoot": "./www",
  "aliases": {
    "/docs": "/var/www/documentation",
    "/shared": "../shared-assets",
    "/api": "/srv/api"
  }
}
```

**Array form** (explicit):

```json
{
  "webRoot": "./www",
  "aliases": [
    { "from": "/docs",   "to": "/var/www/documentation" },
    { "from": "/shared", "to": "../shared-assets" },
    { "from": "/api",    "to": "/srv/api" }
  ]
}
```

### Matching Behavior

* **Longest prefix wins** — with both `/api` and `/api/v2` configured, a request for `/api/v2/spec.json` resolves through `/api/v2`.
* **Segment-boundary aware** — `/docs` matches `/docs` and `/docs/...` but never `/documentation`.
* **Path resolution** — absolute `to` paths are used as-is; relative paths resolve against the `webRoot`.

### Example

Given the struct config above, requests are served from disk like so:

| Request URL            | Served from                                                      |
| ---------------------- | ---------------------------------------------------------------- |
| `/docs/index.bxm`      | `/var/www/documentation/index.bxm`                               |
| `/shared/css/site.css` | `<webRoot>/../shared-assets/css/site.css`                        |
| `/api/v1/users.bxm`    | `/srv/api/v1/users.bxm`                                          |
| `/about.bxm`           | `<webRoot>/about.bxm` *(no alias match — falls back to webroot)* |

{% hint style="info" %}
**Validation:** Alias targets are checked at startup. Entries pointing at a non-existent path or a regular file are logged as a warning and skipped — the server still starts with the remaining valid aliases.
{% endhint %}

## 🛑 Server Management

### Graceful Shutdown

The BoxLang MiniServer supports graceful shutdown for safe server termination:

```bash
# Stop the server gracefully
Press Ctrl+C
```

When you stop the server, you'll see:

```bash
Shutting down BoxLang Server...
BoxLang Server stopped.
```

The graceful shutdown process:

1. **Stops accepting new requests** immediately
2. **Completes active requests** before shutting down
3. **Closes the BoxLang runtime** properly
4. **Releases all resources** (ports, file handles, etc.)

### Background Execution

For production deployments, you can run the server in the background:

```bash
# Run in background (Unix/Linux/Mac)
nohup boxlang-miniserver > server.log 2>&1 &

# Or using screen/tmux
screen -S boxlang-server
boxlang-miniserver

# Or using systemd (Linux)
# Create a service file for automatic startup
```

{% hint style="warning" %}
**Production Note:** For production deployments, consider using process managers like systemd, supervisor, or Docker containers for better service management and automatic restarts.
{% endhint %}

## ⚡ Performance Features

<details>

<summary>Performance Features</summary>

The BoxLang MiniServer includes several built-in performance optimizations:

### Automatic GZIP Compression

The server automatically compresses responses using GZIP compression for better performance:

* **Automatic compression** for responses larger than 1.5KB
* **Smart content detection** - only compresses suitable content types
* **Client support detection** - only compresses when client supports it
* **Bandwidth savings** - typically 60-80% reduction in transfer size

### Performance Characteristics

* **Fast startup times** - typically under 1 second
* **Low memory footprint** - minimal overhead beyond your application
* **High concurrency** - built on Undertow's high-performance architecture
* **Zero-copy static file serving** - optimized static asset delivery
* **Keep-alive connections** - reduces connection overhead

### Performance Tips

```bash
# Allocate more memory for better performance
BOXLANG_MINISERVER_OPTS="-Xmx2g -Xms512m" boxlang-miniserver

# Enable health checks for monitoring
boxlang-miniserver --health-check

# Use environment variables for configuration
export BOXLANG_PORT=8080
export BOXLANG_HOST=0.0.0.0
boxlang-miniserver
```

{% hint style="success" %}
**Performance Tip:** The MiniServer is optimized for development and light production workloads. For high-traffic applications, consider using CommandBox with load balancing and clustering capabilities.
{% endhint %}

### Using 3rd Party Jars <a href="#using-3rd-party-jars-14" id="using-3rd-party-jars-14"></a>

You can load up custom third-party JARs into the runtime in two ways

1. `BOXLANG_HOME/lib` - You can place all the jars that the runtime will load in this location
   1. Remember, you can use the `--serverHome` to choose the location of the server's home
2. Add via the classpath to your runner.

Please note that if you use the `-cp` approach, then you need to use a full `java -cp` syntax or you can customize the `boxlang-miniserver` shell scripts to do your bidding.

If you want to test 3rd part libs with the web server, you’ll need to use a different syntax that uses the `-cp` (classpath) JVM arg and specifies both the boxlang jar AND a semicolon-delimited list of the jars you want to use. It’s a little annoying, but this is how Java works.

```bash
# Format
java -cp {jarpath;jarpath2} ortus.boxlang.web.MiniServer


# Example
java -cp boxlang-miniserver-1.0.0.jar;/path/to/my.jar;/path/to/another.jar ortus.boxlang.web.MiniServer
```

### Modules

The MiniServer can use any module you install into the OS home via the `install-bx-module` binary. However, if you choose your own server home using the `server-home` argument or the environment variable. Then, place the modules inside a `modules` directory inside the server's home.

### JVM Options

You can use the `BOXLANG_MINISERVER_OPTS` env variable to seed the Java arguments the miniserver will start with.

```bash
BOXLANG_MINISERVER_OPTS="-Xmx512m"
boxlang-miniserver
```

### Runtime Source Code

The runtime source code can be found here: <https://github.com/ortus-boxlang/boxlang-miniserver>

We welcome any pull requests, testing, docs, etc.

</details>

## 🌐 Reverse Proxy Setup

<details>

<summary>Reverse Proxy Setup</summary>

For production deployments, it's recommended to place a reverse proxy in front of the BoxLang MiniServer. This provides additional security, SSL termination, load balancing, and better static file serving capabilities.

When MiniServer runs behind a trusted reverse proxy such as Nginx, Traefik, or an AWS Application Load Balancer, enable `useProxyHeaders` so BoxLang can honor the forwarded headers sent by that proxy. The client IP, protocol, and host will then reflect the original request instead of the proxy connection. This setting was added in BoxLang 1.16.0 as part of [BL-2598](https://ortussolutions.atlassian.net/browse/BL-2598).

```json
{
  "useProxyHeaders": true
}
```

{% hint style="warning" %}
Only enable `useProxyHeaders` when requests can reach MiniServer through a trusted proxy. The setting trusts forwarded header values, so exposing MiniServer directly to untrusted clients can allow them to spoof the original request information.
{% endhint %}

### 🔧 Nginx Configuration

Nginx is a popular choice for reverse proxying BoxLang applications:

#### Basic Nginx Configuration

```nginx
# /etc/nginx/sites-available/boxlang-app
server {
    listen 80;
    server_name your-domain.com;

    # Redirect HTTP to HTTPS (recommended)
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    # SSL Configuration
    ssl_certificate /path/to/your/certificate.crt;
    ssl_certificate_key /path/to/your/private.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Security Headers
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

    # Static file serving (optional - let nginx handle static assets)
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        root /var/www/your-app/static;
        expires 1y;
        add_header Cache-Control "public, immutable";
        try_files $uri @boxlang;
    }

    # WebSocket support
    location /ws {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 86400;
    }

    # Health checks (restrict to internal networks if needed)
    location ~ ^/health {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Optional: Restrict health checks to internal IPs
        # allow 10.0.0.0/8;
        # allow 172.16.0.0/12;
        # allow 192.168.0.0/16;
        # deny all;
    }

    # Main application proxy
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;

        # Timeouts
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;

        # Buffer settings
        proxy_buffering on;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }

    # Fallback for static files if not found
    location @boxlang {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

#### Load Balancing with Multiple MiniServers

```nginx
# Upstream configuration for load balancing
upstream boxlang_backend {
    least_conn;
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;

    # Health checks (nginx plus only)
    # health_check interval=10s fails=3 passes=2;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    # SSL and security headers (same as above)

    location / {
        proxy_pass http://boxlang_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

### 🔥 Apache Configuration

Apache HTTP Server with mod\_proxy for reverse proxying:

#### Basic Apache Configuration

```apache
# /etc/apache2/sites-available/boxlang-app.conf
<VirtualHost *:80>
    ServerName your-domain.com

    # Redirect HTTP to HTTPS
    Redirect permanent / https://your-domain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName your-domain.com

    # SSL Configuration
    SSLEngine on
    SSLCertificateFile /path/to/your/certificate.crt
    SSLCertificateKeyFile /path/to/your/private.key
    SSLProtocol TLSv1.2 TLSv1.3
    SSLCipherSuite HIGH:!aNULL:!MD5

    # Security Headers
    Header always set X-Frame-Options DENY
    Header always set X-Content-Type-Options nosniff
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

    # Enable required modules
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

    # WebSocket support
    ProxyRequests Off
    ProxyPreserveHost On

    # WebSocket proxy
    ProxyPass /ws ws://127.0.0.1:8080/ws
    ProxyPassReverse /ws ws://127.0.0.1:8080/ws

    # Health check endpoints
    ProxyPass /health http://127.0.0.1:8080/health
    ProxyPassReverse /health http://127.0.0.1:8080/health

    # Main application proxy
    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

    # Set headers for the backend
    ProxyPassReverse / http://127.0.0.1:8080/
    ProxyPreserveHost On
    ProxyAddHeaders On

    # Static file serving (optional)
    Alias /static /var/www/your-app/static
    <Directory "/var/www/your-app/static">
        Options -Indexes
        AllowOverride None
        Require all granted

        # Cache static files
        <FilesMatch "\.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$">
            ExpiresActive On
            ExpiresDefault "access plus 1 year"
        </FilesMatch>
    </Directory>

    # Error and access logs
    ErrorLog ${APACHE_LOG_DIR}/boxlang-app_error.log
    CustomLog ${APACHE_LOG_DIR}/boxlang-app_access.log combined
</VirtualHost>
```

#### Required Apache Modules

```bash
# Enable required Apache modules
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod expires
sudo a2enmod rewrite

# Enable the site and restart Apache
sudo a2ensite boxlang-app.conf
sudo systemctl reload apache2
```

### 🪟 IIS Configuration

Internet Information Services (IIS) configuration using Application Request Routing (ARR):

#### Prerequisites

1. Install **Application Request Routing (ARR)** module
2. Install **URL Rewrite** module

#### IIS Configuration Steps

1. **Create a new website** in IIS Manager
2. **Configure ARR** at the server level:

```xml
<!-- web.config at server level -->
<configuration>
    <system.webServer>
        <proxy enabled="true" />
        <rewrite>
            <globalRules>
                <rule name="BoxLang Reverse Proxy" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="http://127.0.0.1:8080/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_X_FORWARDED_PROTO" value="https" />
                        <set name="HTTP_X_FORWARDED_FOR" value="{REMOTE_ADDR}" />
                        <set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />
                    </serverVariables>
                </rule>
            </globalRules>
        </rewrite>
    </system.webServer>
</configuration>
```

#### Site-Level web.config

```xml
<!-- web.config for your BoxLang application site -->
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <!-- WebSocket support -->
                <rule name="WebSocket" stopProcessing="true">
                    <match url="ws(.*)" />
                    <action type="Rewrite" url="ws://127.0.0.1:8080/ws{R:1}" />
                </rule>

                <!-- Health check endpoints -->
                <rule name="Health Checks" stopProcessing="true">
                    <match url="health(.*)" />
                    <action type="Rewrite" url="http://127.0.0.1:8080/health{R:1}" />
                </rule>

                <!-- Static files (optional - let IIS handle) -->
                <rule name="Static Files" stopProcessing="true">
                    <match url="^(.*\.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot))$" />
                    <conditions>
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" />
                    </conditions>
                    <action type="None" />
                </rule>

                <!-- Main application -->
                <rule name="BoxLang Application" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="http://127.0.0.1:8080/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_X_FORWARDED_PROTO" value="https" />
                        <set name="HTTP_X_FORWARDED_FOR" value="{REMOTE_ADDR}" />
                        <set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />
                    </serverVariables>
                </rule>
            </rules>
        </rewrite>

        <!-- Security headers -->
        <httpProtocol>
            <customHeaders>
                <add name="X-Frame-Options" value="DENY" />
                <add name="X-Content-Type-Options" value="nosniff" />
                <add name="X-XSS-Protection" value="1; mode=block" />
                <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" />
            </customHeaders>
        </httpProtocol>

        <!-- Static content caching -->
        <staticContent>
            <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" />
        </staticContent>
    </system.webServer>
</configuration>
```

</details>

### 🚀 Production Setup Recommendations

<details open>

<summary>Production Setup Recommendations</summary>

{% stepper %}
{% step %}

#### Configure MiniServer for Production

```bash
# Bind to localhost only (behind reverse proxy)
boxlang-miniserver --host 127.0.0.1 --port 8080 --health-check-secure

# Or using environment variables
export BOXLANG_HOST=127.0.0.1
export BOXLANG_PORT=8080
export BOXLANG_HEALTH_CHECK=true
export BOXLANG_HEALTH_CHECK_SECURE=true
boxlang-miniserver
```

{% endstep %}

{% step %}

#### System Service Setup

Create a systemd service for automatic startup:

```ini
# /etc/systemd/system/boxlang-miniserver.service
[Unit]
Description=BoxLang MiniServer
After=network.target

[Service]
Type=simple
User=boxlang
Group=boxlang
WorkingDirectory=/var/www/your-app
Environment=BOXLANG_HOST=127.0.0.1
Environment=BOXLANG_PORT=8080
Environment=BOXLANG_HEALTH_CHECK=true
Environment=BOXLANG_HEALTH_CHECK_SECURE=true
ExecStart=/usr/local/bin/boxlang-miniserver
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
```

```bash
# Enable and start the service
sudo systemctl enable boxlang-miniserver
sudo systemctl start boxlang-miniserver
sudo systemctl status boxlang-miniserver
```

{% endstep %}

{% step %}

#### Security Considerations

* **Bind to localhost only** when behind a reverse proxy
* **Enable health check security** to restrict detailed information
* **Use HTTPS** at the reverse proxy level
* **Configure proper security headers** in your reverse proxy
* **Restrict health check endpoints** to internal networks if needed
* **Regular security updates** for your reverse proxy software
  {% endstep %}

{% step %}

#### Monitoring and Logging

* **Access logs** at the reverse proxy level
* **Health check monitoring** using `/health/ready` and `/health/live`
* **Performance monitoring** through reverse proxy metrics
* **Log aggregation** for centralized monitoring
  {% endstep %}
  {% endstepper %}

{% hint style="success" %}
**Production Tip:** Using a reverse proxy provides additional benefits like SSL termination, static file serving, request compression, security headers, and load balancing capabilities that complement the BoxLang MiniServer's performance.
{% endhint %}

{% hint style="info" %}
**WebSocket Note:** All reverse proxy configurations include WebSocket support. Make sure your reverse proxy properly handles WebSocket upgrade requests for real-time features to work correctly.
{% endhint %}

</details>


# Spring Boot

Use BoxLang as your Spring Boot view layer, with full framework support built in.

<figure><img src="/files/Zam7ju8y1Q8VrUxy2sle" alt="" width="450"><figcaption></figcaption></figure>

The **BoxLang Spring Boot Starter** is a zero-configuration Spring Boot auto-configuration library that integrates the [BoxLang](https://www.boxlang.io) dynamic JVM language as a view engine inside any Spring Boot 3 web application. Write your templates in BoxLang's expressive `.bxm` markup syntax and let Spring MVC route requests to them — no boilerplate required. You can also leverage any BoxLang features and libraries directly from your Java controllers, services, or any Spring-managed bean by just talking to the `BoxRuntime` API.

```java
BoxRuntime boxlang = BoxRuntime.getInstance();
```

## ✨ Features

* ⚙️ **Zero-configuration auto-configuration** — drop the JAR on the classpath and Spring Boot wires everything automatically via `BoxLangAutoConfiguration`.
* 🖼️ **BoxLang View Resolver** — a `BoxLangViewResolver` resolves logical view names (e.g. `"home"`) to BoxLang `.bxm` templates (e.g. `classpath:/templates/home.bxm`).
* 🌐 **Full web scopes** — templates have access to the complete set of BoxLang web scopes: `URL`, `Form`, `CGI`, `Cookie`, and `Request`.
* 🔗 **Spring Model integration** — every attribute added to the Spring `Model` is automatically injected into the BoxLang `variables` scope, accessible as `#variables.myKey#` in the template.
* 🔄 **Lifecycle-managed runtime** — the `BoxRuntime` starts early in the application lifecycle and shuts down gracefully when the context stops, with no manual wiring needed.
* 🛠️ **Configurable via `application.properties`** — all settings are controlled through the `boxlang.*` property namespace; sensible defaults require no changes for basic use.
* 📄 **Custom `boxlang.json` support** — supply your own BoxLang configuration file via classpath, file URI, or absolute path.
* 🔀 **Pluggable resolver order** — configure the view resolver's position in the Spring MVC resolver chain so BoxLang can coexist with Thymeleaf, FreeMarker, or any other view technology.
* 🏷️ **Spring Boot 3 / Jakarta EE ready** — built against Spring Boot 3.x and the `jakarta.*` namespace.

## 📋 Requirements

<table><thead><tr><th width="374">Dependency</th><th>Version</th></tr></thead><tbody><tr><td>☕ Java</td><td>21+</td></tr><tr><td>🍃 Spring Boot</td><td>3.x+</td></tr><tr><td>🥊 BoxLang</td><td>1.11.0+</td></tr></tbody></table>

{% hint style="info" %}
Make sure `JAVA_HOME` points to a JDK 21+ installation before building or running.
{% endhint %}

## 📦 Installation

### Gradle

```groovy
dependencies {
    implementation 'io.boxlang:boxlang-spring-boot-starter:1.0.0'
}
```

### Maven

```xml
<dependency>
    <groupId>io.boxlang</groupId>
    <artifactId>boxlang-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>
```

{% hint style="success" %}
No `@EnableBoxLang` annotation or manual bean registration is required. Spring Boot's auto-configuration mechanism detects the starter on the classpath and configures everything automatically.
{% endhint %}

## 🚀 Quick Start

Get a BoxLang-powered Spring Boot application running in minutes.

{% stepper %}
{% step %}

### Add the dependency

Add `boxlang-spring-boot-starter` to your project as shown in the [Installation](#installation) section.
{% endstep %}

{% step %}

### Create a Spring MVC controller

```java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HomeController {

    @GetMapping( "/" )
    public String home( Model model ) {
        model.addAttribute( "title", "Hello from BoxLang + Spring Boot!" );
        model.addAttribute( "framework", "Spring Boot 3" );
        return "home"; // resolves to classpath:/templates/home.bxm
    }

    @GetMapping( "/greeting" )
    public String greeting(
        @RequestParam( name = "name", defaultValue = "World" ) String name,
        Model model
    ) {
        model.addAttribute( "name", name );
        model.addAttribute( "message", "Welcome, " + name + "!" );
        return "greeting"; // resolves to classpath:/templates/greeting.bxm
    }

    @GetMapping( "/items" )
    public String items( Model model ) {
        model.addAttribute( "items", java.util.List.of( "Apple", "Banana", "Cherry" ) );
        model.addAttribute( "count", 3 );
        return "items"; // resolves to classpath:/templates/items.bxm
    }
}
```

{% endstep %}

{% step %}

### Create BoxLang templates

Place `.bxm` templates under `src/main/resources/templates/`:

**`src/main/resources/templates/home.bxm`**

```html
<bx:output>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>#variables.title#</title>
</head>
<body>
    <-/tmp Variables are available directly or via the variables scope -->
    <h1>#title#</h1>
    <p>Framework: #framework#</p>
    <p>Rendered at: #dateTimeFormat( now(), "full" )#</p>

    <ul>
        <li><a href="/greeting">Default greeting</a></li>
        <li><a href="/greeting?name=Developer">Greeting with name</a></li>
        <li><a href="/items">Items list</a></li>
    </ul>
</body>
</html>
</bx:output>
```

**`src/main/resources/templates/greeting.bxm`**

```html
<bx:output>
<h2>#message#</h2>
<p><a href="/">Back Home</a></p>
</bx:output>
```

**`src/main/resources/templates/items.bxm`**

```html
<bx:output>
<h2>Items (#count#)</h2>
<ul>
    <bx:loop array="#items#" item="itemName">
        <li>#itemName#</li>
    </bx:loop>
</ul>
<p><a href="/">Back Home</a></p>
</bx:output>
```

{% endstep %}

{% step %}

### Run your application

Start your Spring Boot application as usual.

> **Important JVM Requirements:** BoxLang requires reflective access to JDK internals. Ensure you pass the following JVM arguments when starting the application:
>
> ```
> --add-opens java.base/java.lang=ALL-UNNAMED
> --add-opens java.base/java.lang.reflect=ALL-UNNAMED
> ```
>
> In a Gradle project, this can be added to your `bootRun` task:
>
> ```groovy
> bootRun {
>     jvmArgs = [
>         '--add-opens', 'java.base/java.lang=ALL-UNNAMED',
>         '--add-opens', 'java.base/java.lang.reflect=ALL-UNNAMED'
>     ]
> }
> ```

Navigate to `http://localhost:8080` in your browser.
{% endstep %}
{% endstepper %}

## ⚙️ Configuration (`application.properties`)

The starter registers `BoxLangProperties` under the `boxlang.*` namespace.

| Property                      | Type      | Default                 | Description                                                                                                                                                                                           |
| ----------------------------- | --------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `boxlang.prefix`              | `String`  | `classpath:/templates/` | Directory path where `.bxm` templates are located.                                                                                                                                                    |
| `boxlang.suffix`              | `String`  | `.bxm`                  | File extension for BoxLang templates.                                                                                                                                                                 |
| `boxlang.config-path`         | `String`  | *(none)*                | Location of the BoxLang runtime configuration file (e.g., `classpath:/boxlang.json`). If not set, it defaults to checking `classpath:/boxlang.json` and then falls back to internal runtime defaults. |
| `boxlang.debug-mode`          | `boolean` | `false`                 | Enables BoxLang debug mode. Useful for development logging.                                                                                                                                           |
| `boxlang.view-resolver-order` | `int`     | `2147483642`            | The priority of the BoxLang view resolver in Spring’s resolver chain. Default is `Ordered.MAX_VALUE - 5`.                                                                                             |
| `boxlang.runtime-home`        | `String`  | *(none)*                | Overrides the global `BOXLANG_HOME` environment directory.                                                                                                                                            |

### Example `application.properties`

```properties
boxlang.prefix=classpath:/templates/
boxlang.suffix=.bxm
boxlang.config-path=classpath:/boxlang.json
boxlang.debug-mode=false
boxlang.view-resolver-order=1

logging.level.ortus.boxlang=WARN
logging.level.org.springframework.web=INFO
```

## 📄 BoxLang Configuration (`boxlang.json`)

If no `boxlang.config-path` is set, the auto-configuration probes for `classpath:/boxlang.json` automatically. If that file is absent, BoxLang starts with its built-in defaults.

Place `boxlang.json` at `src/main/resources/boxlang.json` to customise language behaviour. For more info, please see the [Configuration](/getting-started/configuration) documentation.

## 🌐 Template Scopes & Model Integration

BoxLang templates rendered through the view engine have access to all standard BoxLang web scopes:

| Scope       | Description                                                          |
| ----------- | -------------------------------------------------------------------- |
| `variables` | Contains all Spring `Model` attributes plus template-local variables |
| `url`       | Query string parameters from the HTTP request                        |
| `form`      | Form POST data                                                       |
| `cgi`       | CGI/server environment variables                                     |
| `cookie`    | HTTP cookies                                                         |
| `request`   | Request-scoped storage (per HTTP request)                            |

**Accessing Spring Model attributes:**

```html
<bx:output>
    <-/tmp Both forms are equivalent -->
    <p>#variables.title#</p>
    <p>#title#</p>

    <-/tmp Access URL query params -->
    <p>Page: #url.page ?: 1#</p>

    <-/tmp Access cookies -->
    <p>Theme: #cookie.theme ?: "light"#</p>
</bx:output>
```

{% hint style="warning" %}
**Security tip:** Always use `encodeForHTML()` when outputting user-supplied values (e.g., URL or form parameters) to prevent XSS attacks.
{% endhint %}

## 🔥 Hot-Reloading Templates

By default, `boxlang.prefix` points at `classpath:/templates/`, which resolves to the compiled output directory (`build/resources/main/templates/`). Editing a `.bxm` source file has no effect until your build tool copies the updated resource — meaning a restart is usually required.

**To get instant hot-reload without a restart**, switch the prefix to a `file:` path that points directly at the source tree using a Spring dev profile.

### 1. Create `src/main/resources/application-dev.properties`

```properties
# Load templates directly from the source tree — edits take effect on the next request
boxlang.prefix=file:src/main/resources/templates/

# Enable BoxLang debug mode in development
boxlang.debug-mode=true

# Verbose logging in development
logging.level.ortus.boxlang=DEBUG
logging.level.org.springframework.web=DEBUG
```

### 2. Activate the dev profile

```bash
# Pass it as a command-line argument (Gradle example)
./gradlew bootRun --args='--spring.profiles.active=dev'

# Or set it permanently during development in application.properties
echo 'spring.profiles.active=dev' >> src/main/resources/application.properties
```

{% hint style="danger" %}
Keep the `classpath:` prefix for production. The `file:` path works for local development but must not be used in packaged JARs or containers where the source tree is not present.
{% endhint %}

## 🔍 How It Works

1. **Auto-configuration** — `BoxLangAutoConfiguration` is registered and activates on any Servlet-based Spring web application.
2. **Runtime lifecycle** — the `BoxRuntime` is started very early in the application lifecycle, ensuring it is ready before the first HTTP request arrives. It shuts down gracefully when the application context stops.
3. **View resolution** — `BoxLangViewResolver` resolves logical view names to resources using the configured `prefix` + `viewName` + `suffix` pattern. If the resource does not exist, it returns `null` and Spring continues to the next resolver in the chain, enabling seamless coexistence with other view technologies like Thymeleaf or FreeMarker.
4. **Template rendering** — `BoxLangView` wraps the `HttpServletRequest` and `HttpServletResponse` in a `SpringBoxHTTPExchange`, constructs a `WebRequestBoxContext` (which exposes all BoxLang web scopes), injects the Spring `Model` map into the `variables` scope, executes the template, and flushes the output buffer to the servlet response.


# Try BoxLang!

https\://try.boxlang.io

<figure><img src="/files/0vq4vC7szC6QgXQ6Zt2x" alt=""><figcaption></figcaption></figure>

Interested in playing with BoxLang? You can test the syntax in a BoxLang interpreter hosted on AWS Lambda over at [try.boxlang.io](https://try.boxlang.io/). These two micro-services have been written with BoxLang as well.

<figure><img src="/files/h8yprmmbNYcP1lLL7fVu" alt=""><figcaption><p>try.boxlang.io</p></figcaption></figure>

{% hint style="success" %}
Our BoxLang playground was built with our AWS Lambda runtime microservice and our BoxLang Docker Containers.
{% endhint %}

{% hint style="info" %}
Want a guided, hands-on learning path after the playground? Use [BoxLings](https://github.com/ortus-boxlang/boxlings), our interactive CLI exercise tool for learning BoxLang fundamentals.
{% endhint %}


# MatchBox

## What is MatchBox?

MatchBox is a **native Rust implementation** of the [BoxLang](https://github.com/ortus-boxlang/BoxLang) programming language. It lets you write BoxLang scripts (`.bxs`) and run them as blazing-fast, standalone applications — with no JVM, no Java installation, and no runtime overhead.

<https://github.com/ortus-boxlang/matchbox>

### The Problem it Solves

The main BoxLang runtime runs on the JVM, which brings excellent ecosystem access and dynamic power, but also brings weight: a JVM on the host machine, startup latency, and memory overhead. MatchBox is designed for scenarios where none of that is acceptable:

* **Edge deployments** where cold-start time and binary size are critical.
* **CLI tools** that need to ship as a single, zero-dependency binary.
* **Browser apps** where you want to run BoxLang logic natively via WebAssembly.
* **Embedded systems or containers** with minimal compute resources.

### Quick Install

These scripts will prompt you to choose between the **Latest Release** or **Snapshot** version and will install the full **Fat CLI** (which includes runner stubs for all deployment targets).

**Linux / macOS:**

```bash
curl -sSL https://raw.githubusercontent.com/ortus-boxlang/matchbox/master/install/install.sh | bash
```

**Windows (PowerShell):**

```powershell
iex (Invoke-RestMethod -Uri https://raw.githubusercontent.com/ortus-boxlang/matchbox/master/install/install.ps1)
```

### How it Works

MatchBox is a complete, self-contained language toolchain:

1. **Parser** — A [Pest](https://pest.rs/) PEG grammar reads `.bxs` source files and produces an AST.
2. **Compiler** — A multi-stage compiler lowers the AST into a compact bytecode format.
3. **VM** — A stack-based Bytecode Virtual Machine executes the bytecode with a cooperative fiber scheduler for high-concurrency async operations.
4. **Targets** — The same bytecode can be embedded in a native binary, run inside a WASM runtime, or executed directly by the MatchBox runner.

### The MatchBox Philosophy

| Property                 | MatchBox           | BoxLang (JVM)  |
| ------------------------ | ------------------ | -------------- |
| Runtime dependency       | None               | JVM required   |
| Startup time             | Milliseconds       | Seconds        |
| Binary size              | \~500 KB           | Full JVM stack |
| Java interop             | Experimental (JNI) | Full           |
| WASM/browser support     | ✅                  | ❌              |
| Strict subset of BoxLang | ✅                  | Full language  |

### One-Way Compatibility

MatchBox implements a **strict subset** of the BoxLang language. Code written for MatchBox will generally run unmodified on the main BoxLang JVM runtime. Code written for the JVM runtime may use features not yet present in MatchBox.

Think of MatchBox as a "portable and deployable" profile of BoxLang — you target MatchBox when distribution, performance, or JVM-independence is a requirement.\
\
Compatibility is growing quickly so be sure to check back often or submit a request for feature parity.

### What You Can Build

* **CLI tools** — compile to a single native binary and distribute without any installer.
* **Serverless functions** — ultra-small cold start, ideal for AWS Lambda, Cloudflare Workers, or Fastly Compute.
* **Browser applications** — run BoxLang logic directly in the browser via a WASM module.
* **Native Fusion apps** — mix BoxLang with hand-written Rust for peak performance.


# WASM in the Browser

Learn to deploy BoxLang in the browser using WASM and MatchBox

## JavaScript + WebAssembly

MatchBox can compile BoxLang for the browser and Node.js via WebAssembly. There are three distinct modes, chosen to match different use-cases.

| Mode                   | Command                                 | Use case                                         |
| ---------------------- | --------------------------------------- | ------------------------------------------------ |
| **JS Module (AOT)**    | `--target js`                           | Ship a pre-compiled BoxLang app as an ES module  |
| **WASM binary (AOT)**  | `--target wasm`                         | Raw `.wasm` binary, brought your own loader      |
| **Runtime (JIT-like)** | Build `pkg/` once, call `run_boxlang()` | Execute source strings at runtime in the browser |

***

### Mode 1: JavaScript ES Module (AOT)

This is the recommended way to ship a BoxLang application to the browser. MatchBox compiles your script to bytecode, embeds it in a WASM binary, and wraps it in a JavaScript ES module that bootstraps the runtime automatically.

#### Compile

```bash
matchbox --target js my_lib.bxs
# Produces: my_lib.js  +  my_lib.wasm
```

#### Use in HTML

```html
<!DOCTYPE html>
<html>
<head><title>BoxLang App</title></head>
<body>
<script type="module">
    import { greet, calculate } from './my_lib.js';

    const result = await greet("Developer");
    document.body.textContent = result;
</script>
</body>
</html>
```

#### Use in Node.js

```js
import { greet } from './my_lib.js';

const message = await greet("Node");
console.log(message);
```

#### Exporting Functions

BoxLang functions defined at the top level of your script are automatically exported. Access modifiers have no effect on WASM exports — all functions are accessible:

```boxlang
// my_lib.bxs

function greet(name) {
    return "Hello, " & name & "!"
}

function calculate(a, b) {
    return a * b
}
```

***

### Mode 2: Raw WASM Binary (AOT)

Use `--target wasm` when you want the raw `.wasm` file and full control over how it is loaded. This is useful for integration with non-standard JS runtimes, edge platforms, or when you are bundling the WASM via a tool like Webpack or Vite.

```bash
matchbox --target wasm my_app.bxs
# Produces: my_app.wasm
```

Load it manually using the standard WebAssembly API:

```js
const response = await fetch('./my_app.wasm');
const buffer   = await response.arrayBuffer();
const module   = await WebAssembly.instantiate(buffer, importObject);
```

Refer to the [MDN WebAssembly docs](https://developer.mozilla.org/en-US/docs/WebAssembly) for the full instantiation API.

***

### Mode 3: Runtime Mode (Dynamic Execution)

In runtime mode you ship the MatchBox engine itself (`pkg/`) and execute BoxLang source code dynamically at run time — similar to a JIT. This is useful for:

* Allowing user-provided BoxLang scripts in your application.
* Interactive BoxLang playgrounds.
* Server-side rendering on a WASM-capable edge runtime.

#### HTML Integration

```html
<script type="module">
    import init, { run_boxlang } from './pkg/matchbox.js';

    await init();   // load and compile the WASM runtime

    run_boxlang(`
        name = "Browser"
        println("Hello from BoxLang running in #name#!")
    `);
</script>
```

#### Persistent VM (calling functions by name)

For apps that need to call multiple BoxLang functions efficiently, use the persistent `BoxLangVM` instance rather than re-initialising on every call:

```js
import init, { BoxLangVM } from './pkg/matchbox.js';

await init();

const vm = new BoxLangVM();

// Load a script once  
vm.load_source(`
    function add(a, b) { return a + b }
    function greet(name) { return "Hello, " & name }
`);

// Call functions by name as many times as you like
const sum     = vm.call("add",   [10, 20]);
const message = vm.call("greet", ["BoxLang"]);

console.log(sum, message);
```

***

### JavaScript Interop from BoxLang

When BoxLang code is running inside a browser WASM context, it can access the JavaScript environment through the `js` global:

```boxlang
// DOM access
title = js.document.title
js.document.getElementById("output").innerText = "Updated by BoxLang"

// Browser APIs
js.alert("Hello!")
js.console.log("Logged from BoxLang")

// Location
url = js.window.location.href
```

> `js.*` is only available in browser WASM. Using it in a native build throws a runtime error.

***

### Serving Locally for Development

Browsers block WASM file loading over `file://`. Serve your project with any local HTTP server:

```bash
npx serve .
# or
python3 -m http.server 8080
```

Then open `http://localhost:8080` in your browser.

***

### Production Deployment

The WASM output files (`*.js` + `*.wasm`) can be deployed to any static hosting service:

* **CDN** — Upload to S3, Cloudflare R2, or a similar object store.
* **Vercel / Netlify** — Drop the files into your project's output directory.
* **Edge Workers** — The raw WASM binary can be loaded directly into Cloudflare Workers or similar runtimes. See WASM Container for details.

Ensure your server sets the correct `Content-Type` for `.wasm` files:

```
Content-Type: application/wasm
```

Most modern hosts handle this automatically.


# WASM Container

Learn how to run BoxLang in a WASM container using MatchBox

## WASM Container Deployment

MatchBox WASM binaries can be run as standalone server-side workloads using WASM-native runtimes like [Wasmtime](https://wasmtime.dev/), [WasmEdge](https://wasmedge.org/), or inside minimal OCI containers using the WASM OCI image spec.

This deployment model is ideal for:

* **Serverless / FaaS** — minimal cold-start, no OS dependencies.
* **Edge computing** — run BoxLang logic at the network edge (Fastly Compute, Cloudflare Workers via WASI).
* **Microservices** — tiny, hermetically isolated workloads without a full OS stack.

***

### Compiling for WASM/WASI

Use `--target wasm` to produce a raw `.wasm` binary:

```bash
matchbox --target wasm my_service.bxs
# Produces: my_service.wasm
```

The resulting binary contains the MatchBox VM core and your compiled BoxLang bytecode in a custom WASM section. It has no external JS dependencies and can be loaded by any WASM runtime that supports the WASI preview1 interface.

***

### Running with Wasmtime

[Wasmtime](https://wasmtime.dev/) is the reference WASI runtime. Install it and run your binary directly:

```bash
# Install Wasmtime (macOS / Linux)
curl https://wasmtime.dev/install.sh -sSf | bash

# Run your app
wasmtime my_service.wasm
```

Grant filesystem access if your app reads or writes files:

```bash
wasmtime --dir=. my_service.wasm
```

Grant network access (Wasmtime 14+):

```bash
wasmtime --wasi-modules=experimental-wasi-sockets my_service.wasm
```

***

### Running with WasmEdge

[WasmEdge](https://wasmedge.org/) is optimized for cloud-native and microservice workloads:

```bash
# Install WasmEdge
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash

# Run
wasmedge my_service.wasm
```

***

### Docker / OCI Container

MatchBox WASM binaries can be run inside minimal OCI containers. Because the WASM runtime handles everything, the container image needs only the binary itself — no OS, no shell, no libc.

#### Example Dockerfile

```dockerfile
FROM scratch

COPY my_service.wasm /my_service.wasm

ENTRYPOINT ["/my_service.wasm"]
```

Build and run with a WASM-capable container runtime:

```bash
docker build -t my-boxlang-service .
docker run --runtime=io.containerd.wasmtime.v1 my-boxlang-service
```

> **Note:** Standard Docker uses runc by default. To run WASM containers you need a WASM-compatible runtime shim such as [`containerd-shim-wasmtime`](https://github.com/containerd/runwasi) or Docker Desktop's built-in WASM support.

#### Docker Desktop (Built-in WASM Support)

Docker Desktop 4.15+ includes native WASM support via `docker run`:

```bash
docker run --runtime=io.containerd.wasmtime.v1 \
    --platform=wasi/wasm32 \
    my-boxlang-service
```

#### Pushing to a Registry

WASM OCI images can be pushed to any OCI-compatible registry:

```bash
docker push ghcr.io/your-org/my-boxlang-service:latest
```

***

### Limitations

| Feature           | WASM Container  | Notes                                                        |
| ----------------- | --------------- | ------------------------------------------------------------ |
| Java interop      | ❌ Not supported | No JNI in WASM                                               |
| Native Fusion     | ✅ Partial       | Rust interop is valid for any Rust code that can run in WASM |
| DOM / `js.*` APIs | ❌ Not available | JS interop requires a browser context                        |
| Filesystem access | ✅ Via WASI      | Requires runtime `--dir` grants                              |
| Network access    | ⚠️ Experimental | WASI sockets are in preview                                  |
| `sleep()` / async | ✅               | Cooperative fiber scheduler works in WASI                    |


# ESP32

Learn how BoxLang can be deployed to ESP32 devices.

## Building for ESP32

MatchBox supports building and flashing BoxLang scripts directly to ESP32 microcontrollers. This is achieved by cross-compiling a specialized MatchBox runner for the Xtensa or RISC-V architectures and deploying your compiled bytecode to a dedicated flash partition.

### Prerequisites

To build for ESP32, you must have the following installed on your development machine:

1. **Rust ESP32 Toolchain**: Install using `espup`:

   ```bash
   cargo install espup
   espup install
   # Follow instructions to source the export-esp.sh script
   ```
2. **espflash**: For flashing the binary to the device. Version 3.3.0+ is required.
3. **ESP-IDF Prerequisites**: Standard C build tools, Python, and CMake (required for the `esp-idf-sys` crate).

#### WSL Users (USB Access)

If you are using Windows Subsystem for Linux (WSL), you must "attach" your USB device to the Linux instance using `usbipd-win`.

From a **Windows Administrator PowerShell**:

```powershell
usbipd list
usbipd attach --busid <BUSID> --auto-attach
```

### Building and Flashing

Use the `--target esp32` flag to trigger an ESP32 build. You should always specify your chip type via `--chip` (e.g., `esp32`, `esp32s3`, `esp32c3`).

#### 1. Initial Setup (Full Flash)

The first time you flash a device, you must perform a "Full Flash." This installs the MatchBox Runner firmware and the custom partition table required for BoxLang.

```bash
matchbox app.bxs --target esp32 --chip esp32s3 --full-flash
```

*Note: `--full-flash` implicitly triggers the flash process.*

#### 2. Fast Deployment (Default)

Once the Runner is on the device, you only need to update the BoxLang bytecode. This takes \~1 second and does not require re-flashing the firmware.

```bash
matchbox app.bxs --target esp32 --chip esp32s3 --flash
```

### Watch Mode (Live Coding)

MatchBox features a built-in watch mode that provides a "Hot Reload" experience for physical hardware.

```bash
matchbox app.bxs --target esp32 --chip esp32s3 --watch
```

**What Watch Mode does:**

1. **Initial Flash**: Performs a fast-deploy of your script.
2. **Integrated Monitor**: Automatically opens `espflash monitor` and performs a hardware reset.
3. **Auto-Update**: Watches your directory for `.bxs` changes. Upon save, it kills the monitor, flashes the new bytecode in 1s, and restarts the monitor/reset cycle.

### How it Works

1. **Compilation**: Your `.bxs` script is compiled into `.bxb` bytecode using the **Postcard** serialization format, ensuring 64-bit to 32-bit architecture compatibility.
2. **Partitioning**: MatchBox uses a custom partition table (`partitions.csv`) that reserves a 1MB `storage` partition at offset `0x110000` for bytecode.
3. **Runtime**: The ESP32 Runner starts a dedicated FreeRTOS task with a **48KB stack** to host the MatchBox VM.
4. **Environment Awareness**: The BoxLang `server` scope is automatically populated with hardware information (e.g., `server.os.arch` will return `xtensa` or `riscv`).

### Memory and Performance

* **SRAM**: ESP32 devices have limited memory (usually 520KB). The VM is configured with a large stack to prevent overflows, but you should still be mindful of creating massive arrays.
* **Flash**: The VM and runtime add roughly 800KB - 1.2MB to the firmware size. The bytecode is stored separately in the 1MB `storage` partition.

### Native Hardware Access

Standard BoxLang BIFs (Built-in Functions) like `println` are mapped to the ESP32's serial console. To access hardware pins (GPIO, I2C, WiFi), you can use **Native Fusion** or use a BoxLang module that provides hardware wrappers.


# Compiled Native Binaries

Learn to build compiled native binaries with MatchBox

## Native Builds

MatchBox can compile your BoxLang application into a **single, self-contained native binary** for your operating system. The resulting executable requires no JVM, no MatchBox installation, and no runtime dependencies of any kind.

***

### How it Works

MatchBox uses a **runner stub** architecture to produce lean binaries:

1. A pre-compiled, stripped, architecture-specific runner stub (\~500 KB) contains only the VM core.
2. The `matchbox` compiler compiles your `.bxs` source to bytecode.
3. The bytecode is appended to the end of the stub binary.
4. At startup, the stub reads its own trailing bytes, finds the embedded bytecode, and executes it.

This means no intermediate files, no installers, and no external loaders — just a single file you can `chmod +x` and ship.

***

### Building a Native Binary

```bash
matchbox --target native my_app.bxs
```

This produces an executable named after your input file (e.g., `my_app` on macOS/Linux, `my_app.exe` on Windows).

#### Full Example

Create `cli_tool.bxs`:

```boxlang
println("MatchBox CLI Tool")
println("Running on MatchBox " & matchbox.version)

for (i = 1; i <= 5; i++) {
    println("Step #i# complete")
}
```

Compile:

```bash
matchbox --target native cli_tool.bxs
```

Run:

```bash
./cli_tool
MatchBox CLI Tool
Step 1 complete
Step 2 complete
Step 3 complete
Step 4 complete
Step 5 complete
```

***

### Cross-Compilation

Native binaries are platform-specific. To produce binaries for other targets you have two options:

#### Option A: GitHub Actions (recommended)

Use the included GitHub Actions workflow. Every tagged release automatically builds binaries for:

* `x86_64-unknown-linux-gnu`
* `aarch64-unknown-linux-gnu`
* `x86_64-apple-darwin`
* `aarch64-apple-darwin`
* `x86_64-pc-windows-msvc`

#### Option B: Manual Cross-Compilation

Add the desired Rust target and build:

```bash
rustup target add x86_64-unknown-linux-gnu
cargo build --release --target x86_64-unknown-linux-gnu
```

Note: cross-compilation may require a cross-linker for the target platform. The [`cross`](https://github.com/cross-rs/cross) tool simplifies this via Docker:

```bash
cargo install cross
cross build --release --target x86_64-unknown-linux-gnu
```

***

### Binary Size

MatchBox applies aggressive size optimizations in the release profile:

```toml
[profile.release]
opt-level    = "z"   # Optimize for size
lto          = true  # Link-Time Optimization
codegen-units = 1    # Better dead-code elimination
panic        = "abort"
strip        = true  # Strip symbols
```

The resulting binaries are typically **\~500 KB** — small enough to ship as a GitHub release asset or embed in a container image.

***

### Native Fusion: Rust Interop

**Native Fusion** lets you write performance-critical functions in Rust and expose them as BoxLang BIFs (Built-In Functions), all statically linked into your final binary.

> For the full macro and API reference, see Native Fusion Reference.

#### When to Use It

* You need maximum throughput for a hot path (e.g., data parsing, compression, crypto).
* You want to use a Rust crate (e.g., `serde`, `reqwest`, `image`) from BoxLang.
* You need direct access to OS or hardware APIs.

#### Setting Up a Native Fusion Project

1. Create your BoxLang entry point, e.g., `app.bxs`.
2. Create a `native/` directory alongside it.
3. Write one or more `.rs` files inside `native/`.

When MatchBox detects the `native/` directory, it compiles the Rust files together with the VM and links everything into the final binary.

#### Writing a Native BIF

Each file in `native/` must expose a `register_bifs` function that returns a map of function names to implementations:

```rust
// native/math.rs
use matchbox_vm::types::{BxValue, BxVM, BxNativeFunction};
use std::collections::HashMap;

/// Compute the factorial of a non-negative integer.
pub fn factorial(_vm: &mut dyn BxVM, args: &[BxValue]) -> Result<BxValue, String> {
    let n = args
        .first()
        .map(|v| v.as_number())
        .ok_or("factorial: expected a number argument")? as u64;

    let result = (1..=n).product::<u64>();
    Ok(BxValue::new_number(result as f64))
}

pub fn register_bifs() -> HashMap<String, BxNativeFunction> {
    let mut map = HashMap::new();
    map.insert("factorial".to_string(), factorial as BxNativeFunction);
    map
}
```

Call it from BoxLang like any other BIF:

```boxlang
println(factorial(10))   // 3628800
```

#### Build

```bash
matchbox --target native app.bxs
```

MatchBox automatically detects `native/`, compiles the Rust code, merges the BIF registrations, and produces the final binary. No extra tooling needed.

***

### Experimental Java Interop (JNI)

In native builds only, MatchBox includes an experimental JNI bridge that lets you instantiate Java classes and call methods — provided a compatible JVM is installed on the host machine at runtime.

> **This feature is highly experimental.** APIs may change and stability is not guaranteed.

```boxlang
// Instantiate a Java class via JNI
sb = java.new("java.lang.StringBuilder", "Hello")
sb.append(", World!")
println(sb.toString())    // Hello, World!
```

This is not available in WASM builds.


# BoxLang Cloud Servers

BoxLang has official cloud servers that you can run your applications on.

Setting up BoxLang servers on various cloud platforms involves a series of steps to ensure efficient deployment and management. Below is a brief introduction to setting up BoxLang servers on AWS, Azure, Google Cloud, and IBM Cloud. You can find much more information here: <https://boxlang.io/hosting>

{% embed url="<https://boxlang.io/hosting>" %}

<figure><img src="/files/PdvUkVrtRVNIuupBYdL2" alt=""><figcaption></figcaption></figure>

BoxLang Cloud Servers provide ready-to-use virtual machines optimized for running BoxLang applications. Available on multiple cloud platforms with both Windows and Ubuntu configurations, these solutions streamline deployment and offer seamless scalability for developers and enterprises.

```mermaid
graph TB
    subgraph "Internet"
        U[Users/Clients]
    end
    
    subgraph "Cloud Provider"
        subgraph "Load Balancer"
            LB[Load Balancer<br/>HTTP/HTTPS Traffic]
        end
        
        subgraph "BoxLang Instances"
            VM1[BoxLang VM 1<br/>Ubuntu/Windows]
            VM2[BoxLang VM 2<br/>Ubuntu/Windows]
            VM3[BoxLang VM 3<br/>Ubuntu/Windows]
        end
        
        subgraph "Database Layer"
            DB[(Database<br/>MySQL/PostgreSQL)]
        end
        
        subgraph "Storage"
            S3[Object Storage<br/>Files & Assets]
        end
    end
    
    U --> LB
    LB --> VM1
    LB --> VM2
    LB --> VM3
    VM1 --> DB
    VM2 --> DB
    VM3 --> DB
    VM1 --> S3
    VM2 --> S3
    VM3 --> S3
```

## **Available Platforms:**

* **Amazon Web Services (AWS)** - Ubuntu & Windows AMIs
* **Microsoft Azure** - Ubuntu Virtual Machines
* **Google Cloud Platform** - Coming Soon

### Key Features & Advantages

* Pre-configured & optimized - Instantly deploy a fully set-up BoxLang runtime.
* Cloud-ready & scalable - Take full advantage of a powerful infrastructure.
* Enterprise-grade security - Enhanced protection for a reliable environment.
* Cost-effective - Pay only for the resources you actually use.

***

## [Amazon Web Services](/getting-started/boxlang-cloud-servers/amazon-web-services)

AWS offers Elastic Compute Cloud (EC2) instances for running BoxLang servers. To deploy:

1. Launch an EC2 instance within your desired region.
2. Choose an appropriate instance type (e.g., t2.micro for low traffic).
3. Configure security groups to allow relevant traffic on required ports (e.g., HTTP, HTTPS).

## [Azure](/getting-started/boxlang-cloud-servers/microsoft-azure)

Azure provides Virtual Machines (VMs) for hosting BoxLang:

1. Create a virtual machine (VM) in the Azure Portal with the required resources.
2. Select a suitable VM size based on your specific needs.
3. Set up network security groups to manage inbound and outbound traffic.

## [Google Cloud](/getting-started/boxlang-cloud-servers/google-cloud)

Google Cloud offers Compute Engine virtual machines for BoxLang deployment:

1. Create a VM instance via the Google Cloud Console.
2. Choose machine type and region accordingly.
3. Set firewall rules for your server requests.

Each platform provides comprehensive documentation and support to guide you through specific setup requirements and optimizations.


# Microsoft Azure

BoxLang Cloud Servers for Microsoft Azure

Azure Virtual Machines (Azure VMs) are an Infrastructure as a Service (IaaS) offering for computing, providing more control over your cloud resources. With this service, you can pay as you go or make an annual reservation. However, if you would like more detailed information about this service, you can refer to [this](https://learn.microsoft.com/en-us/azure/virtual-machines/overview).

### Ubuntu 24.04 LTS based

#### BoxLang MiniServer on Ubuntu 24.04 LTS

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/ortus.boxlang-miniserver-ubuntu?tab=Overview).

#### BoxLang with CommandBox on Ubuntu 24.04 LTS

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in the Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/ortus.boxlang-with-commandbox-ubuntu?tab=Overview).

### Windows Server 2019 based

#### BoxLang MiniServer on Windows 2019

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/ortus.boxlang-miniserver-windows?tab=Overview).

#### BoxLang with CommandBox on Windows 2019

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/ortus.boxlang-with-commandbox-windows?tab=Overview).

### Red Hat 8 based

#### BoxLang MiniServer on Red Hat 8

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/ortus.boxlang-miniserver-redhat?tab=Overview).

#### BoxLang with CommandBox on Red Hat 8

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/ortus.boxlang-with-commandbox-redhat?tab=Overview).

Learn how to deploy Windows Server-based BoxLang Cloud Servers [here](https://cloud-servers.ortusbooks.com/microsoft/windows-based-images).


# Amazon Web Services

BoxLang Cloud Servers for Amazon Web Services

Azure Virtual Machines (Azure VMs) are an Infrastructure as a Service (IaaS) offering for computing, providing more control over your cloud resources. With this service, you can pay as you go or make an annual reservation. However, if you would like more detailed information about this service, you can refer to [this](https://learn.microsoft.com/en-us/azure/virtual-machines/overview).

## Ubuntu 24.04 LTS based

#### BoxLang MiniServer on Ubuntu 24.04 LTS

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-k5mclsajbxqaa?sr=0-7\&ref_=beagle\&applicationId=AWSMPContessa).

#### BoxLang with CommandBox on Ubuntu 24.04 LTS

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). Review[ our offer in AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-juvpk6ysaxl5e?sr=0-5\&ref_=beagle\&applicationId=AWSMPContessa).

## Windows Server 2019 based

#### BoxLang MiniServer on Windows 2019

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-jm57yzrnbubgo?sr=0-4\&ref_=beagle\&applicationId=AWSMPContessa).

#### BoxLang with CommandBox on Windows 2019

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-hd4jh62surh2g?sr=0-6\&ref_=beagle\&applicationId=AWSMPContessa).

## Red Hat 8 based

#### BoxLang MiniServer on Red Hat 8

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-ynpwc2pyatybs?sr=0-8\&ref_=beagle\&applicationId=AWSMPContessa).

#### BoxLang with CommandBox on Red Hat 8

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-vj44e6ktz3ynu?sr=0-9\&ref_=beagle\&applicationId=AWSMPContessa).

Learn how to deploy Windows Server-based BoxLang Cloud Servers [here](https://cloud-servers.ortusbooks.com/aws/windows-based-images).


# Google Cloud

BoxLang Cloud Servers for Google Cloud

Google Virtual Machines are an Infrastructure as a Service (IaaS) offering for computing, providing more control over your cloud resources. With this service, you can pay as you go or make an annual reservation. However, if you would like more detailed information about this service, you can refer to [this](https://cloud.google.com/products/compute?hl=en).

### Ubuntu 24.04 LTS based

#### BoxLang MiniServer on Ubuntu 24.04 LTS

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/ortussolutions-public/boxlang-miniserver-ubuntu?inv=1\&invt=Ab31kg).

#### BoxLang with CommandBox on Ubuntu 24.04 LTS

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/ortussolutions-public/boxlang-with-commandbox-ubuntu?inv=1\&invt=Ab31kg).

### Windows Server 2019 based

#### BoxLang MiniServer on Windows 2019

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/ortussolutions-public/boxlang-miniserver-windows?inv=1\&invt=Ab31kg).

#### BoxLang with CommandBox on Windows 2019

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/ortussolutions-public/boxlang-with-commandbox-windows?inv=1\&invt=Ab31kg).

### Red Hat 8 based

#### BoxLang MiniServer on Red Hat 8

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang MiniServer. Additionally, you can connect to your Virtual Machine to develop and manage it. [Review our offer in Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/ortussolutions-public/boxlang-miniserver-redhat?inv=1\&invt=Ab31kg).

#### BoxLang with CommandBox on Red Hat 8

Run BoxLang applications, scheduled tasks, scripting, CFML applications, and more with BoxLang as the Engine in CommandBox. Also, you can connect to your Virtual Machine to manage and boost your Software Development Life Cycle (SDLC). [Review our offer in Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/ortussolutions-public/boxlang-with-commandbox-redhat?inv=1\&invt=Ab31kg).

Learn how to deploy Windows Server-based BoxLang Cloud Servers [here](https://cloud-servers.ortusbooks.com/microsoft/windows-based-images).


# IDE & Tooling

Welcome to the world of BoxLang Tooling!

Welcome to the comprehensive BoxLang tooling ecosystem! This section covers all the tools, IDE integrations, and utilities designed to enhance your BoxLang development experience across different platforms and editors.

## 🎓 Interactive Learning

Start learning BoxLang interactively with BoxLings, a CLI-first training tool with progressive exercises and visible TestBox specs.

{% content-ref url="/pages/6ezKzuW4Qf4WQcWZ9So6" %}
[Interactive Learning with BoxLings](/getting-started/ide-tooling/boxlings)
{% endcontent-ref %}

## 🚀 Official IDE Support

BoxLang provides first-class support for modern development environments for:

* Vistual Studio Code
* OpenVSX Compatible Editors
* IntelliJ
* Vim/Neovim
* Textmate

### Supported Platforms

We provide a collection of extensions and modules to enhance your BoxLang development experience on many different IDE platforms. The official IDE for BoxLang is based on Visual Studio Code technology and can be installed on any platform that supports VS Code Extensions:

* [**Visual Studio Code**](https://code.visualstudio.com/) - The primary development platform
* [**Cursor**](https://cursor.com) - AI-powered code editor with BoxLang support
* [**Windsurf**](https://windsurf.dev/) - Modern development environment
* **Any IDE supporting** [**Open VSX**](https://open-vsx.org/) - Extended compatibility
* \*\*[IntelliJ](https://plugins.jetbrains.com/plugin/30311-boxlang-ide) - IntelliJ Official Plugin
* [**Sublime Text 4**](https://www.sublimetext.com/) - Full-featured BoxLang package with completions, docs, and build tools

### BoxLang IDE Extension

Complete language support with IntelliSense, debugging, and AI-powered development assistance.

{% content-ref url="/pages/D0lWEn7noQxN6bKv6jds" %}
[BoxLang IDE](/getting-started/ide-tooling/boxlang-ide)
{% endcontent-ref %}

### BoxLang Theme Extension

Beautiful dark and light themes specifically crafted for BoxLang syntax highlighting and optimal coding experience.

{% content-ref url="/pages/E8MLoUfmUmUHMELFCyqy" %}
[BoxLang Themes](/getting-started/ide-tooling/boxlang-theme)
{% endcontent-ref %}

### BoxLang Sublime Text Package

Comprehensive BoxLang language support for Sublime Text 4, including syntax highlighting, 825+ BIF completions, inline documentation, code formatting, type inference, and a full build system.

{% content-ref url="/pages/FG6R1eihV1MlmVx7CRBx" %}
[BoxLang Sublime Text](/getting-started/ide-tooling/boxlang-sublime-text)
{% endcontent-ref %}

## 🌐 Web-Based Development

### BoxLang Monaco Editor

Monaco Editor language support for BoxLang - providing syntax highlighting, IntelliSense, and custom themes for web-based BoxLang development and online code editors.

{% content-ref url="/pages/H65YFVKJW0BvFD0IuIUm" %}
[BoxLang Monaco Editor](/getting-started/ide-tooling/boxlang-monaco-editor)
{% endcontent-ref %}

### BoxLang TextMate Bundle

TextMate grammar bundle providing comprehensive syntax highlighting and snippets for BoxLang development across TextMate-compatible editors.

{% content-ref url="/pages/fExGpxd9gl5UY8F1YEsy" %}
[BoxLang TextMate Bundle](/getting-started/ide-tooling/boxlang-textmate-bundle)
{% endcontent-ref %}

## 🛠️ Command Line Tools

Powerful CLI utilities for BoxLang development, compilation, debugging, and migration tasks.

### BoxLang Compiler

Command-line compiler for BoxLang source code with optimization and build management capabilities.

{% content-ref url="/pages/Wn25F2P0Qec0hG0lW4mc" %}
[BoxLang Compiler](/getting-started/ide-tooling/boxlang-compiler)
{% endcontent-ref %}

### BoxLang Syntax Check

Fast, execution-free syntax validation for BoxLang and CFML source files - the BoxLang equivalent of `bash -n` or `node --check`, ideal for git hooks and CI.

{% content-ref url="/pages/5qf9zon2qYwVBEkbcqLg" %}
[BoxLang Syntax Check](/getting-started/ide-tooling/boxlang-syntax-check)
{% endcontent-ref %}

### BoxLang Formatter

Command-line formatter for BoxLang and CFML code with check-mode support for CI lint-style enforcement and cfformat migration utilities.

{% content-ref url="/pages/Xb1taSgm6K5go3nqtDRY" %}
[BoxLang Formatter](/getting-started/ide-tooling/boxlang-formatter)
{% endcontent-ref %}

### BoxLang Debugger

Built-in debugging tools and utilities for troubleshooting BoxLang applications with breakpoint support and variable inspection.

{% content-ref url="/pages/wKeHIvqcYfxCQqnUc9ir" %}
[BoxLang Debugger](/getting-started/ide-tooling/boxlang-debugger)
{% endcontent-ref %}

### CFML Feature Audit

Comprehensive auditing tool to analyze CFML codebases and assess BoxLang compatibility and migration readiness.

{% content-ref url="/pages/fj87euvRWKqheMvjgT32" %}
[CFML Feature Audit](/getting-started/ide-tooling/cfml-feature-audit)
{% endcontent-ref %}

### CFML to BoxLang Transpiler

Automated migration tool for converting CFML code to BoxLang syntax with intelligent transformation and compatibility checks.

{% content-ref url="/pages/flPJkZTqUwvjPfrwgNz5" %}
[CFML Transpiler](/getting-started/ide-tooling/cfml-to-boxlang-transpiler)
{% endcontent-ref %}

## 🎨 Syntax Highlighting

Enhanced syntax highlighting solutions for various platforms and applications.

### Multi-Platform Highlighters

Collection of syntax highlighters for embedding BoxLang code in documentation, websites, and applications across different platforms and libraries.

{% content-ref url="/pages/98KmZVOJtvv5JBym3Ost" %}
[Syntax Highlighters](/getting-started/ide-tooling/syntax-highlighters)
{% endcontent-ref %}


# BoxLang IDE

Official BoxLang IDE extension for VS Code and compatible editors with comprehensive language support, debugging, and development tools

The **BoxLang IDE Extension** is the official first-party development tool for BoxLang, providing comprehensive language support, debugging capabilities, and productivity features for modern BoxLang development.

## 📦 BoxLang Developer Pack

{% hint style="success" %}
**Quick Setup**: Get this theme along with all essential BoxLang development tools in one click with the [**BoxLang Developer Pack**](https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-boxlang-developer-pack)!
{% endhint %}

The **BoxLang Developer Pack** is a curated extension pack that includes everything you need for BoxLang development:

* 🚀 **BoxLang Language Support** - Complete language server with IntelliSense, syntax highlighting, and error detection
* 🎨 **BoxLang Theme** - This theme extension with both Dark (Neon) and Light (Muted) variants
* 🧪 **TestBox Support** - Full TDD/BDD testing framework integration
* 📦 **CommandBox Integration** - Package management and project scaffolding tools

### Install the Complete Pack

Instead of installing extensions individually, get the full BoxLang development environment:

**VS Code Marketplace**: [BoxLang Developer Pack](https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-boxlang-developer-pack)

**OpenVSX Registry**: [BoxLang Developer Pack](https://open-vsx.org/extension/ortus-solutions/vscode-boxlang-developer-pack)

```bash
# Install the complete developer pack
code --install-extension ortus-solutions.vscode-boxlang-developer-pack
```

This automatically installs all BoxLang development tools, including this theme, saving you time and ensuring a complete setup.

## 📦 Individual Installation

### VS Code Marketplace

Install directly from the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-boxlang):

```bash
code --install-extension ortus-solutions.vscode-boxlang
```

### OpenVSX Registry

For VS Code compatible editors like **Cursor**, **Windsurf**, **VSCodium**, and others, install from [OpenVSX Registry](https://open-vsx.org/extension/ortus-solutions/vscode-boxlang):

```bash
# For compatible editors using OpenVSX
cursor --install-extension ortus-solutions.vscode-boxlang
```

### Developer Resources

* **GitHub Repository**: <https://github.com/ortus-boxlang/vscode-boxlang>
* **Documentation**: <https://boxlang-ide.ortusbooks.com/>

{% embed url="<https://boxlang-ide.ortusbooks.com/>" %}

<figure><img src="/files/Q8xBuoW7OJzyVbFrHVqZ" alt="BoxLang IDE Extension in VS Code"><figcaption><p>BoxLang IDE Extension providing syntax highlighting, IntelliSense, and debugging support</p></figcaption></figure>

## ✨ Core Features

### Language Server Integration

* **IntelliSense** - Intelligent code completion with method signatures and documentation
* **Inline Documentation** - Hover information for functions, components, and variables
* **Go to Definition** - Navigate to function and component definitions
* **Find References** - Locate all usages of symbols across your codebase
* **Type Information** - Rich type hints and validation
* **Error Detection** - Real-time syntax and semantic error reporting

### Development Tools

* [**Built-in Debugger**](/getting-started/ide-tooling/boxlang-debugger) - Full debugging support with breakpoints, variable inspection, and call stack navigation
* **Mini BoxLang Web Server** - Quick development server for testing applications locally
* **BoxLang Version Manager** - Switch between different BoxLang runtime versions
* **Task Integration** - Execute BoxLang scripts and applications directly from VS Code

### AI-Powered Development

* **BoxLang Agentic Coding** - Chat with `@boxlang` for intelligent code assistance, explanations, and generation
* **Context-Aware Suggestions** - AI understands your BoxLang codebase for better recommendations

### Multi-Language Support

Enhanced syntax highlighting and code introspection for:

* **BoxLang** - Full language support with semantic highlighting
* **CFML** - Legacy ColdFusion compatibility
* **Java** - Embedded Java code blocks
* **HTML/CSS** - Template and styling support
* **SQL** - Database query highlighting
* **JavaScript** - Client-side scripting

### Productivity Features

* **Code Formatting** - Automatic code formatting and indentation
* **Snippet Library** - Pre-built code templates for common patterns
* **Project Templates** - Quick project scaffolding
* **Symbol Navigation** - Outline view and breadcrumb navigation
* **Workspace Integration** - Multi-root workspace support

## 🎯 Getting Started

1. **Install the extension** from VS Code Marketplace or OpenVSX Registry
2. **Open or create** a BoxLang project (`.bx`, `.bxm`, `.bxs` files)
3. **Configure BoxLang runtime** using the version manager
4. **Start coding** with full IntelliSense and debugging support


# Interactive Learning with BoxLings

Learn BoxLang interactively with the BoxLings CLI learning tool

<figure><img src="/files/VY33Kmpakf8vSijtCL7i" alt=""><figcaption></figcaption></figure>

**BoxLings** is an interactive CLI learning tool for BoxLang, inspired by Rustlings. It teaches the language through progressive exercises where you fix intentional issues and use tests to verify behavior.

{% hint style="info" %}
BoxLings is built in BoxLang and teaches both BoxLang fundamentals and Test-Driven Development (TDD/BDD) workflows.
{% endhint %}

BoxLings is part of the practical BoxLang tooling ecosystem:

* Hands-on learning with immediate feedback
* Test-first learning using TestBox specs
* A real-world CLI workflow for everyday BoxLang usage
* It's also a CLI app built in BoxLang

{% embed url="<https://github.com/ortus-boxlang/boxlings>" %}

## Quick Start

```bash
git clone https://github.com/ortus-boxlang/boxlings.git
cd boxlings
boxlang BoxLings.bx init
boxlang BoxLings.bx
```

<figure><img src="/files/yYX9VeuCKWu5xW1NMC5Z" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/uc5m7bKS0XHs8QjavSSo" alt=""><figcaption></figcaption></figure>

## What You Will Practice

* Core language syntax and program structure
* Variables, functions, arrays, structs, and strings
* Error handling, testing patterns, and async workflows
* Scripts (`.bxs`), classes (`.bx`), and templates (`.bxm`)

## Learn More

* Repository: <https://github.com/ortus-boxlang/boxlings>


# BoxLang IntelliJ

Official BoxLang IDE plugin for IntelliJ and JetBrains IDEs with comprehensive language support, debugging, and TestBox integration

The **BoxLang IDE plugin for IntelliJ** brings modern BoxLang development directly into the JetBrains IDE family. Whether you're building new BoxLang applications or maintaining existing CFML codebases, this plugin provides first-class tooling inside IntelliJ and other JetBrains IDEs.

## 📦 Installation

Installing the plugin is easy from the JetBrains Marketplace.

### From IntelliJ

1. Open **Settings → Plugins**
2. Search for **BoxLang IDE**
3. Click **Install**
4. Restart IntelliJ

### Direct from Marketplace

Install directly from the [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/30311-boxlang-ide)

```bash
# Install from JetBrains Marketplace
https://plugins.jetbrains.com/plugin/30311-boxlang-ide
```

<figure><img src="https://www.ortussolutions.com/__media/contentbox:2026/Blogs/introducing-the-boxlang-ide-plugin-for-intellij/plugin-web-view.png" alt="IntelliJ&#x27;s plugin marketplace showing BoxLang IDE"><figcaption><p>BoxLang IDE plugin on the JetBrains Marketplace</p></figcaption></figure>

## ✨ Key Features

### 🎨 BoxLang Syntax Highlighting

Full syntax highlighting for BoxLang source files makes your code easier to read and maintain.

Features include:

* Tokenized syntax highlighting
* Language-aware formatting
* Support for modern BoxLang syntax

<figure><img src="https://www.ortussolutions.com/__media/contentbox:2026/Blogs/introducing-the-boxlang-ide-plugin-for-intellij/hyper-in-intellij.png" alt="Hyper inside IntelliJ&#x27;s BoxLang IDE"><figcaption><p>BoxLang syntax highlighting in IntelliJ</p></figcaption></figure>

### 🧰 BoxLang Project Creation

Quickly bootstrap a new BoxLang project directly from the IntelliJ project wizard.

This allows you to:

* Create a new BoxLang application structure
* Configure runtimes quickly
* Start coding immediately

<figure><img src="https://www.ortussolutions.com/__media/contentbox:2026/Blogs/introducing-the-boxlang-ide-plugin-for-intellij/boxlang-new-project.png" alt="BoxLang New Project Creation"><figcaption><p>Create new BoxLang projects from IntelliJ</p></figcaption></figure>

### 🧠 Language Server (LSP) Support

The plugin integrates with the **BoxLang Language Server**, enabling advanced development features:

* **IntelliSense** - Intelligent code completion
* **Hover Documentation** - Inline documentation for functions and components
* **Go to Definition** - Navigate to symbol definitions
* **Find References** - Locate all usages across your codebase
* **Inline Diagnostics** - Real-time error detection and reporting

<figure><img src="https://www.ortussolutions.com/__media/contentbox:2026/Blogs/introducing-the-boxlang-ide-plugin-for-intellij/symbol-search.png" alt="BoxLang IDE showing Goto Symbol support"><figcaption><p>Language server integration with symbol search</p></figcaption></figure>

### 🐞 Debugging Support

Debug your BoxLang applications directly inside IntelliJ with full debugging capabilities.

The plugin supports:

* **Breakpoints** - Set breakpoints anywhere in your code
* **Step-through Debugging** - Step over, into, and out of functions
* **Variable Inspection** - Inspect variable values at runtime
* **Call Stack Navigation** - Navigate through the execution stack

<figure><img src="https://www.ortussolutions.com/__media/contentbox:2026/Blogs/introducing-the-boxlang-ide-plugin-for-intellij/debugging.png" alt="BoxLang Debugger in action"><figcaption><p>Full debugging support with breakpoints and variable inspection</p></figcaption></figure>

### 🧪 TestBox Integration

Run and debug **TestBox tests** without leaving your IDE.

Benefits include:

* Running tests directly from IntelliJ
* Viewing test results inline
* Faster test-driven development workflows
* Debug test cases with full debugging support

<figure><img src="https://www.ortussolutions.com/__media/contentbox:2026/Blogs/introducing-the-boxlang-ide-plugin-for-intellij/testbox-integration.png" alt="BoxLang IDE TestBox Integration with IntelliJ"><figcaption><p>TestBox integration for running tests inside IntelliJ</p></figcaption></figure>

### 🔵 CFML Syntax Highlighting

The plugin also includes **syntax highlighting for CFML**, making it easier to work in mixed environments.

This is particularly useful for teams that are:

* Migrating CFML applications to BoxLang
* Maintaining legacy codebases
* Working with hybrid projects

## 🚀 Designed for the JVM Ecosystem

BoxLang is built for the JVM and integrates naturally with Java-based tooling and workflows.

That means IntelliJ users get:

* **Familiar Workflows** - Work with BoxLang using the same patterns as Java development
* **Powerful Navigation** - Leverage IntelliJ's robust code navigation features
* **Rich Plugin Ecosystem** - Benefit from IntelliJ's extensive plugin library
* **Seamless JVM Integration** - BoxLang code works naturally with Java tooling

## 📚 Getting Started

Ready to start developing with BoxLang in IntelliJ?

1. [Install the plugin](https://plugins.jetbrains.com/plugin/30311-boxlang-ide) from the JetBrains Marketplace
2. Create a new BoxLang project using the project wizard
3. Start coding with full language server support
4. Debug and test your applications directly in IntelliJ

Learn more about BoxLang at <https://boxlang.io>

## 💬 Feedback & Contributions

We're actively improving the plugin and welcome your feedback:

* [Open issues](https://ortussolutions.atlassian.net/jira/software/c/projects/BLIDE/boards/132?search_id=c5d57cde-72a5-400c-b8ee-32b5fe3c8a6f)
* Submit feature requests
* Contribute improvements

Let's make **BoxLang development on IntelliJ world-class.**


# BoxLang Compiler

Sourceless deployments for all

BoxLang ships with many CLI tools. The BoxLang Compiler is one of them. This tool allows you to compile a file or a directory of files into Java Bytecode. This will allow you to do sourceless deployments.

{% hint style="warning" %}
The compiler still has some issues we need to iron out, mostly around apps using mappings that provide more than one Class/CFC path to reference a single physical file on the disk.
{% endhint %}

This tool will compile and place (by default) your BoxLang files into Java bytecode so you can do sourceless deployments. When BoxLang goes to compile a file, it will check to see if the file has bytecode in it and proceed with loading the class directly, skipping the parsing and compilation step.

## Usage

Make sure you have installed the OS version of [BoxLang](/getting-started/installation) so you get all the tools installed as well. Please note that the action command funnels through the `boxlang` binary, so you can use all the [CLI arguments](/getting-started/running-boxlang#other-command-line-args-10) for `boxlang` runner.

```bash
// Using the script
boxlang compile
    --source /path/to/webroot/index.cfm
    --target /path/to/compiled-webroot/index.cfm
    --basePath /path/to/webroot

// Using the full path to jar
java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.BXCompiler
--source /path/to/webroot/index.cfm
--target /path/to/compiled-webroot/index.cfm
--basePath /path/to/webroot
```

Note, for the code to run, the compiled file needs to have the exact same path on disk as the original file. That means you’ll either need to copy the pre-compiled files back over to the original location or just point the source and target at the same place. **BE WARNED: this will overwrite the source code! So pay attention.**

### **Directory**

And an entire directory like so:

```bash
// Using the script
boxlang compile
    --source /path/to/webroot/
    --target /path/to/compiled-webroot/
    --basePath /path/to/webroot

// Using the full path to the jar
java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.BXCompiler
--source /path/to/webroot/
--target /path/to/compiled-webroot/
--basePath /path/to/webroot
```

Also note, when pre-compiling an entire directory, the tool doesn’t touch non-code files, so if your target is a separate folder, that new folder won’t contain images, js files, etc. The typical use case for this would be in a CI build or similar, where you would override the code files in place.

### CLI Options

* `--basePath path` The path to use for all base operations that require relative paths.
* `--mapping dot_notation` If there is a mapping name to the source folder, then add it here
* `--source file/directory` A file or directory to compile.
* `--stopOnError` or `--stopOnError boolean` to stop execution if an error occurs. Otherwise, it ignores it, logs it, and continues compiling.
* `--target path` Optional; if not passed, it will be compiled and put in the same location as the source. This is a directory where the compiled files will be placed.


# BoxLang Syntax Check

Validate BoxLang and CFML source files for syntax errors without executing them.

The BoxLang Syntax Check tool (`check`) is a CLI action command that parses one or more source files and reports syntax errors, **without executing the code or compiling it to bytecode**. It's the BoxLang equivalent of `bash -n script.sh` or `node --check file.js` — a fast way to validate that your code is well-formed before you run it, commit it, or ship it.

This makes it a great fit for:

* Pre-commit and git hooks
* CI pipelines, as a fast fail-early step before running the full test suite
* Editor/IDE tooling integrations (via `--format json`)

Like the other BoxLang CLI tools, syntax checking is based on our BL AST (BoxLang Abstract Syntax Tree) and the actual BL ANTLR parsers, so results are accurate for both BoxLang and CFML source.

## Usage

Make sure you have installed the OS version of [BoxLang](/getting-started/installation) so you get all the tools installed as well. Please note that the action command funnels through the `boxlang` binary, so you can use all the [CLI arguments](/getting-started/running-boxlang#other-command-line-args-10) for the `boxlang` runner.

```bash
// Using the script
boxlang check [OPTIONS] [FILE...]

// Using the full path to the jar
java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.SyntaxCheck [OPTIONS] [FILE...]
```

You can pass one or more explicit file paths, a `--source` directory to scan recursively, or both.

### Supported Source Files

`.cfm` `.cfc` `.cfs` `.bx` `.bxs` `.bxm`

### CLI Options

* `-h, --help` - Show the help message and exit.
* `--source <PATH>` - Path to a source directory or file to check. When a directory is given, it is walked recursively and every supported file extension is checked.
* `--format <text|json>` - Output format. Defaults to `text`. Use `json` for machine-readable output suited to editor/CI tooling integration.
* `-q, --quiet` - Suppress the per-file success output and summary line. Failures are always reported, even in quiet mode.

You can also pass one or more file paths directly as positional arguments, instead of (or in addition to) `--source`.

### Exit Codes

* `0` - Every checked file is syntactically valid.
* `1` - One or more files have syntax errors, or a usage error occurred (e.g. a missing `--source` path).

## Examples

Check one or more specific files:

```bash
// Using the script
boxlang check myapp.bx myComponent.cfc

// Using the full path to the jar
java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.SyntaxCheck myapp.bx myComponent.cfc
```

Check an entire directory recursively, e.g. in CI or a git hook:

```bash
// Using the script
boxlang check --source ./src

// Using the full path to the jar
java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.SyntaxCheck --source ./src
```

Get machine-readable output for editor/CI tooling:

```bash
// Using the script
boxlang check --source ./src --format json
```

### Sample Output

A valid file produces minimal output and exits `0`:

```
$ boxlang check good.bxs
✅ good.bxs

───────────────────────────────
✅ 1 valid   ❌ 0 invalid   (1 files checked)
```

An invalid file reports the file, line, column, and message, and exits `1`:

```
$ boxlang check bad.bxs
❌ bad.bxs
   bad.bxs: Line: 1 Col: 3 - Unclosed parenthesis [(] on line 1
if ( true {
   ^

───────────────────────────────
✅ 0 valid   ❌ 1 invalid   (1 files checked)
```

Checking a directory reports every file that was scanned, with a combined summary:

```
$ boxlang check --source ./demo
❌ /path/to/demo/bad.bxs
   /path/to/demo/bad.bxs: Line: 1 Col: 3 - Unclosed parenthesis [(] on line 1
if ( true {
   ^
✅ /path/to/demo/good.bxs

───────────────────────────────
✅ 1 valid   ❌ 1 invalid   (2 files checked)
```

`--format json` returns an array of `{file, valid, issues}` records, one per checked file:

```json
[ {
  "file" : "/path/to/demo/bad.bxs",
  "valid" : false,
  "issues" : [ {
    "message" : "Unclosed parenthesis [(] on line 1\nif ( true {\n   ^",
    "line" : 1,
    "column" : 3
  } ]
}, {
  "file" : "/path/to/demo/good.bxs",
  "valid" : true,
  "issues" : [ ]
} ]
```


# BoxLang Formatter

Format BoxLang and CFML code with deterministic, team-wide style enforcement and CI-ready check mode

The BoxLang Formatter is the canonical tool for enforcing consistent code style across BoxLang and CFML codebases.

Use this page as your one-stop technical reference for:

* local formatting workflows
* lint-like enforcement in CI/CD pipelines
* formatter configuration precedence
* cfformat migration and conversion strategy

## 🚀 Command Overview

The formatter is exposed as a BoxLang action command:

```bash
boxlang format [OPTIONS]
```

This command routes through the BoxLang runtime action pipeline, so it can be used consistently in local development, pre-commit checks, and CI runners.

### Supported File Types

The formatter can process these extensions:

* `.bx`
* `.bxs`
* `.bxm`
* `.cfm`
* `.cfc`
* `.cfs`

## 📋 CLI Options

{% hint style="info" %}
**BoxLang v1.14+** — The `--source` flag now accepts a comma-delimited list of paths, and the new `--excludes` flag lets you skip specific files or directories during formatting.
{% endhint %}

Use `boxlang format --help` to view the complete option set available in your installed version.

| Option                         | Description                                                                                                                 | Typical Usage                                                                         |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `-h`, `--help`                 | Show formatter help and exit                                                                                                | `boxlang format --help`                                                               |
| `--source <PATH[,PATH,...]>`   | Comma-delimited list of files or directories to process (BoxLang v1.14+). Defaults to current directory if omitted          | `boxlang format --source ./src` or `boxlang format --source commands,models,services` |
| `--excludes <PATH[,PATH,...]>` | Comma-delimited list of files or directories to skip (BoxLang v1.14+)                                                       | `boxlang format --source . --excludes generated,vendor`                               |
| `--target <PATH>`              | Output path (optional). If omitted, source files are overwritten. Must be a directory when processing multiple source files | `boxlang format --source ./src --target ./formatted`                                  |
| `--check`                      | Check-only mode; exits non-zero when formatting drift exists                                                                | `boxlang format --check`                                                              |
| `--overwrite <BOOL>`           | When `false`, write formatted output to stdout instead of rewriting files                                                   | `boxlang format --overwrite false --source ./models/User.cfc`                         |
| `-c`, `--config <PATH>`        | Explicit `.bxformat.json` or `.cfformat.json` path                                                                          | `boxlang format --config ./.bxformat.json --source ./`                                |
| `--initConfig`                 | Create starter formatter config in current workspace                                                                        | `boxlang format --initConfig`                                                         |
| `--convertConfig`              | Convert legacy `.cfformat.json` into `.bxformat.json`                                                                       | `boxlang format --convertConfig`                                                      |

### Behavior Notes

* Directory formatting processes supported files **recursively**
* `--source` defaults to the current directory when omitted
* `--target` must be a directory when multiple source files are being processed
* Missing or unset configuration falls back to built-in default formatter settings

## 🧪 Core Workflows

### Format In Place (Default Directory)

```bash
boxlang format
```

This is the simplest invocation — it processes all supported files in the current directory and its subdirectories using the default settings.

### Format In Place (Explicit Path)

```bash
boxlang format --source ./
```

Use this when you want to be explicit about the source path, or when formatting a different directory.

### Format a Single File

```bash
boxlang format --source ./models/User.bx
```

Useful for editor tasks, pre-commit hooks, and targeted refactors.

### Print to Stdout (No File Rewrite)

```bash
boxlang format --overwrite false --source ./handlers/MainHandler.cfc
```

This is useful when integrating with custom tooling that captures formatter output.

### CI Gate / Lint-Style Enforcement

```bash
boxlang format --check --source ./
```

In `--check` mode, the command behaves as a lint-style quality gate:

* exits successfully when all files already match formatter rules
* exits non-zero when any file requires formatting

This allows direct integration with CI jobs that should fail on style drift.

## 🚫 Ignore Comments

{% hint style="info" %}
**BoxLang v1.14+** — Three styles of formatter-ignore comments are supported, matching the most popular conventions from the CFML and wider ecosystems.
{% endhint %}

When the formatter encounters an ignore directive, it emits the enclosed code **exactly as written** — no reformatting, no re-indentation, no quote normalization.

### `@formatter:off` / `@formatter:on`

The universal formatter directive, recognized by many language tooling ecosystems:

```js
// @formatter:off
uglyCode =    {foo:   "bar"}
// @formatter:on
```

### `bxformat-ignore-start` / `bxformat-ignore-end`

BoxLang-native ignore markers:

```js
// bxformat-ignore-start
legacyQuery = "SELECT  * FROM    users"
// bxformat-ignore-end
```

### `cfformat-ignore-start` / `cfformat-ignore-end`

Legacy cfformat compatibility — existing ignore blocks from cfformat projects work out of the box:

```js
// cfformat-ignore-start
{ unformatted:   true }
// cfformat-ignore-end
```

### How Ignore Blocks Work

* The **start** marker must appear as a comment on the line **immediately before** the code to skip
* The **end** marker must appear as a comment on the line **immediately after** the code to skip
* Everything between the markers — including indentation, spacing, and quote style — is preserved verbatim
* Ignore blocks can span multiple statements, not just single lines
* Nested ignore blocks are not supported; the first start marker opens the region and the first end marker closes it

## ⚙️ Configuration Model

The formatter auto-discovers configuration using this precedence order:

1. `.bxformat.json`
2. `.cfformat.json` (converted into formatter config model)
3. built-in defaults

This design gives teams a safe migration path:

* BoxLang-native projects can adopt `.bxformat.json`
* mixed/legacy projects can continue using `.cfformat.json` while migrating incrementally

### Bootstrap New Config

```bash
boxlang format --initConfig
```

Use this to generate a baseline `.bxformat.json` in your workspace.

## 🧾 Full Rules Reference (`.bxformat.json`)

This section lists all currently supported formatter configuration keys and how to configure them.

{% hint style="info" %}
Some keys may not appear in the generated `--initConfig` scaffold but are still supported by the formatter config model.
{% endhint %}

### Root-Level Rules

| Key                           | Type        | Default | Allowed / Notes                                                            |
| ----------------------------- | ----------- | ------- | -------------------------------------------------------------------------- |
| `indentSize`                  | number      | `4`     | Indentation width unit                                                     |
| `tabIndent`                   | boolean     | `true`  | Use tabs instead of spaces                                                 |
| `maxLineLength`               | number      | `115`   | Line length target for wrapping decisions                                  |
| `newLine`                     | string      | `"\n"`  | `"os"`, `"\n"`, `"\r\n"`                                                   |
| `singleQuote`                 | boolean     | `false` | Prefer single quotes for strings/keys                                      |
| `preserveStringQuotes`        | boolean     | `false` | Preserve original quote style in source                                    |
| `alignConsecutiveAssignments` | boolean     | `true`  | Vertical align for consecutive assignment-like separators                  |
| `alignConsecutiveProperties`  | boolean     | `true`  | Vertical align for consecutive `property` declarations                     |
| `bracketPadding`              | boolean     | `true`  | Global default for array bracket padding                                   |
| `parensPadding`               | boolean     | `true`  | Global default for parentheses padding                                     |
| `binaryOperatorsPadding`      | boolean     | `true`  | Spaces around binary operators                                             |
| `semicolons`                  | boolean     | `true`  | Append semicolons where applicable                                         |
| `cfFormatCompatibility`       | boolean     | `false` | Internal compatibility mode (normally set by cfformat conversion path)     |
| `sourceType`                  | string/null | `null`  | `BOXSCRIPT`, `BOXTEMPLATE`, `CFSCRIPT`, `CFTEMPLATE`; `null` = auto-detect |

### `struct` Rules

| Key                                      | Type    | Default | Allowed / Notes                                |
| ---------------------------------------- | ------- | ------- | ---------------------------------------------- |
| `struct.padding`                         | boolean | `true`  | Spaces/newlines inside non-empty struct braces |
| `struct.empty_padding`                   | boolean | `false` | Space in empty structs/ordered markers         |
| `struct.quote_keys`                      | boolean | `false` | Force quoting of struct keys                   |
| `struct.separator`                       | string  | `" : "` | `":"`, `"="`, `": "`, `" : "`, `"= "`, `" = "` |
| `struct.multiline.element_count`         | number  | `2`     | Break threshold by number of entries           |
| `struct.multiline.comma_dangle`          | boolean | `false` | Trailing comma when multiline                  |
| `struct.multiline.leading_comma.enabled` | boolean | `false` | Leading comma style                            |
| `struct.multiline.leading_comma.padding` | boolean | `true`  | Space after leading comma                      |
| `struct.multiline.min_length`            | number  | `60`    | Break threshold by flattened text length       |

### `array` Rules

| Key                                     | Type    | Default | Allowed / Notes                                 |
| --------------------------------------- | ------- | ------- | ----------------------------------------------- |
| `array.padding`                         | boolean | `true`  | Spaces/newlines inside non-empty array brackets |
| `array.empty_padding`                   | boolean | `false` | Space in empty arrays                           |
| `array.multiline.element_count`         | number  | `2`     | Break threshold by number of elements           |
| `array.multiline.comma_dangle`          | boolean | `false` | Trailing comma when multiline                   |
| `array.multiline.leading_comma.enabled` | boolean | `false` | Leading comma style                             |
| `array.multiline.leading_comma.padding` | boolean | `true`  | Space after leading comma                       |
| `array.multiline.min_length`            | number  | `50`    | Break threshold by flattened text length        |

### `property` Rules

| Key                                        | Type    | Default | Allowed / Notes                             |
| ------------------------------------------ | ------- | ------- | ------------------------------------------- |
| `property.multiline.element_count`         | number  | `3`     | Break threshold by number of attributes     |
| `property.multiline.comma_dangle`          | boolean | `false` | Trailing comma in multiline attribute lists |
| `property.multiline.leading_comma.enabled` | boolean | `false` | Leading comma style                         |
| `property.multiline.leading_comma.padding` | boolean | `true`  | Space after leading comma                   |
| `property.multiline.min_length`            | number  | `30`    | Break threshold by flattened text length    |
| `property.key_value.padding`               | boolean | `false` | Spaces around `=` in property attributes    |

### `for_loop_semicolons` Rules

| Key                           | Type    | Default | Allowed / Notes                        |
| ----------------------------- | ------- | ------- | -------------------------------------- |
| `for_loop_semicolons.padding` | boolean | `true`  | Space after `;` in `for ( ;; )` header |

### `function` Rules

| Key                                    | Type    | Default      | Allowed / Notes                        |
| -------------------------------------- | ------- | ------------ | -------------------------------------- |
| `function.style`                       | string  | `"preserve"` | Currently preserve-first style control |
| `function.parameters.padding`          | boolean | `true`       | Spaces in non-empty parameter list     |
| `function.parameters.empty_padding`    | boolean | `false`      | Space in empty parameter list          |
| `function.parameters.comma_dangle`     | boolean | `false`      | Trailing comma in multiline parameters |
| `function.parameters.multiline_count`  | number  | `3`          | Break threshold by parameter count     |
| `function.parameters.multiline_length` | number  | `50`         | Break threshold by flattened length    |
| `function.arrow.parens`                | string  | `"always"`   | `"always"` or `"avoid"`                |

### `arguments` Rules

| Key                          | Type    | Default | Allowed / Notes                         |
| ---------------------------- | ------- | ------- | --------------------------------------- |
| `arguments.padding`          | boolean | `true`  | Spaces in non-empty call argument lists |
| `arguments.empty_padding`    | boolean | `false` | Space in empty argument lists           |
| `arguments.comma_dangle`     | boolean | `false` | Trailing comma in multiline arguments   |
| `arguments.multiline_count`  | number  | `3`     | Break threshold by argument count       |
| `arguments.multiline_length` | number  | `50`    | Break threshold by flattened length     |
| `arguments.separator`        | string  | `" = "` | `"="` or `":"`                          |

### `braces` Rules

| Key                                   | Type    | Default       | Allowed / Notes                                    |
| ------------------------------------- | ------- | ------------- | -------------------------------------------------- |
| `braces.style`                        | string  | `"same-line"` | `"same-line"`, `"new-line"`, `"preserve"`          |
| `braces.require_for_single_statement` | boolean | `true`        | Require braces for single statement control blocks |
| `braces.else.style`                   | string  | `"same-line"` | `"same-line"` or `"new-line"`                      |

### `operators` Rules

| Key                                   | Type   | Default     | Allowed / Notes                                                       |
| ------------------------------------- | ------ | ----------- | --------------------------------------------------------------------- |
| `operators.position`                  | string | `"end"`     | Binary operator position on wrapped expressions: `"end"` or `"start"` |
| `operators.comparison_style`          | string | `"symbols"` | `"symbols"`, `"keywords"`, or `"preserve"`                            |
| `operators.ternary.style`             | string | `"flat"`    | `"flat"`, `"always-multiline"`, or `"preserve"`                       |
| `operators.ternary.question_position` | string | `"start"`   | `"start"` or `"end"`                                                  |

### `chain` Rules

| Key                  | Type   | Default | Allowed / Notes                                     |
| -------------------- | ------ | ------- | --------------------------------------------------- |
| `chain.break_count`  | number | `3`     | Break chain when call count reaches threshold       |
| `chain.break_length` | number | `60`    | Break chain when flattened length reaches threshold |

### `template` Rules

{% hint style="info" %}
**BoxLang v1.14+** — The `template.enabled` flag gates template (`.bxm` / `.cfm`) formatting. It defaults to `false` until template formatting exits experimental mode. Set it to `true` to enable.
{% endhint %}

| Key                                  | Type    | Default | Allowed / Notes                                                       |
| ------------------------------------ | ------- | ------- | --------------------------------------------------------------------- |
| `template.enabled`                   | boolean | `false` | Enable/disable template (`.bxm` / `.cfm`) formatting (BoxLang v1.14+) |
| `template.component_prefix`          | string  | `"bx"`  | Commonly `"bx"` or `"cf"`                                             |
| `template.indent_content`            | boolean | `true`  | Indent tag body content                                               |
| `template.single_attribute_per_line` | boolean | `false` | One attribute per line in tags                                        |
| `template.self_closing`              | boolean | `true`  | Use `/>` for self-closing tags                                        |

### `import` Rules

| Key            | Type    | Default | Allowed / Notes                           |
| -------------- | ------- | ------- | ----------------------------------------- |
| `import.sort`  | boolean | `false` | Sort imports alphabetically               |
| `import.group` | boolean | `false` | Group imports by package with blank lines |

### `comments` Rules

| Key                             | Type    | Default | Allowed / Notes                             |
| ------------------------------- | ------- | ------- | ------------------------------------------- |
| `comments.preserve_blank_lines` | boolean | `true`  | Keep blank lines around comments            |
| `comments.wrap`                 | boolean | `false` | Wrap long comments based on `maxLineLength` |

### `class` Rules

{% hint style="info" %}
**BoxLang v1.14+** — The `class.property_spacing` rule controls blank lines between property declarations in class bodies. Default is `1` (single blank line), matching Ortus coding standards.
{% endhint %}

| Key                      | Type    | Default      | Allowed / Notes                                            |
| ------------------------ | ------- | ------------ | ---------------------------------------------------------- |
| `class.member_order`     | string  | `"preserve"` | Member ordering strategy                                   |
| `class.member_spacing`   | number  | `1`          | Blank lines between members                                |
| `class.property_order`   | string  | `"preserve"` | `"preserve"`, `"alphabetical"`, `"length"`, `"type"`       |
| `class.property_spacing` | number  | `1`          | Blank lines between property declarations (BoxLang v1.14+) |
| `class.method_order`     | string  | `"preserve"` | `"preserve"` or `"alphabetical"`                           |
| `class.method_grouping`  | boolean | `false`      | Group methods by modifier/type before ordering             |

### `sql` Rules

| Key                      | Type    | Default | Allowed / Notes                    |
| ------------------------ | ------- | ------- | ---------------------------------- |
| `sql.uppercase_keywords` | boolean | `true`  | Uppercase SQL keywords             |
| `sql.indent_clauses`     | boolean | `true`  | Indent SQL clauses in query blocks |

## 🛠️ Configuration Examples

### Minimal Starter

```json
{
	"maxLineLength": 120,
	"tabIndent": true,
	"parensPadding": true,
	"arguments": {
		"multiline_count": 3,
		"multiline_length": 40
	}
}
```

### Strict CI-Friendly Layout

```json
{
	"maxLineLength": 100,
	"semicolons": true,
	"braces": {
		"style": "same-line",
		"require_for_single_statement": true,
		"else": {
			"style": "same-line"
		}
	},
	"operators": {
		"position": "end",
		"comparison_style": "symbols",
		"ternary": {
			"style": "always-multiline",
			"question_position": "start"
		}
	},
	"comments": {
		"preserve_blank_lines": true,
		"wrap": true
	}
}
```

## 🔄 Migration from cfformat

If your team currently relies on cfformat conventions, migrate with a controlled two-phase approach.

### Phase 1: Convert Existing Config

```bash
boxlang format --convertConfig --source ./
```

This creates a BoxLang formatter config from legacy cfformat configuration so existing style intent is preserved as much as possible.

### Phase 2: Validate with Check Mode

```bash
boxlang format --check --source ./
```

Run this in CI to detect any unexpected drift while your team validates behavior.

### Recommended Migration Strategy

1. Convert config using `--convertConfig`.
2. Run formatter once in a dedicated normalization commit.
3. Enable `--check` in CI to prevent future drift.
4. Refine `.bxformat.json` as project standards evolve.

{% hint style="info" %}
Compatibility mode for `.cfformat.json` is designed for migration safety. For long-term BoxLang-first teams, prefer `.bxformat.json` as the canonical source of formatting policy.
{% endhint %}

## 🧷 CI/CD Integration Patterns

### Minimal CI Step

```bash
boxlang format --check --source ./
```

### Recommended Team Policy

1. Developers run `boxlang format --source ./` before pushing changes.
2. CI enforces `boxlang format --check --source ./`.
3. Pull requests that fail check mode must be reformatted before merge.

This gives deterministic formatting without requiring a separate linter for stylistic concerns.

## 🧠 IDE Auto-Formatting (VS Code / BoxLang IDE)

For editor-on-save workflows and IDE formatter setup, the BoxLang LSP supports experimental formatting. Because this feature is still in beta, you need to explicitly enable it with a few steps.

### Enabling Experimental Formatting in VS Code

{% stepper %}
{% step %}

### Enable formatting in `.bxlint.json`

Add the following to your project's `.bxlint.json`:

```json
{
    "formatting": {
        "experimental": {
            "enabled": true
        }
    }
}
```

{% endstep %}

{% step %}

### Enable format-on-save in VS Code

Add this override to your VS Code `settings.json` (Workspace or User):

```json
{
    "[boxlang]": {
        "editor.formatOnSave": true
    },
    "[boxlang-template]": {
        "editor.formatOnSave": true
    }
}
```

{% endstep %}

{% step %}

### Update BoxLang & LSP versions

Open the Command Palette (`Cmd+Shift+P` / `Ctrl+Shift+P`) and run:

* `BoxLang: Select BoxLang Version` — choose the latest available version
* `BoxLang: Select LSP Version` — choose the latest available version
* `Developer: Reload Window` — to pick up the changes
  {% endstep %}
  {% endstepper %}

Once these steps are completed, the formatter will run automatically when you save `.bx`, `.bxs`, `.bxm`, `.cfc`, `.cfm`, or `.cfs` files.

### Recommended Split of Responsibilities

* IDE format-on-save for fast local feedback
* CLI `--check` mode for authoritative CI enforcement

## 🧩 Complete `.bxformat.json` Schema Template

Copy this file to your project root as `.bxformat.json` and remove or adjust only the keys you want to override. All values shown are the Ortus gold-standard defaults.

{% hint style="info" %}
Run `boxlang format --initConfig` to generate this file automatically in your current directory instead of copy-pasting.
{% endhint %}

```json
{
  "indentSize": 4,
  "tabIndent": true,
  "maxLineLength": 120,
  "newLine": "os",
  "singleQuote": false,
  "preserveStringQuotes": false,
  "alignConsecutiveAssignments": true,
  "alignConsecutiveProperties": true,
  "bracketPadding": true,
  "parensPadding": true,
  "binaryOperatorsPadding": true,
  "semicolons": true,
  "cfFormatCompatibility": false,
  "sourceType": null,

  "struct": {
    "padding": true,
    "empty_padding": false,
    "quote_keys": false,
    "separator": ": ",
    "multiline": {
      "element_count": 2,
      "comma_dangle": false,
      "leading_comma": { "enabled": false, "padding": true },
      "min_length": 40
    }
  },

  "array": {
    "padding": true,
    "empty_padding": false,
    "multiline": {
      "element_count": 2,
      "comma_dangle": false,
      "leading_comma": { "enabled": false, "padding": true },
      "min_length": 40
    }
  },

  "property": {
    "multiline": {
      "element_count": 4,
      "comma_dangle": false,
      "leading_comma": { "enabled": false, "padding": true },
      "min_length": 40
    },
    "key_value": { "padding": false }
  },

  "for_loop_semicolons": { "padding": true },

  "function": {
    "style": "preserve",
    "parameters": {
      "padding": true,
      "empty_padding": false,
      "comma_dangle": false,
      "multiline_count": 3,
      "multiline_length": 40
    },
    "arrow": { "parens": "always" }
  },

  "arguments": {
    "padding": true,
    "empty_padding": false,
    "comma_dangle": false,
    "multiline_count": 3,
    "multiline_length": 40,
    "separator": " = "
  },

  "braces": {
    "style": "same-line",
    "require_for_single_statement": true,
    "else": { "style": "same-line" }
  },

  "operators": {
    "position": "end",
    "comparison_style": "symbols",
    "ternary": {
      "style": "flat",
      "question_position": "start"
    }
  },

  "chain": {
    "break_count": 3,
    "break_length": 60
  },

  "template": {
    "enabled": false,
    "component_prefix": "bx",
    "indent_content": true,
    "single_attribute_per_line": false,
    "self_closing": true
  },

  "import": {
    "sort": false,
    "group": false
  },

  "comments": {
    "preserve_blank_lines": true,
    "wrap": false
  },

  "class": {
    "member_order": "preserve",
    "member_spacing": 1,
    "property_order": "preserve",
    "property_spacing": 1,
    "method_order": "preserve",
    "method_grouping": false
  },

  "sql": {
    "uppercase_keywords": true,
    "indent_clauses": true
  }
}
```

## 📚 Related Tooling

* [BoxLang Compiler](/getting-started/ide-tooling/boxlang-compiler)
* [BoxLang AST](/getting-started/ide-tooling/boxlang-ast)
* [CFML Transpiler](/getting-started/ide-tooling/cfml-to-boxlang-transpiler)
* [CLI Scripting](/getting-started/running-boxlang/cli-scripting)


# BoxLang AST

Access BoxLang's Abstract Syntax Tree (AST) for building code analysis tools, linters, formatters, and migration utilities

**New in BoxLang 1.7.0** - The `BoxAST()` BIF provides programmatic access to BoxLang's Abstract Syntax Tree (AST), enabling developers to build sophisticated code analysis tools, formatters, linters, and migration utilities. The AST represents the parsed structure of BoxLang code in a format that's easy to analyze and manipulate programmatically.

## 🌳 What is an AST?

An Abstract Syntax Tree (AST) is a tree representation of the syntactic structure of source code. Each node in the tree represents a construct occurring in the source code. The AST abstracts away concrete syntax details (like parentheses, semicolons, and whitespace) while preserving the semantic structure of the code.

For example, the code `x = 1 + 2;` would be represented as an AST with:

* An assignment node with target `x`
* A binary operation node for addition
* Literal nodes for values `1` and `2`

## 📋 Table of Contents

* [What is an AST?](#what-is-an-ast)
* [BoxAST() BIF](#boxast-bif)
* [Output Formats](#output-formats)
* [Node Types](#node-types)
* [Common Use Cases](#common-use-cases)
* [AST Analysis Examples](#ast-analysis-examples)
* [Best Practices](#best-practices)

## 📋 BoxAST() BIF

The `BoxAST()` function parses BoxLang or CFML source code and returns its AST representation.

### Syntax

```js
BoxAST(
    source: string,
    returnType: string = "struct",
    sourceType: string = "script"
)

BoxAST(
    filepath: string,
    returnType: string = "struct",
    sourceType: string = "script"
)
```

### Parameters

| Parameter    | Type   | Required | Default    | Description                                                            |
| ------------ | ------ | -------- | ---------- | ---------------------------------------------------------------------- |
| `source`     | string | Yes\*    | -          | BoxLang/CFML source code to parse                                      |
| `filepath`   | string | Yes\*    | -          | Path to file to parse (alternative to `source`)                        |
| `returnType` | string | No       | `"struct"` | Output format: `"struct"`, `"json"`, or `"text"`                       |
| `sourceType` | string | No       | `"script"` | Syntax type: `"script"`, `"template"`, `"cfscript"`, or `"cftemplate"` |

\* Either `source` or `filepath` must be provided, but not both.

### Return Types

#### struct (default)

Returns the AST as a BoxLang struct with full node hierarchy and properties. This is the most useful format for programmatic analysis.

```js
ast = BoxAST( source: "x = 1 + 2;" );
// Returns: struct with nodes, positions, types, etc.
```

#### json

Returns the AST as a JSON string, perfect for passing to external tools or storing for later analysis.

```js
astJson = BoxAST(
    source: "function hello() { return 'world'; }",
    returnType: "json"
);
// Returns: JSON string representation of the AST
```

#### text

Returns a human-readable text representation of the AST structure, useful for debugging and visualization.

```js
astText = BoxAST(
    source: "x = 1 + 2;",
    returnType: "text"
);
// Returns: Pretty-printed text tree structure
```

### Source Types

#### script (default)

Parse BoxLang script syntax (`.bx`, `.bxs` files).

```js
ast = BoxAST(
    source: "function hello() { return 'world'; }",
    sourceType: "script"
);
```

#### template

Parse BoxLang template syntax (`.bxm` files with `<bx:>` tags).

```js
ast = BoxAST(
    source: "<bx:output>#now()#</bx:output>",
    sourceType: "template"
);
```

#### cfscript

Parse CFML/ColdFusion script syntax for migration and compatibility tools.

```js
ast = BoxAST(
    source: "cfset x = 1; cfloop from='1' to='10' index='i' { writeOutput(i); }",
    sourceType: "cfscript"
);
```

#### cftemplate

Parse CFML/ColdFusion template syntax (`.cfm` files with `<cf>` tags) for migration tools.

```js
ast = BoxAST(
    source: "<cfset x = 1><cfoutput>#x#</cfoutput>",
    sourceType: "cftemplate"
);
```

## 💡 Usage Examples

### Basic AST Generation

```js
// Parse simple BoxLang code
code = "x = 1 + 2; y = x * 3;";
ast = BoxAST( source: code );

// Inspect the AST structure
println( ast.toString() );
```

### Using String Member Method

BoxLang strings have a convenient `toAST()` member method:

```js
// Parse using member method
code = "function hello() { return 'world'; }";
ast = code.toAST();

// With parameters
astJson = "x = 1 + 2;".toAST( returnType: "json" );

// Parse template syntax
templateCode = "<bx:output>#now()#</bx:output>";
ast = templateCode.toAST( sourceType: "template" );
```

### Parsing Files

```js
// Parse a BoxLang script file
ast = BoxAST( filepath: "/path/to/myScript.bx" );

// Parse a template file
ast = BoxAST(
    filepath: "/path/to/myTemplate.bxm",
    sourceType: "template"
);

// Parse a CFML file for migration
ast = BoxAST(
    filepath: "/legacy/code/myComponent.cfc",
    sourceType: "cfscript"
);
```

### JSON Export for External Tools

```js
// Generate AST as JSON for external processing
astJson = BoxAST(
    filepath: "myComponent.bx",
    returnType: "json"
);

// Send to external analysis tool
httpPost(
    url: "https://analysis-service.com/analyze",
    body: astJson,
    contentType: "application/json"
);

// Or save to file
fileWrite( "ast-output.json", astJson );
```

### Text Visualization

```js
// Get human-readable AST representation
astText = BoxAST(
    source: "function calculate( a, b ) { return a + b; }",
    returnType: "text"
);

println( astText );
// Outputs formatted tree structure showing nodes and relationships
```

## 🎯 Use Cases

### Code Analysis Tools

Build custom linters and static analysis tools to enforce coding standards:

```js
// Analyze code for patterns
code = fileRead( "myFile.bx" );
ast = code.toAST();

// Walk the AST to find specific patterns
// Example: Find all function declarations
functions = findFunctionNodes( ast );
```

### Code Formatters

Create custom code formatting utilities:

```js
// Parse unformatted code
uglyCode = "function test(){x=1;y=2;return x+y;}";
ast = uglyCode.toAST();

// Traverse AST and reformat based on rules
formattedCode = astToFormattedCode( ast );
```

### Documentation Generators

Extract function signatures, parameters, and documentation comments:

```js
// Parse component file
componentCode = fileRead( "MyComponent.bx" );
ast = componentCode.toAST();

// Extract all functions with their metadata
docs = extractFunctionDocumentation( ast );

// Generate API documentation
generateMarkdownDocs( docs );
```

### Migration Tools

Parse and analyze CFML code for BoxLang migration:

```js
// Parse legacy CFML file
cfmlCode = fileRead( "legacy.cfm" );
ast = BoxAST(
    source: cfmlCode,
    sourceType: "cftemplate"
);

// Analyze CFML features used
features = analyzeCFMLFeatures( ast );

// Generate migration report
generateMigrationReport( features );
```

### Refactoring Tools

Analyze and transform code structures:

```js
// Parse code to refactor
code = fileRead( "needsRefactoring.bx" );
ast = code.toAST();

// Find and replace deprecated patterns
transformedAst = replaceDeprecatedPatterns( ast );

// Generate updated code
newCode = astToCode( transformedAst );
fileWrite( "refactored.bx", newCode );
```

### IDE Tooling

Power syntax highlighting, code intelligence, and autocomplete features:

```js
// Parse current file for IDE features
currentCode = editor.getCurrentCode();
ast = currentCode.toAST();

// Provide intelligent autocomplete based on AST analysis
suggestions = getAutocompleteSuggestions( ast, cursorPosition );
```

## 🔍 AST Structure

The AST returned by `BoxAST()` contains detailed information about the code structure:

### Node Properties

Each AST node includes detailed metadata about the code structure:

* **ASTType** - The kind of node (e.g., "BoxScript", "BoxAssignment", "BoxBinaryOperation", "BoxIntegerLiteral")
* **ASTPackage** - The Java package containing the node class
* **sourceText** - Original source code for this node
* **position** - Source location with start/end line and column numbers
* **comments** - Associated comments
* **Additional Properties** - Node-specific data (name, value, operator, statements, etc.)

### Example AST Structure

For code: `x = 1 + 2`

```js
{
    "ASTType": "BoxScript",
    "ASTPackage": "ortus.boxlang.compiler.ast",
    "sourceText": "x = 1 + 2",
    "position": {
        "start": { "line": 1, "column": 0 },
        "end": { "line": 1, "column": 9 }
    },
    "comments": [],
    "statements": [
        {
            "ASTType": "BoxExpressionStatement",
            "ASTPackage": "ortus.boxlang.compiler.ast.statement",
            "sourceText": "x = 1 + 2",
            "position": {
                "start": { "line": 1, "column": 0 },
                "end": { "line": 1, "column": 9 }
            },
            "comments": [],
            "expression": {
                "ASTType": "BoxAssignment",
                "ASTPackage": "ortus.boxlang.compiler.ast.expression",
                "sourceText": "x = 1 + 2",
                "position": {
                    "start": { "line": 1, "column": 0 },
                    "end": { "line": 1, "column": 9 }
                },
                "comments": [],
                "modifiers": [],
                "left": {
                    "ASTType": "BoxIdentifier",
                    "ASTPackage": "ortus.boxlang.compiler.ast.expression",
                    "sourceText": "x",
                    "position": {
                        "start": { "line": 1, "column": 0 },
                        "end": { "line": 1, "column": 1 }
                    },
                    "comments": [],
                    "name": "x"
                },
                "op": {
                    "ASTType": "BoxAssignment",
                    "ASTPackage": "ortus.boxlang.compiler.ast.expression",
                    "sourceText": "Equal"
                },
                "right": {
                    "ASTType": "BoxBinaryOperation",
                    "ASTPackage": "ortus.boxlang.compiler.ast.expression",
                    "sourceText": "1 + 2",
                    "position": {
                        "start": { "line": 1, "column": 4 },
                        "end": { "line": 1, "column": 9 }
                    },
                    "comments": [],
                    "left": {
                        "ASTType": "BoxIntegerLiteral",
                        "ASTPackage": "ortus.boxlang.compiler.ast.expression",
                        "sourceText": "1",
                        "position": {
                            "start": { "line": 1, "column": 4 },
                            "end": { "line": 1, "column": 5 }
                        },
                        "comments": [],
                        "value": 1
                    },
                    "operator": {
                        "ASTType": "BoxBinaryOperation",
                        "ASTPackage": "ortus.boxlang.compiler.ast.expression",
                        "sourceText": "Plus"
                    },
                    "right": {
                        "ASTType": "BoxIntegerLiteral",
                        "ASTPackage": "ortus.boxlang.compiler.ast.expression",
                        "sourceText": "2",
                        "position": {
                            "start": { "line": 1, "column": 8 },
                            "end": { "line": 1, "column": 9 }
                        },
                        "comments": [],
                        "value": 2
                    }
                }
            }
        }
    ]
}
```

## 📊 Best Practices

{% hint style="success" %}
**When to Use BoxAST():**

* Building code analysis and quality tools
* Creating custom formatters and linters
* Developing migration utilities from CFML to BoxLang
* Generating documentation from source code
* Implementing refactoring tools
* Powering IDE features and code intelligence
  {% endhint %}

{% hint style="info" %}
**Performance Tips:**

* Use `filepath` parameter for large files instead of reading into memory first
* Cache AST results for files that don't change frequently
* Use `returnType: "json"` when passing to external tools
* Consider using `returnType: "text"` only for debugging and development
* Parse incrementally for large codebases rather than all at once
  {% endhint %}

{% hint style="warning" %}
**Important Considerations:**

* **Parsing Errors**: Invalid syntax will throw an exception - wrap in try/catch
* **Large Files**: Parsing very large files can consume significant memory
* **Source Type**: Ensure you specify the correct `sourceType` for CFML vs BoxLang
* **AST Changes**: AST structure may evolve between BoxLang versions
* **Read-Only**: The returned AST is for analysis - use code generation to create new code
  {% endhint %}

## 🔗 Related Resources

* [BoxLang Compiler](/getting-started/ide-tooling/boxlang-compiler)
* [CFML Transpiler](/getting-started/ide-tooling/cfml-to-boxlang-transpiler)
* [BoxLang IDE](/getting-started/ide-tooling/boxlang-ide)
* [Release Notes 1.7.0](/readme/release-history/1.7.0)
* [BoxLang Language Reference](https://github.com/ortus-boxlang/boxlang-docs/tree/v1.x/boxlang-language/README.md)

## 🛠️ Building Tools with BoxAST()

The `BoxAST()` BIF opens up powerful possibilities for the BoxLang ecosystem:

### Example: Simple Linter

```js
function lintCode( code ) {
    ast = code.toAST();
    issues = [];

    // Check for var declarations (prefer local scope)
    if ( findVarDeclarations( ast ).len() > 0 ) {
        issues.append( "Use 'local' scope instead of 'var'" );
    }

    // Check for missing return statements
    functions = findFunctionNodes( ast );
    functions.each( ( func ) => {
        if ( !hasReturnStatement( func ) ) {
            issues.append( "Function '#func.name#' missing return statement" );
        }
    } );

    return issues;
}
```

### Example: Function Extractor

```js
function extractFunctions( filepath ) {
    ast = BoxAST( filepath: filepath );
    functions = [];

    walkAST( ast, ( node ) => {
        if ( node.type == "FunctionDeclaration" ) {
            functions.append( {
                "name": node.name,
                "parameters": node.parameters,
                "returnType": node.returnType ?: "any",
                "line": node.position.line
            } );
        }
    } );

    return functions;
}
```

The possibilities are endless - from simple code metrics to sophisticated refactoring tools, `BoxAST()` provides the foundation for building powerful development tools in the BoxLang ecosystem.


# BoxLang Debugger

Learn how to debug with BoxLang and the BoxLang IDE

<figure><img src="/files/fCuhjAiikq4kanfwjUTQ" alt=""><figcaption></figcaption></figure>

## What is a Debugger?

Have you used a debugger before? Have you used one regularly? If you have great! Hopefully, BoxLang’s debugger will make you feel at home. Let me introduce the concept if you are unfamiliar with using a debugger as part of your development process.

<figure><img src="/files/ThqsglrnuH1RSc2XcmjW" alt="The BoxLang Debugger"><figcaption><p>The BoxLang Debugger</p></figcaption></figure>

Debuggers are a program that runs and controls the execution of the software you are developing. As the debugger is in control of the execution of every instruction, it can freeze the program and provide the developer a chance to inspect the state of their software as if they could freeze time. Often, debuggers will give the developer the power to inspect and change variables within their program and move execution back and forth.

As developers familiar with CFML or Java, we are all familiar with the `writeDump()` or `System.out.println()` style of development. While outputting your application state to the browser or to a file has its place, a debugger offers several benefits over a logging-based debugging approach. Here are just a few of them:

* Add/remove breakpoints as your programming executes instead of having to re-run the request
* Inspect variables at each iteration of a loop
* Create watchers for specific variables and values
* Modify the value of a variable and continue execution
* Step through each method of a call stack to see the different levels of an application
* So much more

Getting started can be daunting if you have never used a debugger before. We have put much effort into making the BoxLang debugger as easy to start as possible. Let’s take a look at how to use it.

## Debugging BoxLang Classes & Scripts

Let's say you have a `.bxs` file. This is BoxLang’s CLI script extension. With a `.bxs` you can execute your file on the command line just like any other scripting language. Our VS Code extension makes it even easier. We provide a right-click option to run BoxLang files or via the command pallete as well.

{% code title="task.bxs" %}

```java
task = new Task();
invoke( task, "setFoo", { foo : "bar" } );
result = invoke( task, "getFoo" );

println( result );
```

{% endcode %}

<figure><img src="/files/vv4aEREXTDWOns49dOv1" alt=""><figcaption></figcaption></figure>

You can also run `bx` files which are BoxLang classes, as long as they have a `main()` method on them, in the same manner as above:

{% code title="Hello.bx" %}

```java
class inject hello="word"{

	property foo;
	property firstName;
	property lastName;
	property numeric age default=1;

	function main( args = {} ){
		test = new Person();
		println( test.toJson() )

		println( this.$bx.getMeta().keyArray() )
		println( this.$bx.getMeta().annotations )
	}

	function onMissingMethod( missingMethodName, missingMethodArgs ){
		println( "Missing method: " & missingMethodName );
		println( "missingMethodArgs: " & missingMethodArgs.toString() );
	}

}

```

{% endcode %}

<figure><img src="/files/AF9t7YfXdT8AFim80hq6" alt=""><figcaption><p>Command Pallete</p></figcaption></figure>

Once you click the `BoxLang: Run Script` option. Your program will execute. The debug console will auto-focus and you will see the console output of your program. “Great!” You might say, “But what about debugging! Fair enough! Let’s look at that next.

If you want to debug a script you will need to set a breakpoint. To set a breakpoint simply hover your cursor over the gutter to the left of the file’s line numbers. When you see a red dot appear, “click” and you will set a breakpoint at that line. Now that you have a breakpoint go and ahead and use our right-click `BoxLang: Run Script` option to kick off a debug session. This time your script will pause at your breakpoint.

### Debug Controls

Now that we are debugging, what special actions can we take? We’ll briefly look at 3 features of our debugger: variables, the call stack, and debugger controls.

#### Variables

The Variables Panel gives you information about the state of your program. You can view and even edit variables by looking at the data presented by this panel. This is where much of the value of the debugger comes from. At every breakpoint you hit you will see an up-to-date snapshot of your application state.

<figure><img src="/files/A3QfZmtTIvP5br1z9O1s" alt=""><figcaption><p>Variables</p></figcaption></figure>

#### Call Stack

The Call Stack Panel lets you see the entire call stack of your current location in the code. This feature is a little more advanced than the variables panel but can provide vital information that helps you understand the flow of code in your app.

<figure><img src="/files/T8M65fxDu399uNV2LV50" alt="" width="375"><figcaption><p>Call Stack</p></figcaption></figure>

#### Controls

Finally, we get to the debugger controls. These controls are the unsung hero of every debug session, you’ll use them often as you incorporate the debugger into your workflow.

<figure><img src="/files/zXlLgMToiEwm35e4Cajq" alt="" width="375"><figcaption><p>Controls</p></figcaption></figure>

* `Play/Pause` - Resume execution if paused/pause execution of a running program.
* `Step Over` - Move to the next pausable location without moving down the call stack
* `Step In` - Move into a deeper stackframe if able or Step Over
* `Step Out` - Move to the parent stack frame
* `Stop` - Stop debugging

The controls mostly speak for themselves. The best way to get familiar with them is to jump in and play around. After just a few minutes of playing around with them, using them as part of your debug process will become second nature.

## Further Debugging

You can also debug your web applications easily by running the BoxLang debugger on either the MiniServer or CommandBox Runtimes:

[MiniServer Debugging](/getting-started/ide-tooling/boxlang-debugger/miniserver-debugging)

[CommandBox Debugging](/getting-started/ide-tooling/boxlang-debugger/commandbox-debugging)

## Conclusion

I hope you will agree that the BoxLang Debugger is a powerful addition to the set of tools we at Ortus have built to help you develop BoxLang applications. Now code some Box!




---

[Next Page](/llms-full.txt/1)

