Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 1271 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

BoxLang v1.x

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Getting Started

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

RC Stage

This is the collection of Release Candidates we released since our first version.

Migrating From Lucee CFML

Introduction

Welcome to BoxLang: A Modern Dynamic JVM Language

BoxLang is a modern dynamic JVM language that can be deployed on multiple runtimes: operating system (Windows/Mac/*nix/Embedded), web server, lambda, 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.

BoxLang Multi-Runtime

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, Azure Functions, etc)

    3. Servlet Containers - CommandBox/Tomcat/Jetty/JBoss/Undertow

  8. Compile down to Java ByteCode

  9. Framework Capabilities (Scheduling, applications, events, async computing, tasks, queues, modules)

  10. Drop-in Replacement for Adobe ColdFusion and Lucee CFML

BoxLang can also be used as a drop-in replacement for Adobe ColdFusion or Lucee CFML Engines by leveraging our bx-compat-cfmlmodule. NO CODE CHANGES, FASTER, MODERN AND SAVE MONEY.

Launch Video

License

BoxLang is open source and licensed under the License. Copyright and Registered Trademark by Ortus Solutions, Corp.

BoxLang Subscriptions

BoxLang can also be enhanced by to give you:

  • Business Support with SLAs

  • Enhanced builds

  • Custom patches and builds

  • Dedicated Engineer

Support Open Source

To support us, please consider becoming our patron at for as little as $10/month.

Discussions & Help

The Ortus Community is how to get help:

You can also join our Slack Box Team at:

Reporting a Bug

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

Jira Issue Tracking

  • BoxLang:

  • BoxLang IDE:

  • BoxLang Modules:

Resources

  • Professional Support:

  • GitHub Org:

  • Twitter:

  • FaceBook:

Ortus Solutions, Corp

This book was written and maintained by and the 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 -

Release History

All the major information about BoxLang Releases

Versioning Schema

BoxLang is maintained under the Semantic Versioning guidelines as much as possible. Releases will be numbered in the following format:

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.

Version
Active Support
LTS (updates & security)
LTS (security-only)
  • 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.

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:

Code Of Conduct

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.

<major>.<minor>.<patch>

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

    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

    • 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 [email protected]. All security vulnerabilities will be promptly addressed.

    JRE Compatibility

    Please make sure your code runs on JRE 21+

    Financial Contributions

    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

    • One-time donations via PayPal

    2029 – 2030

    v4

    2028 – 2029

    2029 – 2030

    2030 – 2031

    v5

    2029 – 2030

    2030 – 2031

    2031 – 2032

    v1

    2025 – 2026

    2026 – 2027

    2027 – 2028

    v2

    2026 – 2027

    2027 – 2028

    2028 – 2029

    v3

    2027 – 2028

    2028 – 2029

    Docker Containers

  • Android/iOS Devices

  • Web assembly

  • Etc

  • Premium Modules
  • Much More...

  • LinkedIn: https://www.linkedin.com/company/tryboxlang

    Professional Open-Source Support
    Overview
    Apache 2
    purchasing subscriptions
    patreon.com/ortussolutions
    https://community.ortussolutions.com/c/boxlang/42
    https://boxteam.ortussolutions.com
    https://github.com/ortus-boxlang/boxlang
    https://ortussolutions.atlassian.net/browse/BL
    https://ortussolutions.atlassian.net/browse/BLIDE
    https://ortussolutions.atlassian.net/browse/BLMODULES
    https://www.ortussolutions.com/services/support
    https://github.com/ortus-boxlang
    https://x.com/TryBoxLang
    https://www.facebook.com/tryboxlang/
    Luis Majano
    Ortus Solutions
    https://www.ortussolutions.com/

    Modules

    The Officially supported BoxLang modules

    Our official modules can be found in the BoxLang Software Directory: FORGEBOX: www.forgebox.io.

    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.

    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

    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.

    CommandBox Runtimes

    The CommandBox CLI installs BoxLang modules into web runtimes.

    Eventually, CommandBox will be the de-facto standard of installation once it's migrated to BoxLang.

    Configuration

    You can customize the boxlang module directory by changing the runtime.modulesDirectory setting in your config/boxlang.json file:

    Core Modules

    Visit the section of our docs for the most up to date listing of our supported modules.

    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 .

    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.

    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.

    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.

    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.

    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.

    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.

    Learn how to deploy Windows Server-based BoxLang Cloud Servers here.

    this
    Modules
    Operating System
    # Install os-wide modules
    install-bx-module bx-compat-cfml
    
    # Install os-wide modules with a specific version
    install-bx-module [email protected]
    
    # Install multiple modules
    install-bx-module bx-compat-cfml bx-esapi bx-orm
    myAppDirectory
    # Install locally
    install-bx-module bx-compat-cfml --local
    
    # Install locally
    install-bx-module [email protected] --local
    
    # Install multiple modules locally
    install-bx-module bx-compat-cfml bx-esapi bx-orm --local
    CommandBox
    box install bx-compat-cfml,bx-esapi
    boxlang.json
    {
    
        // A collection of BoxLang module directories, they must be absolute paths
        "modulesDirectory": [
          "${boxlang-home}/modules"
        ],
    
    }

    Overview

    A quick overview of the BoxLang Language & Framework

    What is BoxLang?

    BoxLang

    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, 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

    • Be dynamic, modular, lightweight and fast

    • Be 100% interoperable with Java

    • Be modern, functional and fluent

    • Modularity at its core

    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.

    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 . 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 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.

    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!)

    Release Video

    We launched an open beta of BoxLang at our developer conference,

    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

    Implement timeout for HTTP requests

    Multi-part request support in HTTP

    Improvement

    Add text-based toString() method for Queries (used in console dumps)

    for in Java transformer not mapping source line numbers for start of loop

    Make include case insensitive

    Enhance metadata visitor to process extends

    add fieldNames key to form scope

    Auto casting for URI and URL classes to string

    Handle bad gateways in HTTP component

    Allow for multiple form fields with the same name in HTTP component

    autocast InetSocketAddress to string

    Bug

    Fix for overeager escaping of quantifier sequences in REFind

    High order closures creating incorrect AST when parsing

    Update DateTime Parsing to handle the Common Javascript Date.toString format

    Module settings no longer overriding after deep merge function added

    Java interop doesn't find method by argument types when passing null

    Can't assign to List due to incorrect validation in referencer

    content-type isn't always getting defaulted in some requests

    for/in loop over struct should get String keys instead of BL Key instances

    showUDFs not cascading down in dump levels

    using cfcookie should update cookie scope

    Fix argument order for FileUpload

    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

    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.

    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.


    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 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 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.

    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.

    🚀 Official IDE Support

    BoxLang provides first-class support for modern development environments with our official Visual Studio Code extension, compatible across multiple editors and platforms.

    BL-603
    BL-604
    BL-586
    BL-589
    BL-590
    BL-596
    BL-597
    BL-599
    BL-600
    BL-601
    BL-602
    BL-584
    BL-585
    BL-587
    BL-588
    BL-591
    BL-592
    BL-593
    BL-594
    BL-595
    BL-598
    BL-606

    Beta Stage

    This is the collection of Betas we released since our first version.

    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 - The primary development platform

    • Cursor - AI-powered code editor with BoxLang support

    • Windsurf - Modern development environment

    • Any IDE supporting Open VSX - Extended compatibility

    BoxLang IDE Extension

    Complete language support with IntelliSense, debugging, and AI-powered development assistance.

    BoxLang Theme Extension

    Beautiful dark and light themes specifically crafted for BoxLang syntax highlighting and optimal coding experience.

    🌐 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.

    BoxLang TextMate Bundle

    TextMate grammar bundle providing comprehensive syntax highlighting and snippets for BoxLang development across TextMate-compatible editors.

    🛠️ 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.

    BoxLang Debugger

    Built-in debugging tools and utilities for troubleshooting BoxLang applications with breakpoint support and variable inspection.

    CFML Feature Audit

    Comprehensive auditing tool to analyze CFML codebases and assess BoxLang compatibility and migration readiness.

    CFML to BoxLang Transpiler

    Automated migration tool for converting CFML code to BoxLang syntax with intelligent transformation and compatibility checks.

    🎨 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.

    🚀 Quick Start Guide

    For New BoxLang Developers

    1. Install VS Code - Download from code.visualstudio.com

    2. Install BoxLang Extension - Search for "BoxLang" in the Extensions marketplace

    3. Install BoxLang Theme - Apply beautiful BoxLang-specific color schemes

    4. Start Coding - Create your first .bx file and experience full language support

    For CFML Developers

    1. Audit Your Codebase - Use the CFML Feature Audit tool to assess migration readiness

    2. Transpile Code - Convert existing CFML to BoxLang using the automated transpiler

    3. Set Up Development Environment - Install the complete BoxLang toolchain

    4. Migrate Gradually - Use both tools to transition your applications systematically

    BoxLang IDE
    BoxLang Themes
    BoxLang Monaco Editor
    BoxLang TextMate Bundle
    BoxLang Compiler
    BoxLang Debugger
    CFML Feature Audit
    CFML Transpiler
    Syntax Highlighters

    Migrating from Adobe ColdFusion

    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

  • InvokeDynamic: BoxLang has a solid core foundation based on the JVM’s InvokeDynamic features. This makes the dynamic language extremely fast, predictable, and adaptable.

  • 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.

  • Pure Functions and Closures: BoxLang supports creating and using closures as a functional programming aspect. However, it also supports lambda pure functions 2 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.

  • 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.

  • 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.

  • 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.

  • 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 lambda 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.

  • 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.

  • 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.

  • 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.

  • 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 as its package manager, server manager, task manager, and REPL tool. Almost any project in https://central.sonatype.com/ 1 and https://www.forgebox.io should work with BoxLang.

  • ...

    CLI tools
    compatibility module
    Into The Box.
    Amazon Web Services
    Azure
    Google Cloud

    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

    • : createObject() now supports classloading arguments as the third argument.

    Easily manage and control classloading with arguments to enhance flexibility and modularity.

    • : Dynamic Task Management in Schedulers

    Added startupTask(task) to dynamically initialize tasks by name or task object.

    • : JSON-based Logging Support

    Appenders and root configurations now include JSON encoders for enhanced logging formats.

    • : Improved Scheduler Logging

    Scheduler logs are now effectively reported to provide better insights.

    • : Enhanced Module Logging

    Modules now have dedicated logs to improve debugging and diagnostics.

    • : New Event Lifecycle: onConfigurationLoad

    Introduced a new lifecycle event for IServices to optimize configuration handling.

    • : Enhanced Compatibility Assignments

    Assignments now accurately interpret null variables for better compatibility.

    • : New Logging Setting: statusPrinterOnLoad

    Added statusPrinterOnLoad for much-needed debugging of logging configurations.


    🛠 Improvements

    • : Streamlined Method Expectations

    Improved handling of methods that don’t expect return values for better consistency.

    • : Enhanced Session Cookie Controls

    Added missing controls for session cookie management to improve security and compliance.

    • : Bytecode Line Number Enhancements

    Added line number details to bytecode generated with ASM for improved debugging.

    • : ASM is Now the Default BoxPiler

    Streamlined the toolchain by making ASM the only default stock BoxPiler.

    • : Optimized Replace Operations

    Updated replaceAll() methods to use pre-compiled patterns for better performance.

    • : Unified Logging Configuration

    Consolidated logging startups and configurations for both servlet and non-servlet environments.

    • : Support for this.componentPaths

    Introduced implicit mapping support for more intuitive path management.

    • : Module Enable/Disable Support

    Modules can now be enabled or disabled using enabled in boxlang.json, removing double negatives like disabled.

    • : Forms Module Introduced

    A new module for handling forms was added, enhancing the BoxLang ecosystem.

    • : Improved Scope Assignment

    Allowed reassignment of a scope to a struct for more flexible programming.

    • : Collision Prevention in IClassRunnable Methods

    Prefixed methods to prevent naming collisions for safer execution.

    • : Graceful Module Unloading

    Added defensive coding for module unloading failures to ensure runtime stability.

    • : Consistent Struct Collector Outputs

    Resolved inconsistencies by ensuring collectors return Struct objects.

    • : Improved Parent Class Delegation

    Enhanced module class loaders to delegate certain parent classes to the parent loader exclusively.


    🐞 Bug Fixes

    • ASM and Debugging Fixes:

    , , , ,

    • Localization and Formatting Issues:

    , ,

    • Parsing Errors:

    , ,

    • Thread and Scope Resolution Bugs:

    , ,

    • Miscellaneous:

    , , ,

    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

    Implement Node pass-through methods to handle cloning and merging of XML objects

    Combine template and script grammars for boxlang

    Error Getting method keyExists for class ortus.boxlang.runtime.types.XML

    StructFindKey returns two findings on the same node if top level key is array

    Better error handling when dump template errors

    Return callback return value from runThreadInContext()

    java interop coerce BL arrays to native arrays

    Add toOptional() method to Attempt

    coerce return values of proxied methods

    output class of non-simple valued fields in class output for cfdump

    prefer same mapping for relative class lookups in box resolver

    Client scope needs more consistencies like the session scope when validating and expiration determination

    Module service record was not registering interceptors with the module settings

    HTTP Component - Implement Proxy Server handling

    add default itnerface helper for the IBoxContext to get the running application name if any

    Servlet to support Jakarta namespace

    New Features

    Move defaultCache to the caches section as default, verify it exists, else create it anyways

    add http events: onHTTPRequest, onHTTPResponse

    Expose buildRegistry() and encapsulate per location registration

    CLI BIFS for working with pure cli apps: cliRead(), cliGetArgs(), cliExit()

    Activate box resolvers cache according to request and app settings

    New setting: classResolverCache : boolean [true] which controls if the class locators caches resolve lookups

    Bugs

    varargs not working

    CF casts Class instances to a String

    Namespaced XML nodes not accessible by their non-namespaced names

    XMLSearch Not Finding Correct Results When Namespaces are Present

    XML asString Generates trailing line break

    StructFindKey Not Returning owner values correctly

    ASM compilation error

    query with empty column name can't be dumped

    WriteDump()/Dump() is broken in current snapshot build

    DateCompare on two zero-hour strings fails with long overflow

    XMLElemNew Illegal Character exception when using the namespace URI as the second argument

    HTTP Component - Implement Basic Authentication

    Cannot access variables scope in a static context -- but there is no variables access

    timezone not always used in datetime caster

    toUnmodifiableStruct() method not threadsafe

    directoryList filter param does not accept a closure

    Support for guid and uuid type

    getDirectoryFromPath returns different result to Lucee and ACF

    argument type of binary is not supported

    argument type of email is not supported

    CGI scope reporting 0 items

    JSONSerialize pretty prints JSON which blows up outbound NDJSON

    CFHTTParam Encodes Query Strings By Default

    URLEncodedFormat Replaces Spaces with Plus Symbols

    Bracket Notation Usage on Java Hashmaps Does not work.

    Detail and Extended Info Can Be Null In Thrown Exceptions

    BoxLang Themes

    Beautiful VS Code themes specifically designed for BoxLang development with dark neon and light muted variations

    Clean, modern themes designed specifically for BoxLang development. This extension provides two carefully crafted color schemes that enhance your BoxLang coding experience with optimal syntax highlighting and visual appeal.

    🎨 Available Themes

    BoxLang Dark (Neon)

    High-contrast dark theme featuring vibrant neon colors with pink, purple, and cyan accents. Optimized for extended coding sessions while maintaining visual appeal and code readability.

    BoxLang Light (Muted)

    Subtle light theme with soft teal and green backgrounds, perfect for daytime development. Features muted accent colors that reduce eye strain during long coding sessions.

    ✨ Key Features

    • BoxLang Optimized - Specifically designed for BoxLang syntax highlighting and component recognition

    • Semantic Highlighting - Enhanced token colors for better code understanding

    • Bracket Pair Colorization - Distinct colors for matching brackets and parentheses

    • Complete UI Theming - Consistent colors across editor, sidebar, terminal, and all VS Code interfaces

    📦 BoxLang Developer Pack

    Quick Setup: Get this theme along with all essential BoxLang development tools in one click with the !

    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:

    OpenVSX Registry:

    This automatically installs all BoxLang development tools, including this theme, saving you time and ensuring a complete setup.

    📦 Individual Installation

    VS Code Marketplace

    Install from the :

    1. Open VS Code and go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)

    2. Search for "BoxLang Theme"

    3. Click Install

    4. Go to File → Preferences → Color Theme

    OpenVSX Registry

    For VS Code compatible editors like Cursor, Windsurf, VSCodium, install from .

    Command Line Installation

    🎯 Recommended Settings

    Enable these VS Code settings for the best theme experience:

    🔧 Theme Selection

    After installation, activate your preferred theme:

    1. Windows/Linux: Ctrl+K, Ctrl+T or File → Preferences → Color Theme

    2. macOS: Cmd+K, Cmd+T or Code → Preferences → Color Theme

    🛠️ Development & Contributing

    GitHub Repository

    • Source Code:

    • Report Issues:

    Contributing Guidelines

    1. Fork the repository

    2. Create a feature branch

    3. Edit theme JSON files in the themes/ directory

    4. Run npm run build to validate changes

    Note: When reporting visual issues, please include your VS Code version, operating system, and screenshots for faster resolution.

    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, BL-300, BL-301, BL-302 Query caching improvements and compatibility updates

    BL-315 Ensure request attributes are available to the web runtime scope

    BL-164 bx-compat-cfml CFML compatibility module updates to ensure null query column values are returned as empty strings

    Bug Fixes

    Fixes compilation issue with variables name cfcatch

    CFML compatiblity for CGI.QUERY_STRING when not provided

    Fix null queryparam functionality

    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

    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 .

    Ubuntu 24.04 LTS based

    CommandBox CLI

    CommandBox is the de facto standard for BoxLang development and execution.

    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

    1.0.1

    May 1, 2025

    Bugs

    BoxRunner fails on some input args

    New Features

    BL-123 Implement multiple statements inside queries

    BL-383 new bif: datasourceRegister() to allow for easy saas integrations to create datasources

    BL-658 MIgrate AST Capture to it's own experimental flag

    BL-748 Add getApplicationContext() method on all contexts for convenience, especially when calling from CF/BL

    Improvement

    BL-730 Miniserver needs to 302 redirect when hitting a directory without the trailing slash

    BL-734 Broadcast Transactional events at the Application listener-level

    BL-735 Allow unregistering a java class (IInterceptor) from an InterceptorPool

    BL-737 Add getRequestContext() method on all contexts for convenience, especially when calling from CF/BL

    BL-738 Allow output from functional wrappers

    BL-740 Autocast simple values to Keys when calling java methods from BL

    BL-741 Allow :: static access to be chained to any expression

    BL-746 Add toLegacyDate BIF and Member Function to Compat module

    BL-751 Make generated getters return null when property is not initialized

    BL-116 Implement unfinished query options

    Bug

    BL-694 Fix tests that fail when using ASM

    BL-695 large json fails to deserialise with bx-compat

    BL-714 Add Whitespace Management

    BL-731 dump errors with compat installed due to null variable

    BL-733 RandRange seems to never return upper range

    BL-736 JDBC Transaction listeners not firing upon transaction event announcement

    BL-739 shebang checks in BoxRunner don't nicely handle invalid file paths

    BL-743 WDDX not parsing booleans correctly

    BL-744 Cannot cast ortus.boxlang.runtime.types.DateTime to java.util.Date

    BL-745 parseDateTime failing

    BL-747 for (sentinel) loop is evaluating the step/increment expression one final time too many when a break is used

    BL-752 error using negative indices to get characters from strings

    BL-754 error: integer number too large

    BL-755 SerializeJSON not working with named params

    BL-953
    BL-955
    BL-956
    BL-958
    BL-959
    BL-964
    BL-966
    BL-967
    BL-968
    BL-983
    BL-984
    BL-998
    BL-999
    BL-1002
    BL-1010
    BL-1013
    BL-843
    BL-935
    BL-952
    BL-989
    BL-1009
    BL-1016
    BL-389
    BL-931
    BL-947
    BL-949
    BL-950
    BL-951
    BL-960
    BL-961
    BL-965
    BL-969
    BL-970
    BL-977
    BL-978
    BL-981
    BL-982
    BL-985
    BL-991
    BL-994
    BL-995
    BL-996
    BL-1000
    BL-1003
    BL-1004
    BL-1005
    BL-1015
    BL-1017
    BL-305
    BL-309
    BL-314
    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.

    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.

    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.

    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.

    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.

    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.

    Learn how to deploy Windows Server-based BoxLang Cloud Servers here.

    this
    BL-1353

    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 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 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

    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 cheaper.

    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.

    Follow our migration guides below in order to migrate your existing ColdFusion/Lucee applications to a BoxLang runtime.

    Migration Guides

    Migrating from Adobe ColdFusionMigrating From Lucee CFML

    Warning

    There could be situations where certain functionality in Adobe/Lucee might not be available in BoxLang. 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.

    BL-121
    BL-699
    BL-794
    BL-828
    BL-829
    BL-832
    BL-833
    BL-846
    BL-682
    BL-706
    BL-760
    BL-766
    BL-784
    BL-787
    BL-788
    BL-791
    BL-809
    BL-812
    BL-822
    BL-830
    BL-831
    BL-839
    BL-694
    BL-742
    BL-759
    BL-762
    BL-760
    BL-819
    BL-825
    BL-820
    BL-823
    BL-824
    BL-827
    BL-813
    BL-815
    BL-817
    BL-826
    BL-836
    BL-841
    BL-845
    createObject( "java", "HelloWorld", [ "/libs/paths" ]
  • Component Support - Special highlighting for BoxLang components (<bx:component> tags)

  • Eye-friendly - Carefully selected contrast ratios for comfortable viewing

  • and select your preferred BoxLang theme
    Select either:
    • BoxLang Dark (Neon) - For high contrast dark experience

    • BoxLang Light (Muted) - For comfortable light experience

    Test themes using npm run dev:host

  • Submit a pull request with screenshots

  • BoxLang Developer Pack
    BoxLang Developer Pack
    BoxLang Developer Pack
    VS Code Marketplace
    OpenVSX Registry
    https://github.com/ortus-boxlang/vscode-boxlang-theme
    GitHub Issues
    BoxLang Dark Neon
    BoxLang Light Muted

    Try BoxLang!

    https://try.boxlang.io

    Interested in playing with BoxLang? You can test the syntax in a BoxLang interpreter hosted on AWS Lambda over at try.boxlang.io. These two micro-services have been written with BoxLang as well.

    try.boxlang.io

    Our BoxLang playground was built with our AWS Lambda runtime microservice and our BoxLang Docker Containers.

    Planswww.boxlang.io
    https://www.youtube.com/live/Bn3gzjzjtuc?si=ahCHxXKqg7_CASkOwww.youtube.com
    BoxLangOrtus Solutions Community

    Syntax Highlighters

    Here is a collection of official and unofficial syntax highlighters for BoxLang

    SyntaxHighlighter

    BoxLang brush module for SyntaxHighlighter. Please check out the instructions on how to build your own SyntaxHighligther and add custom brushes.

    Installation

    Example

    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

    Multi-Runtime

    BoxLang can be deployed to multiple runtimes

    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

    Available Runtimes

    The currently available and in-development runtimes are the following:

    Runtime
    Description

    1.0.0-Beta17

    October 4th, 2024

    In this release, we've introduced the exciting addition of websockets support to BoxLang through the powerful module. This enhancement is not limited to our Runtime but also extends to our 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 .

    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 (). Lastly, we've addressed session management by ensuring that application settings are readily accessible during the onSessionEnd event (). This release encapsulates our ongoing commitment to providing robust, cutting-edge solutions for developers and reaching stable release in the coming weeks.

    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.

    MiniServer Debugging

    Debug code running on the BoxLang MiniServer

    One convenient feature of our official BoxLang VS Code extension is the . The MiniServer is just that, a web server built to be fast and easy to work with. You can use it to spin up a server in any directory within your project and almost instantly test code. We even save your configuration to reuse your server again in the future! Let’s take a quick look at how to configure the MiniServer and some of its features.

    The MiniServer Panel

    After installing the BoxLang extension, you should see a new icon featuring the BoxLang logo in the sidebar. Clicking this icon brings up the BoxLang Server Panel. Here you will see a list of the servers you are currently using for the workspace you are currently in. To start configuring a server click the “+” icon at the top right-hand corner.

    About This Book

    Learn more about this book

    The source code for this book is hosted on GitHub: . 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.

    1.0.0-Beta12

    This update contains 9 features and improvements and 8 bug fixes.

    New Features

    • - Zip Components, Utility and incorporating BIFS

    • - Implement pagePoolClear()

    Frequently Asked Questions

    You can find a collection of frequently asked questions in our main website here:

    Experimental

    Here you can enable/disable experimental flags in BoxLang.

    This block is used to have experimental feature flags for BoxLang. Every experimental flag will be documented here once we have them.

    Compiler

    This is the compiler used for your BoxLang source. The available options are:

    • java : We will transpile your BoxLang source to Java, then compile it

    # Install the complete developer pack
    code --install-extension ortus-solutions.vscode-boxlang-developer-pack
    # VS Code
    code --install-extension ortus-solutions.vscode-boxlang-theme
    
    # VS Code compatible editors
    cursor --install-extension ortus-solutions.vscode-boxlang-theme
    {
      "editor.semanticHighlighting.enabled": true,
      "editor.bracketPairColorization.enabled": true,
      "editor.guides.bracketPairs": "active",
      "editor.fontFamily": "Fira Code, 'Cascadia Code', Consolas, 'Courier New'",
      "editor.fontLigatures": true,
      "editor.fontSize": 14,
      "editor.lineHeight": 1.5
    }

    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 arrayFind, arrayFindNoCase value closures, accept the value and now the index of the item as the second param

    BL-626 New configuration: validBoxLangTemplates to determine which templates the Runnable Loader can process

    BL-627 New configuration: validClassExtensions to determine which class extensions to work with

    BL-629 New security configuration section for disallowing: BIFS, Components, Imports

    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 Remove debugmode capture on miniserver, delegate to the core runtime.

    BL-622 Consolidate CastAttempt and Attempt into a hierarchy

    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 Import nested classes

    BL-615 Java static funcitons not behaving as expected

    BL-616 array.find does not use cf rules to convert result of predicate to boolean

    BL-619 QueryColumnType doesn't handle "idstamp" (mssql)

    BL-620 static scope in application.cfc not initialized before psuedoConstructor runs

    BL-624 Auto-escaping of {} in regex needs to ignore already-escaped braces

    BL-625 Instead of removing special chars from Java FQN, replace with __ to avoid conflicts

    BL-628 Tag expressions not parsing inside template island inside braces

    BL-631 duplicate() doesn't work on empty structs

    BL-633 randrange() not inclusive of upper bound

    BL-634 array.find - can't cast closure to string

    New Features

    BL-605 MiniServer WebSocket handler

    Improvement

    BL-607 Add version/build date to output of Miniserver startup

    BL-610 onSessionEnd needs application settings made available

    BL-611 Remove debugmode capture on miniserver, delegate to the core runtime.

    Bugs

    BL-608 Timeouts (connection, idle) for datasources needs to be in seconds and not in milliseconds to adhere to cfconfig

    BL-609 BoxLang resolvers do not allow class paths to have `-` in them.

    SocketBox
    CommandBox
    MiniServer
    here
    BL-607
    BL-610
  • asm : We will directly compile your BoxLang source to Java bytecode (Default)

  • Please note that asmwill be the default and you will not be able to change it once we release.

    AST Capture

    If enabled, it will activate the AST capture interceptor and on parse it will create a /grapher/data folder in your project with useful AST JSON captures. The default is false.

    boxlang.json
    "experimental": {
        // This choose the compiler to use for the runtime
        // Valid values are: "java", "asm"
        "compiler": "asm",
        // If enabled, it will generate AST JSON data under the project's /grapher/data folder
        "ASTCapture": false
    },

    Modules

    Configure how modules are loaded and work in BoxLang

    BoxLang is a modular language. Each module can have a configuration structure for usage within the language. The name of the key is the name of the module and each module config has the following keys available:

    • enabled : Boolean indicator to disable or eanble the module from loading. Defaults to `true`

    • settings : A structure of configuration settings each module exposes

    boxlang.json
    /**
     * The BoxLang module settings
     * The key is the module name and the value is a struct of settings for that specific module
     * The `enabled` property is a boolean that determines if the module should be enabled or not
     * The `settings` property is a struct of settings that are specific to the module and will be override the module settings
     */
    "modules": {
        // The Compat Module
        "compat-cfml": {
            "settings": {
                "engine" : "Adobe"
            }
        },
        // The Mail module
        "mail" : {
            "settings" : {
                "spoolEnable" : true,
                // Spool interval, in minutes
                "spoolInterval" : 1.5,
                "mailServers" : [
                    {
                        "tls": false,
                        "password": "",
                        "idleTimeout": "10000",
                        "lifeTimeout": "60000",
                        "port": "25",
                        "username": "",
                        "ssl": false,
                        "smtp": "127.0.0.1"
                    }
                ]
            }
        }
    }
    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 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

    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:

    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):

    You can also place numeric separators in decimals

    and in the exponent of scientific notation

    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 Add static assignment modifier

    You can now use the static assignment modifier in your code:

    which is sugar for

    and validate at runtime there is actually a static scope, or throw an exception.

    BL-458 Add final modifier to classes

    You can now use the final modifier in your classes

    which is sugar for:

    This means that your classes will not be able to be inherited from.

    BL-459 final modifier for UDFs

    Your UDFs can now also be declared as final

    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.

    BL-460 Add final assignment modifier for variables

    You can now add final assignment modifers to variables in your code:

    this, of course, can be used with other modifiers

    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

    cannot be mutated OR re-assigned.


    You can see the Set of final keys for a scope via the meta object

    You can also remove keys from the set to make a variable no longer final.

    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 ⚡

    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 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 Allow the incorrect foo..bar syntax that Adobe allows for

    BL-446 Cache sets() and getOrSets() does not accept duration in seconds alongside Duration objects.

    BL-455 Enhance ClassMetadataVisitor

    BL-468 Enhance feature audit to track QoQ separate

    BL-456 Validate var outside of a function

    BL-463 Support Adob'e loose comma parsing in their generic tag-in-script syntax

    BL-465 Enhance errors for identifiers starting with numbers

    BL-470 File And Directory BIFs to auto-expand received paths

    BL-431 Support variable starting with number

    Bugs

    BL-461 Compatible encryption with lucee/acf

    BL-462 replace() and replaceNoCase() should accept "one" not "once" for the scope

    BL-464 tag comments not parsing inside output tag in template parsers

    BL-466 parsing fails with extra whitespace in closing output tag

    BL-467 <cfset and <bx:set fail if not followed by a space

    BL-472 Debugger breakpoints not working regression

    BL-473 BoxLang Error is not readable

    BL-454 Tag island Templating outputs in unexpected order

    n = 1000000000
    n = 1_000_000_000
    n = 1_0_0_0_0_0_0_0_0_0
    n = 3.141_592_653_59
    1e2_345
    static foo = "bar"
    static.foo = "bar"
    final class {}
    class final {}
    final function foo() {
    }
    final function foo() {}
    foo = "brad" // exception because foo is final
    final foo = "bar"
    final static foo = "bar"
    final var foo = "baz"
    final lockDown = [ 1, 2, 3 ].toUnmodifiable()
    variables.$bx.meta.finalKeySet
    final foo = "bar"
    variables.$bx.meta.finalKeySet.clear() // Nothing is final in this scope now
    foo = "baz" // no error
    
    Status

    Bare metal runtime for any OS Java runs in

    Done

    Java scripting interfaces

    Done

    A pure Java webserver built with BoxLang

    Done

    Servlet WAR

    A servlet capable war

    Done

    A BoxLang engine for CommandBox

    Done

    The core impetus of BoxLang is to grow in a hierarchical approach to target specific runtimes with specific behavior for particular runtimes. For example, the concept of a FORM, URL scope, or web functions and components are only available to those runtimes that offer web support.

    Just because a runtime is not listed here doesn't mean BoxLang can't run there. These are just a collection of officially supported runtimes. You can use the core runtime and make it run ANYWHERE the JVM can be run. You can embed it now in Android, Azure, OpenWhisk, and more. However, once we have official runtimes, we will post them here.

    All of our runtime source code can be found in our organization: https://github.com/ortus-boxlang

    Third-Party Runtimes

    We love our community, and if you have created custom runtimes for BoxLang, please let us know, and we will add them here.

    installation methods.

    When you click the “+” icon, you will be prompted with a series of inputs to help configure your server. After filling out the prompts, your new MiniServer will start-up automatically. Once running, a browser window should open to the port the server configures.

    MiniServer Control Icons

    Now that your server is configured, it should show up in the list of available servers. You will see information about the status of your server here as well as some icons to be able to interact with it. Hover your mouse over the server to see what options are available. When the server is stopped you will see something like this:

    Stopped Controls
    • Delete

    • Edit (The name)

    • Run Server

    When the server is running you will see something like this:

    Running controls
    • Debug

    • Open Browser

    • Stop

    Trying Out Your App

    The BoxLang MiniServer is a real life BoxLang runtime. That means you can configure and run your code just like you would any other web server. The great part is it only took 5 seconds to get setup! This is great for quickly spinning up servers to test out an idea or even locally serve files for whatever reason or run small microservices.

    Another advantage of the MiniServer is that it makes debugging your web app very easy. You can spin up a webserver and start debugging your templates almost instantly. Just go add breakpoints wherever you want, hit your code in the browser and voila! You are now debuging your live MiniServer BoxLang application!

    Wrapping Up

    In conclusion, the MiniServer is a pretty cool feature provided by the official BoxLang VS Code extension. As a member of the BoxLang community your feedback is always valuable to us. Download the extension, spin up a MiniServer, throw some breakpoints in, and let us know what you think!

    built-in MiniServer
    Debug the MiniServer
    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

    Shalom Children's Party!

    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.

    https://github.com/ortus-boxlang/boxlang-docs
  • BL-491 - Add the ability to configure the CF transpiler

  • BL-490 - Transpiler doesn't handle attributeCollection

  • BL-438 - Zip Components, Utility and incorporating BIFS

  • Improvements

    • BL-486 - Compiler thread safety

    • BL-485 - Implements SystemCacheClear()

    • BL-483 - Allow "object" passed to throw to be a struct representation of an exception

    • BL-480 - Added all missing boxlang types to BoxLangType class

    • - Address parser performance by limiting operator reserved words

    • - Change template parsers to use SLL prediction mode

    • - Improve parsing performance by only calculating lines of code on error

    • - Add ValueRequiresOneOf Validator

    Bugs

    • BL-484 - Lock expects timeout to be minimum of 1

    • BL-481 - numeric literals with leading zeros are confused with octal values in java source

    • BL-482 - getApplicationMetadata() fails before application listener is defined

    • BL-476 - AST string values incorrectly unescaped outside of cfoutput

    • - Pretty printer incorrect for default case ending tag

    BL-438
    BL-487
    npm install brush-boxlang
    SyntaxHighlighter.brushes.BoxLang = require('brush-boxlang').default;
    SyntaxHighlighter.all();
    https://www.boxlang.io/#faq
    Logo

    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.

    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

    New Features

    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:

    Add loop times=n

    We have added a new construct for looping by using the keyword times in your loop statements:

    You can also use times and the index

    Or the item alias can be used as well as the index

    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.

    Improve parser error messages for unpopped parser modes

    For code like

    or

    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.

    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:

    We have also added several events that you can listen to during the transaction processes:

    • onTransactionBegin

    • onTransactionEnd

    • onTransactionCommit

    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

    Allow for circular references in structs and arrays

    Java 21 update to URL creation as new URL is deprecated

    add getMimeType method in FileSystemUtil to make it easier to get mime types of remote files ( e.g. PDF creation )

    Bugs

    <bx:loop query="query"> doesn't iterate over each item in the query, stays on the first item

    session scope can be null in onSessionEnd, causing errors

    Tasks

    Create tests for all valid and invalid dot and array access expressions

    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

    Writedump output support

    We have finalized the console output for the dump component, but we have also added the following ticket:

    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.

    Ability to mark a @BoxBif as excluded from documentation

    This is more of an internal documentation process for the team.

    New dump template for Java instants

    Java Instants will now be dumped nicely with an internal representation and a human readable representation.

    dump showUDFs

    All the arguments for dumps are now available including this one for controlling the dumping of UDFs on classes.

    Improvements

    Simplify BoxLang class dumps

    Add output and format to dump

    Some BIFs not fully supporting BigDecimal values

    access e.cause as shortcut for e.getCause()

    When creating an abstract class a new `AbstractClassException` is thrown. Great for testing frameworks

    Bugs

    queryaddcolumn ignores the datatype

    Issue with #dateTimeFormat(now(),'mm-dd-yyyy')# function returning incorrect results

    structnew( "linked" ) doesn't work

    argumentCollection doesn't work with implicit constructor

    directory component must always return query

    BoxNewTransformer using hard-coded context name

    toNumeric() not accepting radix values of 2-36

    cannot cast [x to object] on generic caster when using `QuerySetCell()`

    Issue with `Duplicate()` Function Causing Null Pointer Exception in BoxLang

    final keyword not working on this scope

    directoryList() filters are not working as closures/lambdas as they are hardcoded as strings

    Cannot invoke "ortus.boxlang.runtime.types.Query.isEmpty()" because "this.query" is null

    Multiple pipe-delimited glob patterns are not working as directoryList filters

    DuplicationUtil not doing deep clones of structs according to all types

    Throwing custom type exceptions just shows `custom` as the type instead of the actual type in the throw

    remote access not treated as public but as private for functions

    Interfaces don't support multiple inheritance

    CFC source type not detected correctly for abstract or final classes

    Metadata with : in them in cfml mode not treated correctly

    xml entity parsing issue when calling `toString()` on Java objects

    1.0.0-Beta20

    October 25th, 2024

    🚀 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

    trace bif and component

    Setup the thread's context class loader when an application is defined with the correct loader from the Applications java settings

    showDebugOuput added to request box context to allow for tracer/debugging outputs

    new computeAttachmentIfAbsent, to make fluent attachments on IBoxAttachable implementations

    refactor escapeHTML to the lib we use instead of multiple functions

    DateTime objects don't have a len member method

    Improvements

    Add line break in dump console output

    Allow access to super scope from thread

    reuse config of validTemplateExtensions

    Add ability to deep merge config items from the environment.

    track current request context in thread

    improve concurrency of session ID creation

    Move from immutable verbiage to unmodifiable

    Need to set explicit `/` path on session cookies

    if calling serializeJSON() on a class, and the class is marked as not serializable, then return empty struct

    if calling serializeJSON() on a class, properties marked as not serialiable should be skipped.

    Arrays/Lists/Structs/Maps/Classes that have been visited already by JSON will not serialize again but show a recursion marker

    Bugs

    bx-compat-cfml datediff fails to convert string

    Update parser to allow for `@module` notations on imports and `new` operators

    NOT operator precedence not grabbing operators in the chain

    Java Doc implementation is stricter that ACF and Lucee

    Missed module class hierarchy to have the runtime class loader as the parent

    ortus.boxlang.runtime.events.InterceptorPool: Errors announcing [logMessage] interception ortus.boxlang.runtime.types.exceptions.BoxRuntimeException: An error occurred while attempting to log the message

    Dump not showing BoxLang type NullValue as null

    DBInfo schema and several other columns can be null, make sure you address it

    boxclass dump looping construct exception

    java class method not found

    argument collection optional param is null

    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.

    DatabaseException: There is no known date-time pattern for '09/24/2024' value at ortus.boxlang.runtime.jdbc.PendingQuery.executeStatement(PendingQuery.java:390)

    cannot get lenght of native java date time objects

    Can't cast [2021-01-01 12:00:00 pm] to a DateTime.

    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, 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

    Production JIT Algorithm

    Please note that the production algorithm is still being developed. It is scheduled to be online by stable release.

    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.

    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.

    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 scripting, and much more.

    JSR-223

    BoxLang is a certified that can be used by any JVM language via the Scripting API.

    Multi-Runtime

    BoxLang has been designed to run in many using our multi-runtime approach. You can run BoxLang in any OS, web server, servlet container, docker engine, AWS Lambda, 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:

    Then we could run the program like this boxlang hello.bxs and get the following result:

    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:

    Keep reading our guides as you learn more about BoxLang.

    Scheduler

    Configure BoxLang's built-in task scheduler

    BoxLang includes a powerful built-in task scheduler that allows you to schedule and manage tasks at the runtime level. The scheduler is managed by the SchedulerService and can be configured globally or programmatically.

    Configuration Structure

    The scheduler configuration is located in the scheduler section of your boxlang.json file:

    Configuration Properties

    executor

    Type: string Default: "scheduled-tasks" Description: The name of the executor to use for running scheduled tasks. This must reference a valid executor defined in the executors section.

    cacheName

    Type: string Default: "default" Description: The cache to leverage for server fixation or distribution. This is useful when running BoxLang in clustered environments to coordinate scheduled tasks across multiple instances.

    schedulers

    Type: array Default: [] Description: An array of absolute paths to BoxLang scheduler files (.bx) that should be registered upon runtime startup. You can use variable substitutions like ${user-dir} or ${boxlang-home}.

    tasks

    Coming soon.

    Type: object Default: {} Description: You can define tasks manually in the configuration instead of using scheduler files. Each task is defined as a key-value pair where the key is the unique task name.

    Programmatic Scheduling

    You can also create and manage scheduled tasks programmatically using BoxLang's scheduling functions and components. The configuration above provides the foundation and default settings for the scheduler service.

    Related Configuration

    • - Configure the thread pools used by the scheduler

    • - Configure caches used for task coordination

    • - Configure logging for scheduler operations

    CommandBox

    The defacto enterprise servlet deployment for BoxLang - Power your mission-critical applications with CommandBox

    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 *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

    Runtime Configuration

    Configure it your way!

    BoxLang has an installation-level configuration file that allows developers to adjust various settings from the compiler to default cache providers, runtime-wide data sources, and much more. Depending on which runtime you are using, the configuration file location might change, but the configuration segments remain the same.

    Runtime
    Default Config Location

    Security

    Configure the security settings in BoxLang

    This segment is where you can configure the security elements of BoxLang under the securityblock in the boxlang.json

    Allowed File Operation Extensions

    An explicit whitelist of file extensions that are allowed to be uploaded - overrides any values in the disallowedWriteExtensions

    Individual file extensions may be whitelisted in your Application context like so:

    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!

    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 .

    New Feature

    Global events for Application events

    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 .

    Ubuntu 24.04 LTS based

    CommandBox Debugging

    Debugging a CommandBox BoxLang Server

    So you’ve installed and are running the latest BoxLang server like a boss. You open up your browser and are met with an error message. This looks like a job for, you guessed it, the BoxLang VS Code Debugger!

    Hooking VS Code Up To Your Server

    Connecting your debugger to an external may seem intimidating but CommandBox + VS Code makes this pretty straightforward.

    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.

    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.

    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.

    Authors

    Information about the authors

    Luis Fernando Majano Lainez

    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 .

    He is the CEO of , 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

    Datasources

    Here, you can configure the global data sources in the runtime.

    Datasources

    Here is where you can register datasources globally in the runtime. You can override them at runtime via:

    • Application.bx|cfc - For the application

    Hostingboxlang.io
    {
      "scheduler": {
        "executor": "scheduled-tasks",
        "cacheName": "default",
        "schedulers": [],
        "tasks": {}
      }
    }
    New Features

    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 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 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 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 Handle single values in arrayAppend merge=true

    A nice feature to support further merging techniques with arrays.

    Improvements

    BL-503 dump improvement of UI when using expand/collapse

    BL-545 Show errors in class pseudo constructor in tag context

    BL-555 List utils need to trim all values when converting to arrays

    BL-558 LocalDateTime not showing in dumps as a date/time string, but as a Java Object

    BL-567 Update date/time and instant dump templates to be less verbose and more functional

    BL-569 Allow CF tag islands and template islands to be nested more than one level deep.

    BL-570 Merge CF lexer and grammar for faster parsing and more accurate lexing

    BL-571 Make tag expression parsing smarter

    BL-576 expandPath() must ignore invalid paths, just returning the input

    BL-579 More IO BIFs need to ignore invalid paths

    Bugs

    BL-434 script block parsing can be tricked by comments

    BL-546 Lucee allows properties to be anywhere in the pseduoconstructor of a class, not just at the top

    BL-547 flush component only flushes up one buffer, not all the way

    BL-550 Boxlang doesn't parse milliseconds in datetime string

    BL-551 Date "string" doesn't have date time member functions available

    BL-552 Querynew failing with more than one column defined

    BL-553 Regular Expression Syntax not supported

    BL-557 Metadata visitor doesn't support struct annotations with unquoted keys

    BL-561 Hyper module failing

    BL-562 bx-compat cfloop requires "index" when it shouldn't

    BL-563 transaction shouldn't require global DSN

    BL-564 cfproperty tag lucee allows non quoted properties

    BL-565 Class name sensitivity based on provided rather than class found

    BL-566 No reading dump templates due to pathing incorrectly in debug mode

    BL-568 Static support not compatible with CFML

    BL-572 javacast not actually casting as expected

    BL-573 functions in variables scope vs values in variables scope

    BL-575 bx-compat unquoted hashed expressions cause compiler error

    BL-577 serializeJSON errors when serializing a function

    BL-578 Sentinel loop with missing expressions fails

    BL-582 mid() It does not remove characters if the count is more than the length

    BL-583 Cannot invoke "ortus.boxlang.runtime.types.IStruct.putAll(java.util.Map)" because "recipient" is null

    BL-479
    BL-478
    BL-477
    BL-474
    BL-475
    BL-142
    BL-508
    BL-489
    BL-504
    BL-507
    BL-497
    BL-499
    BL-501
    BL-517
    BL-518
    BL-223
    BL-471
    BL-492
    BL-493
    BL-494
    BL-498
    BL-500
    BL-502
    BL-505
    BL-506
    BL-509
    BL-510
    BL-511
    BL-512
    BL-513
    BL-514
    BL-515
    BL-516
    BL-521
    BL-522

    Ability to run BoxLang with AWS Lambda

    Done

    Docker

    BoxLang CLI, MIniServer and CommandBox images

    Done

    Azure Functions

    Ability to run BoxLang with Microsoft Functions

    In Progress

    Google Cloud Functions

    Ability to run BoxLang with Google Cloud Functions

    In Progress

    Android

    Ability to run BoxLang in Android Devices

    In Planning

    iOS

    Ability to run BoxLang in iOS Devices

    In Planning

    WebAssembly

    Ability to run BoxLang as WebAssembly compiled code

    In Planning
    OS
    JSR-223
    MiniServer
    CommandBox
    AWS Lambda
    BL-720 Implement table filter for dbinfo component

    BL-721 getComponentList() should also return the declared attributes of a component

    BL-722 getFunctionList() should also return the declared arguments of a BIF

    Improvement

    BL-710 Implement Algorithm Argument for RandRange

    BL-716 Set request class loader into thread as context class loader

    BL-717 Retain directories in dynamic class loader

    BL-728 Add nullIsUndefined flag to control how null variables are handled

    BL-729 Don't default properties with no default value to null when compat has enabled nullIsUndefined scope behavior

    Bug

    BL-638 Passing a null named argument hides outer bindings by the same name

    BL-641 Missing BIF - CSRFGenerateToken is now supplied with the bx-csrf module

    BL-669 Difference in args vs local variables handling

    BL-677 Incompat: metadata annotations from inherited sub classses added to top level class

    BL-679 cfloop collection with an array throws casting exception

    BL-697 argument collection optional param is null

    BL-711 dot access not chaining to static access

    BL-712 NPE when calling non-existent Java method

    BL-715 Duplicate of cfc instance presenting as struct

    BL-718 Key access in StructMapWrapper not working

    BL-719 GetTagData(), GetFunctionData() function not implemented, implement in the COMPAT module

    BL-724 import name restrictions too strict

    BL-726 Assignment not working on static fields of an imported class

    BL-727 Adding two ints uneccessarily returns a long

    the bx-csrf module
    BL-713
    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.

    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.

    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.

    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.

    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.

    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.

    Learn how to deploy Windows Server-based BoxLang Cloud Servers here.

    this
    BL-117
    BL-670
    BL-684
    BL-688
    BL-689
    BL-698
    BL-672
    BL-673
    BL-683
    BL-686
    BL-687
    BL-690
    BL-693
    BL-703
    BL-707
    BL-708
    BL-709
    BL-640
    BL-645
    BL-663
    BL-668
    BL-671
    BL-675
    BL-676
    BL-678
    BL-680
    BL-696
    BL-697
    BL-701
    BL-702
    BL-704
    BL-705
    https://www.youtube.com/watch?v=8M0IdUl7IWg&t=1swww.youtube.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

    Florida International University
    Ortus Solutions
    Luis F. Majano
    www.luismajano.com
    onTransactionRollback
  • onTransactionSetSavepoint

  • onTransactionAcquire*

  • onTransactionRelease*

  • https://docs.google.com/spreadsheets/d/1XkCQ8CPXslQWGCr8LHaQcDHZOMiwxST2nzX63_CSzvI/edit?gid=0#gid=0
    BL-394
    BL-395
    BL-396
    BL-397
    BL-408
    https://boxlang.ortusbooks.com/boxlang-framework/transactions
    BL-402
    BL-406
    BL-407
    BL-398
    BL-404
    BL-372
    Executors
    Caches
    Logging
    Anything placed in the allowed extensions overrides the disallowed extensions array

    Disallowed Imports

    An array of regex patterns (case-sensitive) that will try to be matched to imports or to creation of classes. If they match the patterns a security exception wil be thrown.

    Disallowed BIFS

    An array of BIF names that will be disallowed from execution.

    Disallowed Components

    An array of Component names that will be disallowed from execution.

    Disallowed File Operation Extensions

    The list of file extensions that are not allowed to be uploaded. Also enforced by file relocation operations ( e.g. copy/move ). By default, in the CLI and Lambda runtimes, we don't restrict, but you can :)

    In Web runtimes, the following extensions are disallowed by default. Unlike other engines this list does not apply to just uploads but applies to File move and copy operations. This is enforced to prevent a bad actor from uploading a file with one extension and being able to copy it to another that is executable.

    Note: If you wish to override a single extension you may do so by placing the extension in the allowedFileOperationExtensions setting in the application:

    populateServerSystemScope

    This is a boolean flag that, if enabled, will populate the server.system scope with the Java environment and properties. If disabled, it will not populate them and users will only be able to get environment and properties via the getSystemSetting() BIF.

    Usage

    Make sure you have installed the OS version of BoxLang 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 for boxlang runner.

    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:

    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.

    A-la-carte via query execution calls

    The key is the name of the datasource and the value is a struct of configuration for the JDBC connection. Most of the items can be different depending on the JDBC module and driver used. However, at the end of the day we need to know at least either the driver , the connectionString or individual items of the connection. Check out our guide on defining datasources here.

    Default Datasource

    The name of the datasource in the datasources configuration struct, which will act as the default one for the entire runtime.

    boxlang.json
    // 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"
    	}
    },
    expandedPath = expandPath( "/brad" );  // /absolute/path/to/brad
    contractPath( expandedPath ); // /brad
    loop times=5 {
        result &= "*";
    }
    loop times=5 index="i" {
        result &= i;
    }
    loop times=5 item="i" {
        result &= i;
    }
    <--- I never end
    foo = "trumcated...
    "executor": "scheduled-tasks"
    "cacheName": "default"
    "schedulers": [
      "${user-dir}/schedulers/MainScheduler.bx",
      "/path/to/custom/MyScheduler.bx"
    ]
    boxlang.json
    // These are the security settings for the runtime
    "security": {
    	// All regex patterns are case-insensitive
    	// A list of regex patterns that will match class paths, and if matched, execution will be disallowed
    	// This applies to import statements, createObject, new, and class creation
    	// Ex: "disallowedImports": ["java\\.lang\\.(ProcessBuilder|Reflect", "java\\.io\\.(File|FileWriter)"]
    	"disallowedImports": [],
    	// A list of BIF names that will be disallowed from execution
    	// Ex: "disallowedBifs": ["createObject", "systemExecute"]
    	"disallowedBifs": [],
    	// A list of Component names that will be disallowed from execution
    	// Ex: "disallowedComponents": [ "execute", "http" ]
    	"disallowedComponents": [],
    	// This is a boolean flag that determines if the server.system scope will be populated with the
    	// Java system properties and environment variables. By default this is set to true.
    	"populateServerSystemScope": true,
    	// An explicit whitelist of file extensions that are allowed to be uploaded - overrides any values in the disallowedWriteExtensions
    	"allowedFileOperationExtensions": [],
    	// The list of file extensions that are not allowed to be uploaded. Also enforced by file relocation operations ( e.g. copy/move )
    	"disallowedFileOperationExtensions": []
    },
    "allowedFileOperationExtensions": [],
    this.allowedFileOperationExtensions = [ "bxm", "bx" ];
    // Ex: "disallowedImports": ["java\\.lang\\.(ProcessBuilder|Reflect", "java\\.io\\.(File|FileWriter)"]
    "disallowedImports": [],
    // Ex: "disallowedBifs": ["createObject", "systemExecute"]
    "disallowedBifs": [],
    // Ex: "disallowedComponents": ["execute", "http"]
    "disallowedComponents": [],
    "disallowedFileOperationExtensions": [
    		"bat",
    		"exe",
    		"cmd",
    		"cfm",
    		"cfc",
    		"cfs",
    		"bx",
    		"bxm",
    		"bxs",
    		"sh",
    		"php",
    		"pl",
    		"cgi",
    		"386",
    		"dll",
    		"com",
    		"torrent",
    		"js",
    		"app",
    		"jar",
    		"pif",
    		"vb",
    		"vbscript",
    		"wsf",
    		"asp",
    		"cer",
    		"csr",
    		"jsp",
    		"drv",
    		"sys",
    		"ade",
    		"adp",
    		"bas",
    		"chm",
    		"cpl",
    		"crt",
    		"csh",
    		"fxp",
    		"hlp",
    		"hta",
    		"inf",
    		"ins",
    		"isp",
    		"jse",
    		"htaccess",
    		"htpasswd",
    		"ksh",
    		"lnk",
    		"mdb",
    		"mde",
    		"mdt",
    		"mdw",
    		"msc",
    		"msi",
    		"msp",
    		"mst",
    		"ops",
    		"pcd",
    		"prg",
    		"reg",
    		"scr",
    		"sct",
    		"shb",
    		"shs",
    		"url",
    		"vbe",
    		"vbs",
    		"wsc",
    		"wsf",
    		"wsh"
    	],
    this.allowedFileOperationExtensions = [ "bxm", "bx" ];
    "populateServerSystemScope" : false
    // 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
    // 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
    boxlang.json
    // You can assign a global default datasource to be used in the language
    "defaultDatasource": "main",
    "datasources" : {
        "main" : {...}
    }

    CommandBox becomes even more powerful with CommandBox PRO, which is included with BoxLang+ and BoxLang++ subscriptions. 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:

    For more Docker deployment options, visit the CommandBox Docker Hub repository.

    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

    You can find out more about getting started with CommandBox or CommandBox Pro in our CommandBox documentation.

    📦 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:

    This will add the right file types and handlers to CommandBox for BoxLang.

    This will no longer be needed on CommandBox 6.1+

    🚀 Start up a Server

    Starting a BoxLang server with CommandBox is simple and powerful. Navigate to your application's webroot and run:

    Additional Server Options

    CommandBox provides extensive server configuration options for enterprise deployments:

    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:

    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:

    Advanced Enterprise Configuration

    For production and enterprise deployments, you can leverage additional CommandBox features:

    🌍 Environment Variables

    The servlet/CommandBox runtime uses the same environment variables as the core OS runtime. You can find detailed information about all available environment variables here.

    🔧 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:

    Debug Mode

    You can enable debug mode for your BoxLang server using several approaches:

    --debug flag via the server start command

    env.BOXLANG_DEBUG environment variable

    Set env.BOXLANG_DEBUG in your server.json file:

    BOXLANG_DEBUG in a .env file

    Set BOXLANG_DEBUG=true in a .env file:

    .cfconfig.json debugMode setting

    Or set debuggingEnabled in your .cfconfig.json server configuration file:

    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

    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.

    CommandBox
    Ortus Solutions
    Running BoxLang

    All runtimes allow for configuration overrides.

    boxlang.json

    Once you startup a runtime, the runtime will find the BOXLANG_HOMEand create the config/boxlang.jsonfile with the defaults that it ships with. You may also change the granular config settings at runtime using the environment or Java properties by prefixing any configuration item with BOXLANG_or boxlang. See below.

    If you are running BoxLang within CommandBox, the configuration file will be inside the server directory inside of CommandBox under WEB-INF/boxlang/. You can also run the following command to see the server home directory:

    Runtime Home Directory

    By default, the BoxLang home directory is a .boxlang/ directory inside your user's home directory. For instance, on a Ubuntu machine, this might be /home/elpete/.boxlang/ if you are executing BoxLang under the elpete user account.

    ℹ️ The BoxLang home can be adjusted on startup via a --home flag:

    By allowing a custom home directory, you can manage multiple BoxLang runtimes and allow:

    1. custom, per-runtime configuration

    2. a custom set of BoxLang modules

    3. etc

    Boxlang.json Reference

    Here is the latest reference of the current default boxlang.json file:

    https://github.com/ortus-boxlang/BoxLang/blob/development/src/main/resources/config/boxlang.json

    Please note that JSON support in BoxLang allows you to use comments inline.

    Internal Variables

    The following are the internal variable substitutions you can use in any value:

    Here is an example:

    Environmental/Properties Configuration

    BoxLang gives you the ability to override any of the runtime configuration or module settings via environment variables or Java system properties. For example adding an environment variable of boxlang.security.allowedFileOperationExtensions=.exe,.sh would override the disallowed defaults, and allow users to upload and rename files with these extensions ( not a good idea! ).

    The variable names can be either snake-cased or dot-delimited. For example BOXLANG_DEBUGMODE=true will work the same as boxlang.debugMode=true to set the entire runtime in to debug mode.

    This convention allows you to make granular changes to sub-segments of the configuration without overriding parent items. JSON is also allowed when overriding config settings. For example, if I wanted to set the runtime logging level to trace without putting the runtime in to DebugMode, I could set the environment variable: boxlang.logging.loggers.runtime.level=TRACE or add the JVM arg -Dboxlang.logging.loggers.runtime.level=TRACE

    Environment Variable Substitution

    BoxLang supports environment variable substitution using the syntax ${env.environment_variable_name:default}. For example, using ${env.MYSQL_HOST:localhost} will result in the value of the MYSQL_HOST environment variable, if found, or fall back to the localhost value if the environment variable is not defined.

    Inside your boxlang.json configuration file, you can use this to populate datasource credential secrets:

    Configuration Segments

    Here, you will find each segment and its configuration details.

    AWS Lamba

    {lambdaRoot}/boxlang.json

    Operating System

    ~/.boxlang/config/boxlang.json

    MiniServer

    ~/.boxlang/config/boxlang.json

    CommandBox

    ~/.commandbox/servers/{serverHome}/WEB-INF/boxlang/config/boxlang.json

    Directives
    Caches
    Datasources
    Experimental
    Executors
    Logging
    Modules
    Scheduler
    Security
    Configuring CommandBox

    To start we will need to make sure our server is configured properly. You can do this one of two ways.

    1. We can add JVMArgs to the CLI when starting a BoxLang CommandBox server:

    1. The alternative approach is to add some configuration to our server.json definition:

    In these examples I’ve used port 8888 as the port we want the debugger to connect to control the CommandBox server through. You can specify whatever open port you want. You just need to make sure that you use the same one at every step.

    Once you start your server it should run as normal.

    Configuring VS Code

    Now that your server is configured, we need to setup VS Code. We will need to update your .vscode/launch.json. If you don’t see this file, you can create it yourself and VS Code will pick it up.

    We want the launch.json to look something like this:

    That's it. Now VSCode will know to what port to connect to your debugger running inside of CommandBox.

    Starting a Debug Session

    At this point your server is configured, it’s running, and you have just added a launch configuration. The next step is to run the debugger. All we need to do is open up the debug tab in our side-panel and select the correct configuration, which is the one we just added Debug CommandBox

    Now that we have everything setup all we need to do is press “play” or hit f5 and VS Code will fire up the BoxLang debugger and attach to your BoxLang server. That's it! Go add some breakpoints, go create some bugs and then fix them!

    CommandBox
    JSR223
    JSR-223 dynamic language
    different runtimes
    Logo

    Running BoxLang

    BoxLang and the Multiverse!

    Please check out our 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.

    The script for *nix/Mac is boxlang

    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.

    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.

    BoxLang Debugger

    Learn how to debug with BoxLang and the BoxLang IDE

    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.

    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.

    Demos

    BoxLang has an extensive collection of runnable demos showcasing real-world applications and integrations.

    Discover an extensive collection of demos at . 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:

    Executors

    Here you can configure the global thread executors in BoxLang.

    BoxLang allows you to register named executors globally. The JSON object key is the name of the executor and the value is another object with the type and a threads property, which is optional. By default, BoxLang pre-configures two executors for you:

    If you omit the threadson the executors, we will use the default of 20 threads.

    # 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
    install commandbox-boxlang
    server start cfengine=boxlang javaVersion=openjdk21_jdk
    # 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
    # Install individual modules
    install bx-mysql,bx-derby
    
    # Install modules with specific versions
    install [email protected],bx-redis@latest
    
    # Install from different sources
    install bx-compat-cfml
    install github:ortus-boxlang/bx-elasticsearch
    {
        "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"
        }
    }
    {
        "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...'"
        }
    }
    {
        "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"
        }
    }
    server start --debug
    "env": {
       "BOXLANG_DEBUG": true
    }
    BOXLANG_DEBUG=true
    {
        "debuggingEnabled": true
    }
    server status property=serverHome
    boxlang --home /path/to/boxlang-home
     * ${boxlang-home} - The BoxLang home directory
     * ${user-home} - The user's home directory
     * ${user-dir} - The user's current directory
     * ${java-temp} - The java temp directory
    "classGenerationDirectory": "${boxlang-home}/classes",
    {
        // ...
        "datasources": {
            "mySqlServerDB": {
                driver: "mssql",
                host: "localhost",
                port: "${env.MSSQL_PORT:1433}",
                database: "myDB",
                username: "${env.MSSQL_USERNAME:sa}",
                password: "${env.MSSQL_PASSWORD:123456Password}"
            }
        },
    
    }
    server start cfengine=boxlang
      javaVersion=openjdk21_jre
      JVMArgs='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8888'
    {
      "JVM": {
        "args": "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8888",
        "javaVersion": "openjdk21_jre"
      }
    }
    {
      "configurations": [
        {
          "name": "Debug CommandBox",
          "type": "boxlang",
          "request": "attach",
           // make sure this is the same value you configured your server with
          "serverPort": "8888",
          "program": "${workspaceFolder}"
        }
      ]
    }
    import java.lang.System
    import java.util.Date as MyDate
    import ortus.boxlang.runtime.types.Array
    
    start = new MyDate().getTime()
    num = 1000
    myArray = []
    myCopy = Array.copyOf( myArray )
    
    printLn( myCopy.size() )
    println( "Hello from BoxLang, printed on: " & now() )
    Hello from BoxLang, printed on: {ts '2024-05-21 22:07:19'}
    Logo
    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!

    1. 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.

    1. 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.

    2. 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.


    🔧 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!

    /**
     * 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 );
    	}
    
    }
    "boxlang": {
        "minimumVersion": "1.0.0",
        "moduleName": "test",
    }
    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()

    The script for Windows is boxlang.bat

    BoxLang Home

    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

    /Users/username/.boxlang
    /home/username/.boxlang
    c:/Windows/users/myuser/.boxlang

    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.

    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.

    Folder/FIle
    Description

    /classes

    Where all the compiled classes will be stored

    /config

    Where configuration files are stored for the runtime

    /config/boxlang.json

    The . Here is where you can configure all the settings, caches, datasources, compiler information, and so much more.

    /global

    Where global BoxLang classes and component templates can be stored for the entire runtime

    /lib

    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.

    /logs

    All log files will be stored here

    Start the REPL

    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.

    You can run one-off expressions from the REPL like so:

    Press Ctrl-C to exit the REPL or type exit or quit

    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

    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.

    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

    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.

    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)

    I get the output:

    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.

    You can now call it with zero or more arguments!

    One Off Code Execution

    So, to give a quiet example of the --bx-code flag here’s running some one-off code.

    This assumes script, not templating tags.

    Piping code

    You can also pipe statements into the BoxLang binary for execution as well. This assumes script, not tags.

    or

    Command Line Arguments

    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 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 for more information.

    • --bx-printAST - Prints out BoxLang AST in JSON format for code provided via the -c flag (for debugging)

    • --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

    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.

    installation page
    Licenses Available TODAY!

    Additionally, we are thrilled to open up support license subscriptions (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).

    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 [email protected].

    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, your applications will fly and be highly performant.

    Release Notes

    New Features

    BL-1065 Make sure execution exceptions are propagated to an `exception.log` for all runtimes

    BL-1070 Create getHTTPTimeString bif in the CFML Compat Module

    BL-1071 Missing bif: createTime()

    Improvement

    BL-1020 returns 500 status code when hitting the default error page

    BL-1027 Allow annotation values of unquoted strings

    BL-1028 allow RHS of castas operator to omit quotes

    BL-1029 default output to true in Application classes

    BL-1034 Disable external DTD validation

    BL-1050 Migrate usage of LoggerFactory.getLogger to the internal BoxLang logger classes in the core

    BL-1052 BIF and Component abstract objects now have a logger that maps to a `runtime` logger for ease of use

    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 Improve boxpiler selection by using the interface not classes or direct implementations

    Bugs

    BL-816 Abort should not fire the `onRequestEnd` method ( or it should fail quietly )

    BL-1008 Struct.put Usage Throws Error

    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 numeric key access of struct failing for BigDecimal keys

    BL-1030 directoryList does not sort by name

    BL-1031 Too many pattern letters: m

    BL-1032 Trivial: Typo in error message

    BL-1033 thread attribute scope needs to be headlessly accessible

    BL-1035 structget() incorrectly returning true with cfml-compat installed

    BL-1037 String caster doesn't work on char[] and produces incorrect results for Character[]

    BL-1038 class dump template doesn't work with compat module

    BL-1039 Access and mutation of native Java unboxed arrays doesn't work

    BL-1040 Query objects do not allow complex data when adding columns via `queryAddColumn()` with no data type.

    BL-1041 Can't use EMail as a returntype from EMail object

    BL-1043 shebang detection not working and skipping execution to the REPL

    BL-1044 isValid uuid returns false

    BL-1045 Error executing dump template

    BL-1047 default string representation of exception object

    BL-1048 Dereferencing property on Java class not calling getter

    BL-1049 Jakarta servlet removed response.setStatus( int, String ) from API

    BL-1051 Typo in exception string for parseDateTime

    BL-1053 getDirectoryFromPath breaks when passed a null value

    BL-1055 Durations created by `createTimespan` can't be casted to strings

    BL-1058 `this` scope can no longer be mutated

    BL-1059 final access modifier with explicit static scope on assignment not working

    BL-1060 static method access on non-imported identifer not working

    BL-1061 boxpiler was defaulting to javaboxpiler internally, remove it, it should be null and seeded later

    BL-1066 isSimpleValue returns true on Exception in Compat Mode

    BL-1068 QueryParam: SQL Server Unknown Column Type `datetime`

    BL-1069 ParseDateTime failure with `hh:nn a` mask - e.g. `03:00 PM`

    BL-1075 onRequestEnd() not firing for on class requests

    Planswww.boxlang.io
    www.boxlang.io/plans
    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.

    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:

    Command Pallete

    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.

    Variables

    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.

    Call Stack

    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.

    Controls
    • 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

    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!

    The BoxLang Debugger
    The BoxLang Debugger
    📱 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 - your online coding playground where you can experiment with BoxLang code directly in your browser without any local setup required.

    BoxLang online coding playground at try.boxlang.io

    📝 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:

    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 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

    Pro Tip: Each demo folder typically contains its own README with specific setup instructions, dependencies, and usage examples. Always check the README first!

    https://github.com/ortus-boxlang/bx-demos/
    Available Executor Types

    The available types of executors you can register in BoxLang are:

    Type
    Description

    cached

    Creates a thread pool that creates new threads as needed but will reuse previously constructed threads when available.

    Use Case: Best for applications that execute many short-lived asynchronous tasks.

    fixed

    Creates a thread pool with a fixed number of threads. If all threads are busy, new tasks will wait in a queue until a thread is available.

    Use Case: Ideal for situations where you need a consistent number of threads to handle tasks, ensuring that the resource usage remains predictable.

    fork_join

    Designed for tasks that can be broken down into smaller tasks and executed in parallel. It uses a work-stealing algorithm to optimize throughput.

    Use Case: Suitable for recursive algorithms, parallel processing, and tasks that can be divided into subtasks.

    scheduled

    Allows tasks to be scheduled to run after a given delay or to execute periodically with a fixed number of threads.

    Use Case: Perfect for tasks that need to run at regular intervals or after a specific delay, such as periodic maintenance or monitoring tasks.

    single

    Creates a single-threaded executor that executes tasks sequentially.

    Use Case: Useful for scenarios where tasks must be executed in order, ensuring that no two tasks run simultaneously.

    virtual

    It uses virtual threads, also known as fibers, which are lightweight and managed by the JVM, providing high scalability with low overhead.

    Use Case: Best for high-concurrency applications where many lightweight tasks need to be managed efficiently.

    As long as they implement the executor services interfaces, you can use them in BoxLang.

    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.

    Requirements

    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. Alternatively, see the tabs below for instructions on how to automate it.

    To use our BoxLang/CFML to Java transpiler, you must have the JDK installed, not the JRE.

    We recommend using to get started on a Mac with the BoxLang requirements. If not, you must download the requirements separately from the link above.

    Once the requirements are installed, move down to the quick installer.

    Leverage your system‘s package manager to install the needed requirements.

    APT

    Yum

    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)

    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

    Quick Installer

    Once the requirements above are installed, to get started quickly with BoxLang, use our BoxLang Quick Installer for Mac, Linux,* Nix, or Windows. This will allow you to execute the script in your favorite terminal application. Please note that some OS will require you to run it as an administrator or with sudo capabilities.

    You can see the full documentation for the quick installer in the link below:

    Let's get started:

    Just copy the following into your terminal to install by default for your user.

    If you want a system-wide installation, then prefix it with sudo:

    Please make sure you use the --help on our scripts to see everything you can do with them.

    Just copy the following into your terminal to install be default for your user.

    If you want a system-wide installation then prefix it with sudo:

    Please make sure you use the --help on our scripts to see everything you can do with them.

    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.

    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,

    • boxlang-miniserver - Our BoxLang MiniServer binary runner,

    • 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

    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 snapshotto install the bleeding edge release. You can find all the latest artifacts here:

    You can get the version of the current BoxLang Runtime by running boxlang --version

    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-modulesto install multiple modules at once as well.

    All our modules are available in the cloud software directory . You can also register and collaborate with modules of your own 🙋.

    Install to the BoxLang Home

    Install Locally

    You can also install modules to the running application (CLI, web) by using the --localoption in the command. This will create a boxlang_modulesfolder from which you ran the command and install the modules locally.

    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:

    To get started easily just follow the instructions:

    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 🚀

    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:

    • Zip (All OSs):

    • Jar:

    • Quick Installer (Mac/*nix)

    MiniServer Binaries

    The BoxLang MiniServer includes the BoxLang OS runtime with the addition of our super-fast and lightweight web server.

    • All OSs:

    AWS Lambda Binaries

    BoxLang can also run on AWS Lambdas. It even powers our entry playground at .

    • Runtime:

    • Template

    CommandBox BoxLang Server

    BoxLang can also be deployed using . This is our preferred way to deploy web applications using BoxLang. BoxLang +/++ Subscribers even get access to . Note: This installation method is typically tailored for a specific web application and is not typically accessible by other applications.

    Learn more in our

    Servlet EE Binaries

    This is the servlet edition of BoxLang that you can deploy on any servlet container (Jetty, Tomcat, JBoss, etc)

    • WAR:

    • JAR:

    Docker

    We have a full

    BoxLang IDE

    The BoxLang IDE is a collection of modules for VSCode that will give you a line debugger, LSP (Language Server Protocol), highlighting, introspection, generation, and much more. You can find it here:

    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 .

    BoxLang+, ++ Modules

    Our subscribers not only get professional/customized support but also new features, and modules. You can find out more about our subscriptions here: . Here is the collection of modules that you will get with your subscription which are not part of the open source edition.

    Module
    Description
    Status

    Logging

    Configure the logging framework in BoxLang

    This section configures the logging framework in BoxLang. Please note that BoxLang leverages RollingFileAppenders for most of its loggers. This provides consistency for the language and a consistent destination. You can customize it as you see fit, but this provides uniformity to the core and modules.

    The loggingsection is divided into global log settings and a loggers section where you can configure named loggers in the runtime.

    Please also note that in BoxLang, you can log data as text or as JSON.

    Global Properties

    Logs Directory

    This is the folder where BoxLang will store its log files. By default we use the following:

    Max Log Days

    The maximum number of days to keep log files before rotations. The default is 90 days or 3 months. If you put a 0 then rotation will never happen and you will log forever!

    Max File Size

    The maximum filesize for a single log file before rotation occurs. The default is 100 Megabytes. You can use a number or the following suffixes: KB, MB, GB.

    Total Cap Size

    The total cap size of ALL log files before rotation and compression begins. The default is 5 Gigabytes. You can use a number or the following suffixes: KB, MB, GB.

    Root Level

    This is the level at which the root logger will be allowed to be logged. By default, it is WARN, However, if it detects you are in debug mode, it will bump it to DEBUG.

    Default Encoder

    By default, BoxLang is configured to log using a pattern textual encoder. However, if you want to leverage the new JSON Lines format, you can switch the encoder for ALL loggers to be JSON. Valid values are text or json

    Status Printer On Load

    Activate the status printer on load to print out the logging configuration. This is useful for debugging LogBack and BoxLang logging configurations. The default is false.

    Loggers

    BoxLang allows you to pre-define named loggers that will be configured when used via BoxLang calls to:

    • writeLog() BIF

    • log component

    However, you can also retrieve named loggers via the LoggingService. By default, we will register the following named loggers:

    • runtime - The default log file for all runtime-related logging

    • async - All async operations and facilities will log here

    • cache - All cache operations and facilities will log here

    Logger Properties

    Every logger has the following configuration properties:

    Each logger will have the following configuration items:

    Property
    Default
    Type
    Description

    1.0.0-Beta19

    October 18th, 2024

    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

    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.

    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.

    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"

    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 wildcard imports from loaded jars

    The feature 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.

    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:

    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.

    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.

    The following were support tickets for all of these functionalities

    • Import Definitions now support module addressing for simple, wildcard and aliases

    • JavaResolver module targeted resolution

    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:

    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.

    Improvements

    Move CFID to compat module

    Have servlet runtime return actual pagecontext object instead of fake

    Update the allowedFileOperationExtensions and disallowedFileOperationExtensions to the security block

    Allow casting to array of primitive types

    Improve exception when trying to invoke null as a function

    Get ColdBox Loading via ASM

    Improve logic surrounding loading of pre-compiled source files

    added a `isCommitted()` to the PageContext to match the servlet response to assist when doing resets without exceptions

    StopGaps and config from cfconfig.json to boxlang.json

    NotImplemented updated to check if it's a string and if empty, then ignore it to provide leeway

    Rename default sessions cache to `bxSessions` to create the `bx` prefix standards. Add configuration to boxlang.json

    Bug

    boxlang invokes private onApplicationStart

    expandPath does not preserve file system case

    cfml2wddx action missing

    deserializeJSON not handling white space / control characters

    Update parser to allow for `@module` notations on imports and `new` operators

    listFind() and listFindNoCase() are allowing partial matches

    Can't dump null in console

    Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null

    CFML Feature Audit

    Discover if your application is compatible with BoxLang.

    The BoxLang CFML Feature audit tool is a CLI tool that will scan your source code and give you a compatibility report. This will allow you to see if your CFML code will run natively in BoxLang or if any BIFs or Components are required. Like the other tools, this is based on our BL AST (BoxLang Abstract Syntax Tree), so it should be accurate and not require anything like regex. It’s using the actual BL ANTLR parsers.

    Install the Compatibility Modules

    Before you run the tool, install the appropriate BoxLang modules so our tool can also account for those module collaborations. We recommend the following to simulate a CFML server:

    Remember, as you read below, tags are now called “components” in BoxLang. This tool will parse tag-based and script-based code alike.

    Features

    This CLI tool will scan

    • a single file

    • or a folder of files recursively (in parallel)

    and will track:

    • what BIFs you are using

    • What Components (Tags) you are using

    including the

    • file name where it is used

    • line number it was used on

    • The module that BIF/component is from

    • Whether or not that feature is missing from BoxLang currently (true/false)

    Data tracked can be

    • every occurrence of a component or BIF

    • aggregate of what BIFs/components were used per file

    • aggregate summary of what BIFs/components were used across all files

    and can be

    • printed to console

    • and/or written to CSV report file

    Usage

    Make sure you have installed the OS version of 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 for boxlang runner.

    You can call the tool using our script or the full path to the jar.

    CLI Options

    • --source - Defaults to working directory. If supplied, it must be followed by an absolute path or a path relative to the working directory.

    • --missing - Filter results to only show BIFs and Components which are missing from BoxLang.

    • --aggregate - Instead of showing every usage instance, roll-up counts at the file level by default.

    Examples

    Get a full report of all BIFs and Components used in a file

    Scan all your models for missing BIFs and Components

    Same as above, but aggregate results per file and write results to a CSV report

    Get a summary level aggregate report of all missing features in ColdBox output to the console

    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 Anyone?

    We have added support for 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-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

    boxlang
    boxlang.bat
    java -jar path/to/boxlang-1.0.0.jar
    boxlang task.bx
    boxlang myscript.bxs
    boxlang mytemplate.bxm
    
    boxlang /full/path/to/test.bxs
    boxlang /full/path/to/Task.bx
    boxlang.bat task.bx
    boxlang.bat myscript.bxs
    boxlang.bat mytemplate.bxm
    java -jar boxlang-1.0.0.jar task.bx
    java -jar boxlang-1.0.0.jar /full/path/to/test.bxs
    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]
    
    println( "Time is #now()#" )
    ╰─ boxlang test.bxs
    Time is {ts '2024-05-22 22:09:56'}
    class{
    
            function main( args=[] ){
    
                    println( "Task called with " & arguments.toString() )
    
            }
    
    }
    ╰─ boxlang Task.bx
    Task called with {ARGS=[]}
    
    ╰─ boxlang Task.bx boxlang rocks
    Task called with {ARGS=[boxlang, rocks]}
    boxlang --bx-code "2+2"
    echo "2+2" | java -jar boxlang-1.0.0.jar
    echo "2+2" | boxlang
    # 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
    task.bxs
    task = new Task();
    invoke( task, "setFoo", { foo : "bar" } );
    result = invoke( task, "getFoo" );
    
    println( result );
    Hello.bx
    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() );
    	}
    
    }
    
    git clone https://github.com/ortus-boxlang/bx-demos.git
    boxlang.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": {
    	// Use this for IO bound tasks, does not support scheduling
    	// This is also the default when requestion an executor service via executorGet()
    	"io-tasks": {
    		"type": "virtual",
    		"description": "Unlimited IO bound tasks using Java Virtual Threads"
    	},
    	// Use this for CPU bound tasks, supports scheduling
    	"cpu-tasks": {
    		"type": "scheduled",
    		"threads": 20,
    		"description": "CPU bound tasks using a fixed thread pool with scheduling capabilities"
    	},
    	// Used for all scheduled tasks in the runtime
    	"scheduled-tasks": {
    		"type": "scheduled",
    		"threads": 20,
    		"description": "Scheduled tasks using a fixed thread pool with scheduling capabilities"
    	}
    },
    boxlang.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",
    	// Activate the status printer on load to print out the logging configuration
    	// Turn on to debug LogBack and BoxLang logging configurations
    	"statusPrinterOnLoad": false,
    	// 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
    		}
    	}
    },
    # Install the modules to simulate a CFML server (Adobe, Lucee)
    install-bx-module bx-compat-cfml bx-password-encrypt bx-esapi bx-image bx-ini bx-mail bx-pdf bx-unsafe-evaluate bx-wddx bx-web-support

    work_stealing

    Creates a pool of threads that attempts to keep all threads busy by stealing tasks from other threads when they have completed their work.

    Use Case: Excellent for irregular workloads where tasks may vary significantly in complexity and duration, optimizing resource usage and improving performance.

    /modules

    Here is where the BoxLang modules are installed and will be available for the entire operating system binary.

    version.properties

    The version information of the installed runtime.

    Runtime Home Directory
    runtime configuration file
    Logo
    Not found
    datasource - Used by the creation, debugging, and management of datasources
  • modules - For all modular information, activation, etc

  • application - Application-specific logs

  • scheduler - All tasks and schedulers can log here

  • encoder

    logging > defaultEncoder

    text or json

    The encoder to use for logging. By default it leverages what was defined in the logging.defaultEncoder configuration.

    level

    TRACE

    logLevel

    The log level is to be assigned to the appender. By default, each appender is wide open to the maximum level of TRACE.

    additive

    true

    boolean

    true means that this logger will inherit the appenders from the root logger and log through all of them. false means it doesn't bubble up log messages.

    appender

    file

    string

    The type of appender to use for this logger. By default we use the rolling file appender. Valid values are: - file - console Coming soon values: - smtp - socket - db - syslog - class name

    appenderArguments

    ---

    object

    Name-value pairs that configure the appender. Each appender can have different arguments.

    --aggregate summary - If the arg “summary” is passed after the aggregate flag, we will roll the results up even further to include all files processed. In “summary” mode, the total number of files processed will also be output to the console, along with a breakdown of the number of file extensions encountered.

  • --quiet - Do not output the details of what was found on the console. Use in conjunction with the report path arg if you want to write out a report file. Even in quiet mode, each file processed will be output.

  • --reportFile - An absolute or relative (to the working dir) file path to write the data matching your filters and aggregate settings in a CSV format. Intermediate folders will be created. If the filename does not end with .csv, it will be appended.

    • The CSV columns, when not aggregating the data, will be File,Name,Type,Module,Missing,Line

    • The CSV columns, when aggregating data at a per-file level, will be: File,Name,Type,Module,Missing,Count

    • The CSV columns, when aggregating data at a summary level, will be: Name,Type,Module,Missing,Count

  • BoxLang
    CLI arguments
    JSON Lines
    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 section for all the docs on this.

    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.

    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.

    All the arguments from the dump bif/component will be passed through.

    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 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 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 Consolidate/Rename "LS" Bifs and Move US-Centric ones to Compat

    BL-409 Member method cleanup

    BL-410 Improve REPL output of native Java arrays

    BL-541 Add "decimal" as a cast type

    Bugs

    BL-496 replace and replaceNoCase functions do not accept a callback

    BL-519 Query dereferencing is not working correctly: Column '1' does not exist in query

    BL-520 Run Class via URL

    BL-523 A class which uses inheritance, the metadata includes the inherited functions in itself and parent.

    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 lsParseDateTime errors when given locale and mask

    BL-526 dateformat incorrectly parsing date with leading 0's?

    BL-527 onMissingMethod is not firing if the execution of the method is from within the class

    BL-528 query dumps assume the value is simple and can explode with encodeForHTML() can't do complex objects

    BL-530 Improve tracking of class in function box context

    BL-531 Difference of behavior with cfdirectory recurse = true not including path

    BL-532 super long strings cause compilation errors due to limitations in Java source code

    BL-533 Errors in miniserver when flushing large amounts of output to buffer

    BL-534 Missing !== operator

    BL-535 query cell assign erroring

    BL-537 Add onBifInvocation Interception Announcement to BIF invoke method

    // The location of the log files the runtime will produce
    "logsDirectory": "${boxlang-home}/logs",
    "maxLogDays": 90,
    "maxFileSize": "100MB",
    "totalCapSize": "5GB",
    "rootLevel": "WARN",
    "defaultEncoder" : "text"
    // Activate the status printer on load to print out the logging configuration
    // Turn on to debug LogBack and BoxLang logging configurations
    "statusPrinterOnLoad": false
    "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
    },
    // Using the script
    boxlang featureAudit <options here>
    
    // Using the full path to the jar
    java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.FeatureAudit  <options here>
    // Using the script
    boxlang featureAudit --source includes/myFile.cfm
    
    // Using the full path
    java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.FeatureAudit --source includes/myFile.cfm
    // Using the script
    boxlang featureAudit --source ./models/ --missing
    
    // Using the full path
    java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.FeatureAudit --source ./models/ --missing
    // Using the script
    boxlang featureAudit --source ./models/ --missing --aggregate --quiet --reportFile /path/to/models-missing-features.csv
    
    // Uisng the Full path
    java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.FeatureAudit --source ./models/ --missing --aggregate --quiet --reportFile /path/to/models-missing-features.csv
    // Using the script
    boxlang featureAudit --source ./coldbox/ --missing --aggregate summary
    
    // Using the full path
    java -cp boxlang-1.0.0.jar ortus.boxlang.compiler.FeatureAudit --source ./coldbox/ --missing --aggregate summary
    // 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
    		}
    	}
    },
    // Just call the toUnmodifiable() to lock the type
    myData = myDataService.queryData().toUnmodifiable()
    
    // You can also unlock it via the toMutable() method
    unlockedData = myData.toMutable()
    function onBxDump( data ){
      .. listen to the dump call
    }

    Arch Linux Variants

    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

    Use the following PowerShell 7.x script to install the JRE 21. HOWEVER, MAKE SURE YOU RUN THIS AS AN ADMINISTRATOR.

    Powershell 7.x:

    Windows PowerShell (5.x):

    • Once this runs, the JRE will be installed in your C:\Program Files\Java\jre{version}

    • A JAVA_HOME will be created for you

    Ensure you restart any terminal windows for the changes to take effect.

    Just copy this into a Powershell Terminal. HOWEVER, MAKE SURE YOU RUN THIS AS AN ADMINISTRATOR.

    Please make sure you use the --help on our scripts to see everything you can do with them.

    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.

  • bx-redis

    Native Redis integration is used for caching, session distribution, and publish-subscribe events. install-bx-module bx-redis

    Done

    bx-mongo

    Native MongoDB integration for caching, session distribution and advanced MongoDB operations.

    In Development

    bx-couchbase

    Native Couchbase integration for caching, NoSQL, session distribution and advanced Couchbase usage.

    In Development

    bx-pdftools

    Our collection of enhanced PDF tooling. Includes the ability to extract PDF forms, fill out PDF forms, squash, merge and more.

    In Development
    homebrew
    BoxLang Quick Installer
    learn more
    learn more
    https://downloads.ortussolutions.com/#/ortussolutions/boxlang/
    FORGEBOX
    BoxLang Version Manager (BVM)
    https://downloads.ortussolutions.com/ortussolutions/boxlang/boxlang-installer.exe
    https://downloads.ortussolutions.com/ortussolutions/boxlang/boxlang-latest.zip
    https://downloads.ortussolutions.com/ortussolutions/boxlang/boxlang-latest-all.jar
    https://downloads.ortussolutions.com/ortussolutions/boxlang/install-boxlang.sh
    https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-miniserver/boxlang-miniserver-latest.zip
    https://try.boxlang.io
    https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-aws-lambda/boxlang-aws-lambda-latest-all.jar
    https://github.com/ortus-boxlang/boxlang-starter-aws-lambda
    CommandBox
    CommandBox Pro
    CommandBox guide.
    https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-servlet/boxlang-servlet-latest.war
    https://downloads.ortussolutions.com/ortussolutions/boxlang-runtimes/boxlang-servlet/boxlang-servlet-latest-all.jar
    Docker guide you can follow here.
    FORGEBOX
    Modules
    BoxLang+, and ++
    https://boxlang.io/plans
    BoxLang IDE
    brew install openjdk@21
    # Update OS first
    sudo apt-get update
    sudo apt-get full-upgrade
    
    # Install requirements
    sudo apt-get install openjdk-21-jre
    # Update OS first
    sudo yum update
    sudo yum upgrade
    
    # Install requirements
    sudo yum install java-21-openjdk
    
    # Update OS first
    sudo xbps-install -Su
    
    # Install requirements
    sudo xbps-install openjdk21
    
    /bin/bash -c "$(curl -fsSL https://install.boxlang.io)"
    sudo /bin/bash -c "$(curl -fsSL https://install.boxlang.io)"
    /bin/sh -c "$(curl -fsSL https://install.boxlang.io)"
    sudo /bin/sh -c "$(curl -fsSL https://install.boxlang.io)"
    powershell -NoExit -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://install-windows.boxlang.io'))"
    BL-667
    BL-232
    BL-653
    BL-653
    BL-646
    BL-647
    BL-648
    BL-657
    BL-658
    BL-612
    https://community.ortussolutions.com/t/introducing-the-socketbox-stomp-broker-demo/10396
    BL-328
    BL-637
    BL-644
    BL-650
    BL-652
    BL-654
    BL-655
    BL-660
    BL-661
    BL-662
    BL-666
    BL-635
    BL-636
    BL-639
    BL-642
    BL-645
    BL-649
    BL-651
    BL-659
    try.boxlang.io
    BoxLang Try Online Interface

    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 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

    By default, queries will use , which has default timeouts and lastAccessTimeout values set.

    To specify a custom caching provider, you can use the cacheProvider query option:

    To specify custom cache entry timeouts, use cacheTimeout or cacheLastAccessTimeout:

    Note that the bx-compat-cfml module will take care of implementing .

    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:

    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

    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).

    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.

    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.

    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.

    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.

    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.

    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.

    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.

    Improvements

    Refactor JDBC connection retrieval out of the QueryOptions class

    Dynamic method matching discovery algorithms updated to do 2 pass algorithm: exact, loose coercion matching

    Improvement of cache service and cache provider methods for easier boxlang interactions

    Refactored the dump css to `resources/dump/html/Dump.css`

    Migrate dynamic proxies to native java implementation from the JDK

    passing the session id to the onsessionstart listener

    Give better warnings if the sessionStorage is not a valid string

    Bug

    attributecollection not handled properly on cfthrow

    Left in system out calls that need to be removed

    JSR ScriptEngine starting runtime without debug flag if passed

    Creating a default cache was not setting the right name and a "default" already registered exception was being thrown

    Default argument values not always checked for type

    Implements missing from Box Class metadata

    Static Scope missing from metadata

    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

    transpile queryGetRow() to queryRowData()

    Ths is a compatibility feature for CFML engines so they can use the queryGetRow() BIF which internally funnels to the () method.

    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:

    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

    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:

    JSStringFormat BIF

    This BIF is now complete to provide JavaScript escaping when using BoxLang as the template processor:

    xml component

    We have now finalized XML support in BoxLang with a beautiful xml component:

    getVariable() & 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:

    Add getClientVariablesList() to compat

    Legacy client scope support added to the compat module

    New getDescendantsOfType() AST method with predicate

    This is an internal method of our contexts to allow us to retrieve things easily with predicates.

    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.

    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.

    Add isNumericDate BIF

    This BIF is now in the core thanks to a client migration.

    Add getHTTPTimeString BIF to web-support

    Our web support package gets a new BIF thanks to a client migration

    Writedump label support

    WriteDump in BoxLang now get beautiful labels!

    java.math.BigInteger caster

    We have a new caster for BigInteger and BigDecimal to help us with precise mathematics in BoxLang.

    Improvements

    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.

    content component can have body

    Enhance error messages for parsing invalid tag code

    Bugs

    MalformedInputException: Input length = 1 when parsing CFC

    component detection can be tricked if there is a tag comment line starting with the word "component"

    Regression: Can't run files via BoxRunner due to new action command logic

    Sometimes trying to shutdown runtime throws NPE if it was never started fully

    pretty print visitor outputting extra " on tag catch block

    pretty print visitor doesn't handle array notation invocation

    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

    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.

    Consolidate the runtime into services without the need of getInstance()

    A simple internal improvement to improve locking and instance usage.

    New Features

    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

    Examples

    Please note that the attributes is a struct of data that we will bind into the thread's local scope.

    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] )

    Examples

    Collect stream of objects into BoxLang array

    Collect stream of Map entries into a struct

    Collect an array of structs into an existing query object

    Collect a stream of objects into a list

    orThrow( type, message ) for attempts

    Attempts now allow you to do a custom exception type and message. Check out the docs.

    ifSuccessful() alias to ifPresent() on attempts

    Attempts now allow you to have an alias to ifPresent() that's fluent: ifSuccessful(). Check out the docs.

    Bugs

    Parser detection for unparsed tokens only works if there are 2 or more tokens left

    Declaring UDFs in function context doesn't always work

    CFConfig datasources aren't importing due to lack of support for the 'dbdriver' key

    Runtime can deadlock due to syncronized methods

    NPE calling isNumeric()

    JSONSerialize() errors when useSecureJSONPrefix not a boolean

    Cannot call getWriter(), getOutputStream() already called

    empty url vars coming through as null

    Tasks

    Create tests for al valid and invalid dot and array access expressions

    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 Create the config `runtimes` struct so any runtime can store their settings there by convention

    BL-1327 Add simple rewrites to miniserver

    Improvements

    Add a `version` key to the boxlang.json to track the current version of the runtime.

    expandPath(".") when running boxlang as a shell script does not point to the current working directory

    Possible minor bug in Mail

    Can we improve URL to PDF support?

    Pre-compiled matchers for exception stack builds for performance

    LineNumber alias on exception traces for multiple Box tools in the open

    Upate isObject, isArray and IsStruct to have more edge cases and consistencies across engines

    looping over XMLNode as collection only loops over child nodes

    BoxLang file with no extension should try to determine if it's an executable class

    Expand relative this.mappings in application class

    change extract() BIF so filter argument works the same as directoryList()

    make missing template error use relative path, not absolute path

    Support samesite and expires in servlet

    change compress() BIF so filter argument works the same as directoryList()

    generatePBKDFKey() compat issues

    SCryptVerify() doesn't support hashes generated in Adobe ColdFusion

    Bugs

    Compat: FileMove in ACF/Lucee automatically overwrites the destination file

    Use of compat-transpiled name in scoped variable throws error

    Compat: Error parsing date with zero month

    Cookie with Quoted Value Intermittently comes back with URL-Escaped quotes

    Rethrown Exception Inside Transaction Being Wrapped In Application Exception

    Elvis using nullValue on right hand side throws error

    Using BIFS in CLI schedulers throws an error that request context is empty

    Dumping class with top argument results in Struct template error.

    Class which implements IReferenceable alone throws errors when Attempting Serialize to JSON

    Error with parseDateTime on ISO with fully numeric offset

    relative include with ../../ can result in illegal class name

    caches set operations relies on timeouts being Objects, do stricter validation and conversion to avoid can't cast string to longs

    hash CFML compatability

    cfml compat: returnformat is case sensitive for remote methods

    cfml compat - cfinclude with non cfml files

    CFML compat. Undefined query values are strings in ACF / Lucee

    CacheLocator cache is too aggressive on same name but different location classes

    dump templates for Function, Map and XML missing expand null checks

    XML structkeyExists returns false when objects are there but isNull returns false

    jsonSerialize() or deserialize with cookie setting is adding extra "

    static initializer above properties is giving a syntax error

    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

    Serializing queries to JSON compatibility

    DynamicObject.hasMethodNoCase() is returning false for methods that clearly exist and are invokable

    JDBC - Missing support for no connection limit

    Static access is not a valid construct for array access

    featureAudit incorrectly reports the valueList() BIF as missing

    cfhtmlhead does not work properly

    Implement CFCookie Expires

    cfcookie samesite attribute not honored

    CFML Compat - cfcookie encodevalue attribute not honored

    overriding `/` mapping in this.mappings not working

    dump/abort doesn't always default response content type in servlet

    ASM Boxpiler is not generating the correct bytecode when dealing with abstract classes

    bx:location throws error in console

    BX-PDF - Issue with PDF support and document section, specifically Acrobat Reader

    documentsection name not properly setting bookmark name

    Relax default permissions of bx:document

    Compat: dateTimeFormat "h" mask

    SCryptVerify() function aliases

    hash() returns lower case from CFM pages

    Schedulers defined in Application.bx do not have access to application scope values defined in onApplicationStart

    cliread was closing the system.in instead of sharing across the cli

    bitwise complement doesn't work with variable

    Expansion of "/tmp" resolves to relative path.

    elvis doesn't work in lambda

    Tasks

    TimeBox Certification

    Compat: Document DateAdd Behavior with Decimal Number Difference from ACF/Lucee

    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

    Quick Setup: Get this theme along with all essential BoxLang development tools in one click with the !

    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:

    OpenVSX Registry:

    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 :

    OpenVSX Registry

    For VS Code compatible editors like Cursor, Windsurf, VSCodium, and others, install from :

    Developer Resources

    • GitHub Repository:

    • Documentation:

    ✨ 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

    Development Tools

    • - 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

    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

    🎯 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

    BoxLangwww.boxlang.io

    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

    CFML Transpiler

    Transpile your CFML code to BoxLang.

    This CLI tool will allow you to transpile your CFML code into BoxLang native code. This is a great way to move forward and leverage BoxLang for your future projects. It will also transpile your Tag-based CFCs into script.

    🚀 Usage

    Make sure you have installed the OS version of 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 for the boxlang runner.

    You can call the tool using our script or the full path to the JAR:

    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'))"
    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'))"
    # 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 [email protected]
    
    # 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
    
    # Get all the help
    install-bx-module --help
    # 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
    # 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 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
    # Install BVM
    curl -fsSL https://install-bvm.boxlang.io/ | bash
    
    # Or download and run locally
    wget --content-disposition https://install-bvm.boxlang.io/
    chmod +x install-bvm.sh
    ./install-bvm.sh
    box install commandbox-boxlang
    box server start cfengine=boxlang javaVersion=openjdk21_jdk
    # Update OS first
    sudo pacman -Syu
    
    # Install requirements
    sudo pacman -S jre21-openjdk
    
    // 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
    },
    import cbvalidation.models.*;
    import cbvalidation.models.result.*;
    
    class accessors="true" serialize="false" singleton {
    
        ...
        // cbvalidation.models.GenericObject
        target = new GenericObject( arguments.target )
        
        ...
    
    }
    // 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);
        }
    }
    // 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()
    // 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();
    
    // 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-1199
    BL-1275
    BL-1278
    BL-1285
    BL-1286
    BL-1287
    BL-1293
    BL-1296
    BL-1310
    BL-1311
    BL-1323
    BL-1324
    BL-1334
    BL-1336
    BL-1337
    BL-1339
    BL-1098
    BL-1123
    BL-1131
    BL-1218
    BL-1266
    BL-1267
    BL-1271
    BL-1272
    BL-1273
    BL-1274
    BL-1279
    BL-1280
    BL-1281
    BL-1282
    BL-1283
    BL-1284
    BL-1289
    BL-1290
    BL-1291
    BL-1292
    BL-1294
    BL-1297
    BL-1299
    BL-1301
    BL-1302
    BL-1303
    BL-1304
    BL-1306
    BL-1307
    BL-1308
    BL-1309
    BL-1312
    BL-1313
    BL-1317
    BL-1321
    BL-1325
    BL-1326
    BL-1328
    BL-1331
    BL-1340
    BL-1341
    BL-1343
    BL-1345
    BL-1346
    BL-1348
    BL-1349
    BL-179
    BL-1136
    Logo
    - 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.

  • the default Boxlang CacheProvider
    the historical cachedWithin and cachedAfter query options
    BL-261
    BL-281
    BL-284
    BL-285
    BL-289
    BL-292
    BL-298
    BL-254
    BL-280
    BL-283
    BL-290
    BL-291
    BL-296
    BL-297
    BL-198
    BL-278
    BL-279
    BL-282
    BL-286
    BL-287
    BL-288

    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

  • BL-435
    queryRowData
    BL-436
    BL-437
    BL-439
    BL-442
    BL-443
    BL-444
    BL-448
    BL-449
    BL-450
    BL-440
    BL-441
    BL-143
    BL-447
    BL-425
    BL-426
    BL-429
    BL-427
    BL-428
    BL-432
    BL-451
    BL-452
    BL-453
    .toBXList( [String delimiter] )
    BL-376
    BL-392
    BL-374
    BL-388
    BL-390
    attempt
    BL-391
    attempt
    BL-373
    BL-377
    BL-378
    BL-379
    BL-380
    BL-381
    BL-385
    BL-386
    BL-372
    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:

    Pretty JSON Serialization (BL-1542)

    Added pretty argument to jsonSerialize() function to enable formatted JSON output for improved readability and storage.

    Example:

    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:

    List Example:

    Query Example:

    Struct Example:

    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:

    🚀 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 Add `compressionLevel` to the zip component and utilities

    BL-1512 Add checksums to all binary creations in the build process

    BL-1533 xNone() for bif operations: array, list, query, struct

    BL-1542 Added `pretty` argument to jsonSerialize() to allow for pretty serialization

    Improvement

    BL-1471 Add Examples to docs for BIFs and Components

    BL-1494 Don't allow scopes to be "overridden" with scope hunting

    BL-1511 Add Support for Compressed HTTP responses

    BL-1516 arrayFind shouldn't throw on mismatched types

    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 Add --help -h to Mini Server

    BL-1522 Add --help -h to Feature Audit, CFTranspiler, Scheduler, BoxRunner and more

    BL-1526 Bumps org.semver4j:semver4j from 5.7.0 to 5.7.1.

    BL-1528 Add lazy expiration for caching

    BL-1534 Query Concurrency Improvements : There are some inconsistencies and issues when dealing with adding data to queries in parallel threads

    BL-1536 Bumps com.fasterxml.jackson.jr:jackson-jr-stree from 2.19.0 to 2.19.1.

    BL-1537 Refactor @NonNull and @Nullable to use compile time checkers instead of runtime dependencies

    BL-1544 Create a transpiler rule for cfquery params: `cfsqltype` to `sqltype`

    Bugs

    BL-1216 Image scaleToFit creating black images

    BL-1217 Image resize not working as member func.

    BL-1472 JDBC - Transaction defaults to app-default datasource, and ignores the datasource named in the first query

    BL-1501 Compat: Math Operations Which Encounter Timestamps Should Cast as Fractional Days

    BL-1503 Update parallel computations to use a tiered execution approach; xSome, xEvery, xMap, xFilter, xEach

    BL-1504 looping groups breaks when it should continue

    BL-1507 HTTP Errors When Uploading File

    BL-1513 fix() behaviour is not equal to Lucee's behaviour

    BL-1523 All multi-part form fields are being written to disk

    BL-1524 CFCatch support when catch variable defined in bx-compat-cfml

    BL-1527 DATETIME is not being aliased by query parameters in prepared statements

    BL-1529 Several concurrency issues on cache entries created and last access timeouts

    BL-1530 cache entry equals evaluating the hash codes incorrectly and causing collisions

    BL-1531 Set base template for remote methods in super class

    BL-1532 Better handle ../ in servlet paths

    BL-1541 The `type` property in class metadata still references "component" instead of being "class"

    BL-1547 duplicate function broken when using xml objects

    queryExecute(
        "SELECT * FROM developers WHERE role = ?",
        [ "Developer" ],
        { cache: true }
    );
    queryExecute(
        "SELECT * FROM developers WHERE role = ?",
        [ "Developer" ],
        { cache: true, cacheProvider : "redis" }
    );
    queryExecute(
        "SELECT * FROM developers WHERE role = ?",
        [ "Developer" ],
        {
            cache: true,
            cacheTimeout : createTimespan( 0, 0, 0, 30 ),
            cacheLastAccessTimeout : createTimespan( 0, 0, 0, 30 )
        }
    );
    writedump( myQuery.$bx.meta )
    // 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" ) )
    // 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()
    // Create, register and return
    getBoxRuntime().getAsyncService()
        .newVirtualExecutor( "MyVirtualExecutor" )
    writedump( getModuleList() )
    writeDump( getModuleInfo( "bx-image" ) )
    createDynamicProxy( myclass, [ array of interfaces ] )
    createDynamicProxy( myclass, interface path )
    [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
    // 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" );
    <script>
    let info = "#JSStringFormat( "An example string value with ""quoted"" 'text'" )#"
    </script>
    <bx:xml variable="myVar">
      <root>
        <foo attr="brad" />
        <foo attr="luis" />
        <foo attr="jon" />
      <root>
    </bx:xml>
    setVariable( prepVar(), "hello" )
    
    println( getVariable( getVar() ) )
    boxlang task.cfm
    boxlang script.cfs
    class{
        // serializable
        property name;
        // not serializable
        property boolean isLoggedIn deafult=false serializable=false
    
    }
    threadNew( lambda/closure, [attributes={}], [threadName], [priority=normal] )
    threadNew( () => {
        printLn( "thread is done!" );
        sleep( 1000 );
        result = "done";
    } );
    
    threadNew( () => calculateOrder( invoice ), {invoice:myData}, "order-builder", "high" )
    foods = [ 'apples', 'bananas', 'pizza', 'tacos' ];
    result = foods.stream().parallel().toBXArray();
    
    import java.util.stream.IntStream;
    result = IntStream.range(1, 6).toBXArray();
    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" );
    qry = queryNew( "name,title", "varchar,varchar" );
    
    [
      	{ name: "Brad", title: "Developer" },
      	{ name: "Luis", title: "CEO" },
      	{ name: "Jorge", title: "PM" }
    ].stream().toBXQuery( qry );
    foods = [ 'apples', 'bananas', 'pizza', true ];
    foods.stream().toBXList();
    
    [ "www", "google", "com" ].stream().toBXList( "." )
    // Zip Component
    bx:zip compressionLevel="9"
    
    // Compress BIF
    compress( compressionLevel: 9 )
    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 ) );
    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 )
    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')
    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)
    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)
    # 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 ✓"

    Type Information - Rich type hints and validation

  • Error Detection - Real-time syntax and semantic error reporting

  • SQL - Database query highlighting

  • JavaScript - Client-side scripting

  • Workspace Integration - Multi-root workspace support

    Start coding with full IntelliSense and debugging support

    BoxLang Developer Pack
    BoxLang Developer Pack
    BoxLang Developer Pack
    Visual Studio Code Marketplace
    OpenVSX Registry
    https://github.com/ortus-boxlang/vscode-boxlang
    https://boxlang-ide.ortusbooks.com/
    Built-in Debugger
    BoxLang IDE Extension in VS Code
    BoxLang IDE Extension providing syntax highlighting, IntelliSense, and debugging support
    Getting Help

    📋 CLI Options

    Option
    Short
    Description
    Default

    --help

    -h

    Show help message and exit

    -

    --verbose

    -v

    Enable verbose output with detailed progress information

    false

    --source <PATH>

    -

    Path to source directory or file to transpile

    New in 1.6.0: The --verbose / -v flag provides detailed transpilation progress, showing file-by-file status, parsing issues, and directory creation operations.

    🔄 File Extension Mapping

    The transpiler automatically converts ColdFusion file extensions to their BoxLang equivalents:

    ColdFusion
    BoxLang
    Description

    .cfm

    .bxm

    ColdFusion markup → BoxLang markup

    .cfc

    .bx

    ColdFusion component → BoxLang class

    .cfs

    .bxs

    ColdFusion script → BoxLang script

    💡 Examples

    Transpile Current Directory

    Transpile Specific Directory

    Transpile Single File

    Verbose Mode (New in 1.6.0)

    The verbose output will show:

    • 🚀 Transpiler initialization

    • 📂 Directory scanning progress

    • 🔄 File-by-file transpilation status

    • ⚙️ Parsing operations

    • 📁 Directory creation

    • ✅ Success confirmations

    • ❌ Detailed error messages with parsing issues

    Stop on Error

    Complete Example with All Options

    📂 Behavior

    • Directory Transpilation: Preserves folder structure from source to target

    • Single File Transpilation: Allows custom target naming

    • Auto Directory Creation: Missing target directories are created automatically

    • Error Handling: Parsing errors are logged; processing continues unless --stopOnError is used

    • Parallel Processing: Directory mode processes files in parallel for better performance

    • Extension Auto-Mapping: Target extensions are automatically determined based on source type

    🔧 Supported Source Files

    The transpiler supports the following ColdFusion file types:

    • .cfm - ColdFusion markup pages

    • .cfc - ColdFusion components

    • .cfs - ColdFusion script files

    ⚠️ Known Limitations

    The transpiler has some current limitations to be aware of:

    • Whitespace: May not preserve the exact whitespace from the original source. Since the Abstract Syntax Tree (AST) doesn't store whitespace from script-based code, you'll get whatever formatting the tool applies. We plan to make some of this configurable (tabs vs. spaces, etc.)

    • Annotations: ALL function and class annotations are converted to the new @foo bar syntax. We'll update this eventually to keep inline annotations as inline and only move CF "JavaDoc" style annotations to pre-annotations

    • Script Conversion: All CFCs will be converted to script. This is by design as BoxLang enforces classes to only be written in script

    📖 Additional Resources

    • BoxLang Documentation

    • Community Forums

    • GitHub Repository

    BoxLang
    CLI arguments

    Caches

    This configures the caches in the runtime

    Overview

    BoxLang comes bundled with an enterprise caching engine that can be configured with different settings and backend object stores. It is also can give you the ability to register caches that adhere to our BoxCache interface (ICacheProvider) to create an implementation agnostic API. Apart from the core providers we create, we also have several in our + subscriptions and anybody can build custom providers as well.

    You can also define per-application caches by defining them in the Application.bx file in your applications.

    Default Caches

    Every BoxLang runtime comes pre-configured with the following caches that are mandatory for operation:

    Cache
    Hint

    Configuration

    Every cache must be placed inside the cachesobject with a unique name key. The value of that key contains:

    • provider - The name of a core provider or a full classpath to use. Ex: BoxCacheProvider which is the core one, or a module collaborated class or class path class: ortus.boxlang.modules.redis.RedisCache

    • properties - An object of configuration for the provider.

    BoxCache Provider

    Our BoxCacheProvideris an enterprise-level cache designed to be fast and event-driven. Here are the available configuration options.

    Object Stores

    Global Properties

    Here are the global properties for all object stores.

    evictCount

    How many objects can be evicted once a policy is triggered? The default is 1.

    evictionPolicy

    The eviction policy to use. The available policies are:

    • LRU (default): Least Recently Used

    • LFU: Least Frequently Used

    • FIFO: First in First out

    • LIFO: Last in Last Out

    freeMemoryPercentageThreshold

    The free memory percentage threshold to trigger eviction 0 = disabled, 1-100 = percentage of available free memory in heap. If the threshold is reached, the eviction policy is triggered. The default is 0.

    maxObjects

    The maximum number of objects to store in the cache. The default is 1000

    defaultLastAccessTimeout

    The maximum number of seconds an object can be kept in the cache since its last access. If an object is not accessed at this time or greater, it will be removed from the cache. The default is 1800 seconds or 30 minutes.

    defaultTimeout

    The maximum time in seconds to keep an object in the cache regardless if it's used or not. A default timeout of 0 = never expire, careful with this setting. The default is 3600 seconds or 60 minutes.

    objectStore

    The object store to use to store the objects. The default is a ConcurrentStore.

    reapFrequency

    The frequency in seconds to check for expired objects and expire them using the policy. This creates a BoxLang task that runs every X seconds to check for expired objects. The default is 120 seconds or 2 minutes.

    resetTimeoutOnAccess

    If enabled, the last access timeout will be reset on every access for the cache entry. This means that the last access timeout will be reset to the defaultLastAccessTimeout on every access. Usually for session caches or to simulate a session. The default is false.

    useLastAccessTimeouts

    If enabled, the last access timeout will be used to evict objects from the cache. The default is true.

    Object Stores

    BoxCache supports multiple object store backends for different caching scenarios. Each store provides different persistence, performance, and distribution characteristics.

    For detailed information about each store type, including configuration examples and best practices, see the documentation:

    • - High-performance in-memory caching (default)

    • - Memory-sensitive caching with automatic GC support

    • - Disk-based persistent caching

    • - Database-backed distributed caching (New in 1.7.0)

    Each store page includes:

    • Features and capabilities

    • Complete configuration examples

    • Store-specific properties

    • Usage patterns and best practices

    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.

    1.1.0

    May 12, 2025

    New Features

    • Add parse() helper methods directly to runtime, which returns parse result

    • new security configuration item: populateServerSystemScope that can allow or not the population of the server.system scope or not

    # Install the complete developer pack
    code --install-extension ortus-solutions.vscode-boxlang-developer-pack
    code --install-extension ortus-solutions.vscode-boxlang
    # For compatible editors using OpenVSX
    cursor --install-extension ortus-solutions.vscode-boxlang
    # Using the OS binary
    boxlang cftranspile [OPTIONS]
    
    # Using the full path to the JAR
    java -jar boxlang-1.6.0.jar ortus.boxlang.compiler.CFTranspiler [OPTIONS]
    # Display comprehensive help
    boxlang cftranspile --help
    boxlang cftranspile -h
    # Transpile all ColdFusion files in current directory
    boxlang cftranspile --target ./boxlang-output
    # Convert an entire project with directory structure preserved
    boxlang cftranspile \
        --source ./coldfusion-code \
        --target ./boxlang-code
    # Convert a single file (extension auto-detected)
    boxlang cftranspile \
        --source app.cfm \
        --target app.bxm
    # See detailed progress information during transpilation
    boxlang cftranspile \
        --source ./cf-app \
        --target ./bx-app \
        --verbose
    # Stop transpilation on first error encountered
    boxlang cftranspile \
        --source ./cf-app \
        --target ./bx-app \
        --stopOnError
    # Full-featured transpilation with verbose output
    boxlang cftranspile \
        --source /path/to/cf/project \
        --target /path/to/bx/project \
        --verbose \
        --stopOnError

    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 Create query of queries support

    BL-883 Implement list parameters in JDBC queries

    BL-933 Ability to register custom functions for QoQ

    BL-942 Interceptor Service now does a service loader load of all interceptors found in the runtime to auto-load them

    Improvements

    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 Update getMetaadata() for dynamic proxies to leverage the class metadata instead of instances

    BL-865 CFTranspiler should not turn off accessors for persistent classes

    BL-866 Exception type matching check cause

    BL-919 Implement "Quick" algorithm for Hash BIF

    BL-920 Compat: CacheGet second argument is boolean for Lucee

    BL-926 ASM error in do/while with a break

    BL-938 Update the getOrCreateSession() to verify if the session has expired, and if so, rotate it.

    BL-939 Change generic tag-in-script syntax for Box Script to prefix with bx:

    Bugs

    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 structsort with callback errors

    BL-758 QofQ shouldn't require global DSN

    BL-764 xmlsearch - invalid XPath

    BL-801 ASM Failing test - fix bx:output transformer

    BL-802 ASM Failing test - fix abort exception

    BL-834 Dump Top Updates will not dump certain classes without a top argument, top shows as reached for subsequent dumps

    BL-847 BL GenericProxies cannot have java.lang.Object methods call on them

    BL-849 Class properties are merged from all inheritance levels in the metadata

    BL-850 Dumps are not in order of execution

    BL-851 Java List dumps are not working with top and are off by 1

    BL-854 Wirebox Block: testbuildJavaClass Methods on Java objects cannot be called with named arguments when using invoke()

    BL-855 Coercion for constructors from string to numbers are not working

    BL-856 Coercion from strings to numbers does not exist

    BL-857 isInstanceOf bif and keyword are not working on createObject("java") proxies. It gives a negative result

    BL-858 var scoping issues for bleeding scopes on class dump template

    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 ORM: getter setters are not enabled for persistent CFCs

    BL-863 ORM: writedump causes ClassInfo not found

    BL-864 ORM: entityLoad should only require entity name

    BL-867 Show the right exception type when invoking dynamic objects and there are exceptions from a caused by

    BL-868 caching does not handle quoted numbers or booleans in config

    BL-869 ORM: EntityLoad errors when using a filter

    BL-870 soft reference cannot be stored directly in a struct

    BL-875 rework onSessionEnd to make sure the application exists when calling the listeners

    BL-877 Lucee allows params to be passed to cfquery tag via `params` attribute

    BL-879 IsNumeric() returns true for "true" and "false"

    BL-880 QueryNew() throws exception if row data array is empty

    BL-884 MSSQL throws error when executing certain queries if language is not English

    BL-885 Setting a dynamic variable name doesn't work

    BL-886 Can't cast [now] to a DateTime

    BL-887 cfloop step not implemented

    BL-888 allow "switch" as struct key name in CF script

    BL-889 The instance [ortus.boxlang.runtime.types.exceptions.ParseException] has no public field or inner class [ERRORCODE]

    BL-890 In function [numberFormat], argument [number] with a type of [java.lang.Boolean] does not match the declared type of [number]

    BL-891 Datasources created after module load take on custom DSN parameters defined in bx-mssql

    BL-892 cfqueryparam with list attribute causes "The index 2 is out of range"

    BL-893 Queryparam list=true is unsupported

    BL-894 Key in arguments scope gets lost

    BL-895 Allow "switch" to be used in dot access

    BL-896 Can't cast ts to a Number.

    BL-897 named query params not handled correctly

    BL-898 Account for placeholder text in comments and quoted strings in SQL

    BL-899 numberFormat is displaying a leading 0 when formatting integers < 10

    BL-901 Duplicate() on CGI scope creates empty struct

    BL-902 CGI-Scope weirdness

    BL-903 MSSQL connection gets lost

    BL-904 Empty test fails when using ASM

    BL-905 MSSQL Query columns have wrong values

    BL-906 Using bx:output inside of bx:catch causes bxCatch scope to disappear

    BL-907 Array Loop with negative step doesn't work

    BL-909 Cannot invoke "ortus.boxlang.runtime.components.Component$BodyResult.isEarlyExit()" because "bodyResult" is null

    BL-910 Passing query column to listToArray() BIF fails

    BL-911 IsNumeric BIF returns true on booleans in compat mode

    BL-912 getBaseTemplatePath returns `Application.cfc` in onRequestStart

    BL-913 Throw with exception object as unnamed argument fails

    BL-914 Null session scope when attempting to update the last visit

    BL-917 Compat GetComponentMetadata Failures with "Can't cast null to a Key".

    BL-918 String [1 LTE 5] cannot be cast to a boolean

    BL-923 Compat: Attributes to Functions Are Scoped in to nested Parameters Struct

    BL-925 Cannot invoke method [clearbuffer()] on a null object

    BL-927 Double variable assignment failing in ASM

    BL-928 Compat: Invoke method has different required object method

    BL-930 StructFindKey Returns a Null Value when Struct being searched contains nulls

    BL-932 toBinary() not lenient enough for decoding with line paddings

    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 getOrCreateSession() relying on the starting listener for settings, when it should look at the context to reflect changes if any

    BL-941 WebRequest interceptor in web support is not auto-loading, also will affect any other composable runtimes

    BL-944 node.xmlText explicit assignment throws error that value is not node or XML instance

    BL-945 xmlAttributes assignment error - key not found

    Task

    BL-217 ColdBox Test Suite

    BL-220 Quick Test Suite

    BL-548 Parser performance and removing ambiguity

    BL-767 CFcasts Suite

    BL-837 UnleashSDK Certification

    BL-908 Incorporate TestBox test suite

    Stories

    BL-237 Phase II : Update all the toAST() methods to the new and consolidated approach

    BL-238 Phase III : Performance tests for phase I + II toolchains

    BL-239 Phase V : Create the QoQ SQL grammar, parser, and astss

    Current directory (.)

    --target <PATH>

    -

    Path to target directory or file (required)

    -

    --stopOnError [BOOL]

    -

    Stop processing on first error

    false

    https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-boxlangmarketplace.visualstudio.com
    Install Now
    Not found

    RANDOM: Randomly evict objects

    BlackHoleStore - Mock store for testing

    Performance considerations
  • When to use each store type

  • default

    The default cache in BoxLang is used for queries, templates, and many more internal usages.

    bxSessions

    If you activate session management in your web or client applications, user session information will be stored here.

    bxRegex

    This is where all dynamic regular expressions are compiled and kept.

    BoxCache Stores
    ConcurrentStore
    ConcurrentSoftReferenceStore
    FileSystemStore
    JDBCStore

    Improvements

    • BL-1333 Create links to BoxLang modules

    • BL-1351 match getHTTPTimeString() and default time to now

    • BL-1358 Work harder to return partial AST on invalid parse

    • BL-1363 Error executing dump template [/dump/html/BoxClass.bxm]

    • Compat - Move Legacy Date Format Interception to Module-Specific Interception Point

    • allow box class to be looped over as collection

    • Rework event bus interceptors to accelerate during executions

    • Compat - Allow handling of decimals where timespan is used

    • Allow Numeric ApplicationTimeout assignment to to be decimal

    Bugs

    • BL-1354 BoxLang date time not accepted by JDBC as a date object

    • BL-1359 contracting path doesn't work if casing of mapping doesn't match casing of abs path

    • BL-1366 sessionInvalidate() "Cannot invoke String.length() because "s" is null"

    • BL-1370 Some methods not found in java interop

    • string functions accepting null

    • onMissingTemplate event mystyped as missingtemplate

    • fileExists() not working with relative paths

    • optional capture groups throw NPE in reReplace()

    • array length incorrect for xml nodes

    • Numeric Session Timeout Values Should Be Duration of Days not Seconds

    BL-1365
    BL-1388

    BoxLang Quick Installer

    The BoxLang Quick Installer is the fastest way to get started with BoxLang.

    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:

    Windows:

    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

    PDF Module

    Differences From CFML

    A quick guide on key differences and issues when migrating from CFML

    Please note that our CFML Compatibility is still in progress. Please keep this page bookmarked as we progress to our stable release.

    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 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:

    GitHub Actions

    Run BoxLang in your GitHub Actions seamlessly with the official setup action.

    🚀 Automate your BoxLang setup - This GitHub Action sets up the runtime for CI/CD workflows with optional CommandBox CLI and module installation.

    ⌨️ Action Inputs

    Configure your BoxLang setup using these input parameters:

    Input
    Type
    Default
    boxlang.json
    "caches": {
    	// The configuration for the BoxLang `default` cache.  If empty, we use the defaults
    	// See the ortus.boxlang.runtime.config.segments.CacheConfig for all the available settings
    	// This is used by query caching, template caching, and other internal caching.
    	// You can use the cache() BIF in order to get access to the default cache.
    	"default": {
    		"provider": "BoxCacheProvider",
    		"properties": {
    			// How many to evict at a time once a policy is triggered
    			"evictCount": 1,
    			// The eviction policy to use: Least Recently Used
    			// Other policies are: LRU, LFU, FIFO, LIFO, RANDOM
    			"evictionPolicy": "LRU",
    			// The free memory percentage threshold to trigger eviction
    			// 0 = disabled, 1-100 = percentage of available free memory in heap
    			// If the threadhold is reached, the eviction policy is triggered
    			"freeMemoryPercentageThreshold": 0,
    			// The maximum number of objects to store in the cache
    			"maxObjects": 1000,
    			// The maximum in seconds to keep an object in the cache since it's last access
    			// So if an object is not accessed in this time or greater, it will be removed from the cache
    			"defaultLastAccessTimeout": 1800,
    			// The maximum time in seconds to keep an object in the cache regardless if it's used or not
    			// A default timeout of 0 = never expire, careful with this setting
    			"defaultTimeout": 3600,
    			// The object store to use to store the objects.
    			// The default is a ConcurrentStore which is a memory sensitive store
    			"objectStore": "ConcurrentStore",
    			// The frequency in seconds to check for expired objects and expire them using the policy
    			// This creates a BoxLang task that runs every X seconds to check for expired objects
    			"reapFrequency": 120,
    			// If enabled, the last access timeout will be reset on every access
    			// This means that the last access timeout will be reset to the defaultLastAccessTimeout on every access
    			// Usually for session caches or to simulate a session
    			"resetTimeoutOnAccess": false,
    			// If enabled, the last access timeout will be used to evict objects from the cache
    			"useLastAccessTimeouts": true
    		}
    	},
    	// This is the holder of all sessions in a BoxLang runtime.
    	// The keys are prefixed by application to create separation.
    	"bxSessions": {
    		"provider": "BoxCacheProvider",
    		"properties": {
    			// How many objects to evict when the cache is full
    			"evictCount": 1,
    			// The eviction policy to use: FIFO, LFU, LIFO, LRU, MFU, MRU, Random
    			"evictionPolicy": "LRU",
    			// The maximum number of objects the cache can hold
    			"maxObjects": 100000,
    			// How long should sessions last for in seconds. Default is 60 minutes.
    			"defaultTimeout": 3600,
    			// The object store to use to store the objects.
    			// The default is a ConcurrentStore which is a thread safe and fast storage.
    			// Available Stores are: BlackHoleStore, ConcurrentSoftReferenceStore, ConcurrentStore, FileSystemStore, Your own.
    			"objectStore": "ConcurrentStore",
    			// The free memory percentage threshold to start evicting objects
    			// Only use if memory is constricted and you need to relieve cache pressure
    			// Please note that this only makes sense depending on which object store you use.
    			"freeMemoryPercentageThreshold": 0,
    			// The frequency in seconds to check for expired objects and expire them using the policy
    			// This creates a BoxLang task that runs every X seconds to check for expired objects
    			// Default is every 2 minutes
    			"reapFrequency": 120,
    			// This makes a session extend it's life when accessed.  So if a users uses anything or puts anything
    			// In session, it will re-issue the timeout.
    			"resetTimeoutOnAccess": true,
    			// Sessions don't rely on the last access timeouts but on the default timeout only.
    			"useLastAccessTimeouts": false
    		}
    	},
    	// Stores all dynamic regular expressions used in the runtime
    	"bxRegex": {
    		"provider": "BoxCacheProvider",
    		"properties": {
    			"evictCount": 1,
    			"evictionPolicy": "LRU",
    			"freeMemoryPercentageThreshold": 0,
    			"maxObjects": 500,
    			// 30 minutes ifnot used
    			"defaultLastAccessTimeout": 1800,
    			// 60 minutes default
    			"defaultTimeout": 3600,
    			"objectStore": "ConcurrentSoftReferenceStore",
    			"reapFrequency": 120,
    			"resetTimeoutOnAccess": false,
    			"useLastAccessTimeouts": true
    		}
    	}
    },
    "myCache" : {
        "provider" : "BoxCacheProvider",
        "properties" : {}
    }
    "evictCount" : 1
    "evictionPolicy" : "Random"
    "freeMemoryPercentageThreshold" : 10
    "maxObjects" : 1000
    "defaultLastAccessTimeout" : 1800
    "defaultTimeout" : 3600
    "objectStore" : "FileSystemStore"
    "reapFrequency" : 240
    "resetTimeoutOnAccess" : true
    "useLastAccessTimeouts" : true
    BL-1375
    BL-1381
    BL-1382
    BL-1383
    BL-1387
    BL-1372
    BL-1374
    BL-1377
    BL-1378
    BL-1379
    BL-1384
    Verify Installation

    📋 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.

    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):

    Ubuntu/Debian:

    RHEL/CentOS/Fedora:

    Alpine Linux:

    📋 Table of Contents

    • Quick Start

    • Prerequisites

    • Installation Options

    • Command Options

    📦 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)

    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

    📖 Help Command

    Always make sure to run the --help command to get the latest and greatest command usage.

    🎯 Detailed Usage

    Single-Version Installer Commands

    Module Management

    🌐 Running Applications

    BoxLang Runtime

    BoxLang MiniServer

    🔧 Configuration

    Environment Variables

    🐛 Troubleshooting

    Common Issues

    BoxLang not found after installation:

    Java not found:

    Permission denied errors:

    Module installation fails:

    Getting Help

    📚 Resources

    Documentation

    • 📖 Official Documentation

    • 🚀 Getting Started Guide

    • 📋 Language Reference

    • 🔧 Module Development

    Community

    • 💬 Discord Community

    • 📧 Mailing List

    • 🐛 Issue Tracker

    • 💡 Feature Requests

    Examples

    • 🧑‍💻 Interactive Playground

    • 📁 Sample Applications

    • 🎓 Tutorials

    Testing

    Help test new features and releases:

    📄 License

    This project is licensed under the Apache License, Version 2.0.

    🆘 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


    Made with ♥️ in USA 🇺🇸, El Salvador 🇸🇻 and Spain 🇪🇸

    BQI
    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

    • 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

    • 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

    Examples

    Simple example using tag-based syntax to generate a physical file:

    Example using script syntax to create a variable containing the binary contents of the PDF, which is then written to a file

    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 Exit REPL with quit or exit

    You can now exit the BoxLang REPL by typing quit or exit.

    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 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.

    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

    Improvements

    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 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 Finalize FileUpload, FileUploadAll BIFs and File Component upload actions in Web Support

    The web runtimes now have file uploading capabiltiies finalized.

    Bugs

    BL-405 BigIntegers cause error: integer number too large

    BL-419 Not all unquoted tag attribute values are parsing

    BL-105
    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.

    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.

    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.

    CastAs operator

    BoxLang has a new castAs operator that you can use instead of the javaCast() bif.

    No transpilation changes are needed since this is a BL-only feature.

    Multiple catch types

    BoxLang supports

    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.

    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

    would turn into this BoxLang

    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.

    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.

    Import keyword

    CFML has the import tag, but there doesn’t seem to be any special script version of it, ours looks like this:

    Import Aliases

    You can also import classes from any resolver and attach an alias to remove any ambiguity.

    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.

    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

    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

    • 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

    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

    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:

    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:

    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:

    In BoxLang, this is renamed to fetchSize:

    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 , more specifically the ZonedDateTime class 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:

    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

    Quick Syntax Style Guide
    Description

    version

    semver

    latest

    The BoxLang version to install, if not passed we use the latest stable.

    modules

    string

    ---

    If added, a space-delimited list of modules to install upon installation of the binary for you.

    with-commandbox

    boolean

    false

    If true, it will install the latest CommandBox as well.

    commandbox_version

    string

    latest

    The CommandBox version to install. Only used if with-commandbox is true.

    commandbox_modules

    Version Options:

    • latest - Latest stable release

    • snapshot - Latest development build

    • 1.2.0 - Specific version number

    • 1.x - Latest in major version series

    🔳 Usage Examples

    Simple Setup

    📦 With BoxLang Modules

    🎯 Specific Version

    📦 With CommandBox

    🔧 CommandBox with Specific Version

    🛠️ CommandBox with Modules

    ⚙️ Full Configuration Example

    🔑 With ForgeBox API Key

    🎯 Specific Version with Modules

    📦 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

    Web Application Testing

    Module Development Workflow

    Multi-Platform Testing

    Enterprise CommandBox Deployment

    🔍 System Requirements

    The action automatically installs required dependencies:

    • Java Runtime: OpenJDK 21 (or equivalent JRE)

    • System packages: curl, unzip, and other utilities as needed

    • BoxLang Runtime: Complete BoxLang installation

    • CommandBox (optional): When with-commandbox: true

    Automatic Dependency Management: The action handles all system requirements automatically. No manual Java or system package installation needed!

    📦 Popular Module Combinations

    Web Development Stack

    API Development

    Data Processing Pipeline

    Enterprise Integration

    🐛 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:

    BoxLang Dynamic JVM Language

    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:

    AI Streaming with Async Execution:

    Cross-Origin Streaming:

    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

    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

    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

    🗄️ 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:

    Advanced Configuration with Eviction:

    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

    Supported Databases:

    • Oracle

    • MySQL / MariaDB

    • PostgreSQL

    • Microsoft SQL Server

    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

    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.

    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"

    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

    🔧 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)

    Module System Enhancements

    • Added missing properties to getModuleInfo() struct snapshot

    • Fixed module publicMapping registration

    • Improved IService lifecycle by ensuring onConfigurationLoad() is called correctly

    HTTP Component Improvements

    • Added client certificate functionality support:

    • 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()

    🥊 Developer Experience

    Dynamic Object Creation

    Enhanced createDynamicProxy() and createObject() to accept custom class loaders:

    IStruct Convenience Method

    New getAsChar() method on IStruct for convenient character extraction:

    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

    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

    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():

    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

    HTTP Component - Support Client Cert Functionality

    allow hyphen in pre annotations to match post annotations

    Performance improvement of all scheduled task calls by introducing non concurrent maps for logging and closure suppliers

    Don't rewrite miniserver requests with rewrite file extension

    Apply placeholders to JSON as soon as it's read to ensure all keys are replaced

    Improve performance of running static initializer on class

    Added missing properties to getModuleInfo() struct snapshot

    Validate request URIs

    Optimize ASM generation by not relying on disk class files

    dump class improvements

    Component annotation for ignoring ignore outpout only setting

    Component annotation for auto-evaluating interpolated expressions

    Rename all dump() member methods to be .bxDump() to avoid conflicts with actual methods named dump()

    Catch Java access errors when getting Fields dynamically in class dump

    Allow createDynamicProxy(), createObject() to accept a class loader

    Ignore valid template extension setting of * when searching for Application descriptors

    can't dump java.sql.Time

    Performance tuning on cache stores

    New Features

    Implement bytecode compat version

    New getAsChar() on IStruct for convenience

    New JDBCStore for the Box Cache

    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

    New SSE() BIF and Emitter for Web Runtimes to allow for server side event streaming. Especially great when building AI Agents

    New BoxAST() bif to help you return the AST of source or a filepath

    Bugs

    specifying `username` and `password` throws 'unable to open connection' in cfquery - mssql

    CFStoredProc does not return multiple result sets when using a statement like an insert as first query

    Servlet resolution of relative paths can return incorrect mapping

    Prevent Double Encoding of Query Params passed by HTTParam

    loose struct converter can error on getting public fields

    Don't catch abort exceptions

    appending null to list fails

    listDeleteAt() is not working correctly on cfml compat mode or not

    Stored Procedure errors out on missing parameter

    FileCopy bif using overwrite is not using it.

    mapping paths with ../ not always normalized

    recursive class references cause stack overflow on JSON serialization

    Compat: HTTP getAsBinary=no not always honored in other engines

    Duplicate Fails When Encountering Optional

    HTTP Component Returns Raw Optional for Result response When No Timeout is Specified

    Module publicMapping is not being registered

    dateConvert is throwing an error

    bx:mail not handling string useSSL or useTLS attributes

    CFDUMP and WRITEDUMP do not dump to a file

    Instances of IService in BL Modules never call onConfigurationLoad

    CF transpiler doesn't catch dynamic sql type on proc param

    BOXLANG_DEBUG env var not used in servlet

    Class dump doesn't output this scope values, just keys twice

    subsequent requests do not respect in-progress onApplicationStart()

    I am getting an error after server forget and server start

    Better error for Import Statements in Class bodies

    Web Compat: Empty `allow` argument to FileUpload is treated as "All" by other Engines

    MiniServer Exchange GetRequestBody Method Throws Error when RequestBody Is Empty

    GetFileInfo Returns Incorrect `type` string for Directory

    File Uploads smaller than 10KB not being stored on disk

    expandPath() uses wrong base path when application.xx is in different dir

    stored proc param not casting timestamp

    Regression Windows Boxlang REPL

    FileUpload - When Temp directory is passed in explicitly in absolute destination path, directories should be created

    FileUpload - Ensure correct handling for template relative destination paths

    jsessionid cookie value set to null - breaks AWS WAF

    Mapping CGI scope returns null values

    Add handling for string dates as a common mask

    Maven Integration

    Maven Integration allows BoxLang to seamlessly incorporate Java dependencies into your runtime, expanding your application's capabilities with the vast Java ecosystem.

    BoxLang offers seamless integration with Maven, the widely used Java build and dependency management tool. This integration enables you to easily integrate third-party Java libraries into your BoxLang runtime, providing access to the vast Java ecosystem without requiring complex setup procedures.

    Overview

    The Maven integration in BoxLang works through a simple but powerful mechanism:

    • Centralized Dependency Management: Use Maven's pom.xml to declare all your Java dependencies

    • Automatic Download: Maven handles downloading and resolving dependency conflicts

    • Runtime Integration: BoxLang automatically loads all JARs from the lib/ folder

    • Simple Workflow: Add dependencies, run mvn install, and start using Java libraries immediately

    📋 Table of Contents

    Installing Maven

    Before you can use Maven integration, you need to have Maven installed on your system.

    Option 1: Using Chocolatey (Recommended)

    Option 2: Using Scoop

    Option 3: Manual Installation

    1. Download Maven from

    2. Extract to C:\Program Files\Apache\maven

    Verify Installation

    After installation, verify that Maven is working:

    You should see output showing the Maven version, Java version, and OS information.

    Getting Started

    The BoxLang home by default is located in your user's home directory: ~/.boxlang from here is where you will be making maven installation commands. Fire up a terminal and navigate to your BoxLang HOME.

    The BoxLang POM File

    BoxLang Home includes a pre-configured pom.xml file specifically designed for runtime dependency management:

    Basic Workflow

    1. Edit the POM: Add your desired dependencies to the <dependencies> section

    2. Install Dependencies: Run mvn install in the BoxLang Home directory

    3. Use Libraries: Start using the Java libraries in your BoxLang code immediately

    Adding Dependencies

    Finding Dependencies

    Use to find the dependencies you need. Simply search for the library and copy the Maven coordinates.

    Adding a Dependency

    Edit the pom.xml file and add your dependency inside the <dependencies> section:

    Installing Dependencies

    Navigate to your BoxLang Home directory and run:

    This command will:

    • Download all declared dependencies and their transitive dependencies

    • Place all JARs in the lib/ folder

    • Make them available to the BoxLang runtime

    Cleaning Dependencies

    To remove all downloaded dependencies:

    This will clear the lib/ folder of all Maven-managed JARs.

    Practical Examples

    Text Processing with Apache Commons

    Add powerful text processing capabilities to your BoxLang applications:

    QR Code Generation

    Add QR code generation capabilities to your BoxLang applications:

    Encryption and Security

    Add cryptographic capabilities with Bouncy Castle:

    Advanced Usage Patterns

    Multi-Module Dependencies

    For large applications, organize dependencies by functionality:

    Version Management

    Use properties for easier version management:

    Excluding Transitive Dependencies

    Sometimes you need to exclude specific transitive dependencies:

    Best Practices

    1. Keep Dependencies Updated

    Regularly check for newer versions of your dependencies:

    2. Use Specific Versions

    Always specify exact versions rather than ranges:

    3. Document Your Dependencies

    Add comments explaining why each dependency is needed:

    4. Test After Adding Dependencies

    Always test your BoxLang application after adding new dependencies:

    5. Monitor Dependency Size

    Keep an eye on the total size of your lib/ folder:

    Troubleshooting

    Dependency Conflicts

    If you encounter dependency conflicts, use Maven's dependency tree to investigate:

    Class Loading Issues

    If classes aren't found after installation:

    1. Verify the JAR is in the lib/ folder

    2. Restart the BoxLang runtime

    3. Check for package name typos in your BoxLang code

    If you continue to experience class loading issues, we recommend building BoxLang modules for complete isolation.

    Version Compatibility

    Some dependencies may require specific versions of Java. Check compatibility before adding:

    Conclusion

    Maven integration makes BoxLang incredibly powerful by providing access to the entire Java ecosystem. Whether you need advanced text processing, HTTP clients, database drivers, encryption libraries, or specialized tools, Maven integration makes it simple to add and manage these dependencies.

    Key benefits:

    • 🚀 Easy Setup: Simple mvn install command to add dependencies

    • 🔧 Automatic Management: Maven handles dependency resolution and conflicts

    • 📚 Vast Ecosystem: Access to thousands of Java libraries

    • 🔄 Version Control

    With Maven integration, BoxLang applications can leverage decades of Java library development, making it possible to build enterprise-grade applications with minimal setup complexity.

    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

    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!

    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

    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

    • Maven pom.xml for the BoxLang Home so you can integrate with any Java library

    • implement nested grouped output/looping

    • Logger appenders in the boxlang.json can now chose their own encoder: text or json

    • Added ability for loggers to chose between file and console appenders

    Improvements

    • Add executionTime to result object of bx:http

    • FileCopy( source, targetDirectory ) when using a target directory doesn't work on BoxLang but works on Lucee

    • File bifs have too many casts, do one cast for performance

    • Add a unique request id metadata header when making requests in http so it can track easily

    Bugs

    • postBIFInvocation event

    • Simple preFunctionInvoke interceptor throws errors due to recursing into itself

    • Module that defines an interceptor has to specify "too much" for the class path

    • ModuleService reload and reloadAll() methods to provide ability for module reloading on development

    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 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 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 object, which allows you to navigate in, get keys, cast them, do defaults, and so much more.

    Check out our data docs for further information.

    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.

    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.

    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.

    Please see our docs on for further information.

    Allows Java methods to be referenced and passed around as a variable and invoked later like UDFs

    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.

    BL also allows you to grab a reference to a static method from a Box class as well using the :: notation.

    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.

    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

    And finally, here we use a Java method to pass directly in place of a UDF or Closure to a higher order function.

    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.

    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

    new interception points when a session get's created and destroyed

    We have introduced two new global interception points that modules can listen to:

    Event
    Data
    Description

    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.

    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.

    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:

    Which brings about the next ticket:

    Sessions are now monitored by cache interceptors to detect removals so as to shutdown the sessions before removal

    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:

    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

    Combine config settings into a single struct

    Allow optional attribute delimiters in ACF tag-in-script syntax

    Refactor dump loading of CSS to use caching again

    Refactor page pool to be per-mapping

    jsessionID is the internal standard for boxlang sessions, move to this instead of cfid

    getOrSet() in the cache should return the object not an optional

    Bugs Squashed

    BL Compat module should coerce null values to empty string

    MSSQL DROP TABLE throws 'The statement must be executed before any results can be obtained'

    Adobe Compatibility: Missing support for new java() and new component()

    cfinvoke does not support params as attribute-value pairs

    If the global runtime `javaLibraryPaths` is already a jar/class location, then use it, else it breaks

    allow "var" before CF catch variable in script

    ResetSession on the scripting request context was invalidating the new session instead of the old session

    Session creation if the default timeout is not a duration, it should treat it as seconds, not milliseconds

    Session object was not serializable

    Cache was evicting items without reaping

    DateTime toString() not accounting for formatter being null

    sessionRotate() not copying over old keys due to nullification of keys when invalidating the old session

    Docker

    Containerize all things with BoxLang - Professional Docker images for development and production

    Professional BoxLang Docker images for modern containerized deployments

    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: - Full BoxLang CLI runtime

    • MiniServer Images: - Lightweight web server

    • 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

    CLI Usage Examples

    🌐 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

    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

    MiniServer Usage Examples

    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:

    📦 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

    Available Modules

    Common modules you can install:

    • bx-compat-cfml - ColdFusion/CFML compatibility layer

    • bx-mysql - MySQL database connectivity

    • bx-esapi - Enterprise Security API

    ⚙️ 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:

    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}/

    Web Server Features

    • REWRITES - Enable URL rewrites (default: true)

    • REWRITE_FILE - Rewrite configuration file (default: index.bxm)

    BoxLang Environment Override

    BoxLang supports overriding any configuration setting via environment variables using the BOXLANG_ prefix. For complete documentation, see .

    Examples:

    • BOXLANG_DEBUGMODE=true

    🚀 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.

    Experimental Feature: The Nginx integration is currently experimental and not recommended for critical production workloads. Use with caution and thorough testing.

    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 Certificates

    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:

    This repository contains:

    • Dockerfiles for all image variants

    • Build scripts and automation

    • Nginx configurations for production deployments

    • Testing infrastructure and examples

    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

    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

    Professional Support: For enterprise Docker deployments, BoxLang+ and BoxLang++ subscribers receive priority support, custom image builds, and deployment assistance. Visit for more information.

    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 🚀🔥

    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

    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. 🚀

    Premium Modules Have Landed

    We have now our first premium module for BoxLang +/++ subscribers: BX-REDIS. Our bx-redismodule 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:

    Giving you great capabilities for caching, distributed sessions, pub-subscribe and much more. You can find out about this initial release here ()

    Licenses Available!

    Remember that our support license subscriptions () for BoxLang +/++ are available now. Offering enterprise-grade support, priority fixes, premium modules, and exclusive benefits. As an introductory offer, all licenses are available at 25% 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 , your applications will fly and be highly performant.


    Release Notes

    Improvements

    Explore speed improvements to parser

    Support CF syntax of space inside elvis operator

    allow getSystemSetting() to default to a non-simple value

    bx-compat - Client Scope Listener should not start up or look for cache if client management is disabled

    Make miniserver bind to 0.0.0.0 by default

    Change order of app shutdown

    boxAnnounce() and boxAnnounceAsync() get a poolname so you can announce globally or to the request pools

    missing bif: BoxRegisterInterceptionPoints() to register interception points for global or request pools

    In BL files, only default output=false in tag-based UDFs

    Setup the hikari defaults for connection pooling to modern standards

    Update query object to return array of structs into a consolidated method: toArrayOfStructs()

    Attempts needed remail of left over isSimplevalue evaluations

    Rename bx:module to be bx:component

    Bugs

    esapiEncode does not allow an zero length input string

    BX-ORM: Datasource with name [defaultDatasource] not found in the application or globally

    `try`/`finally` doesn't always run `finally`

    ASM regression - break exiting out of more than just the loop

    LinkedHashMap right-hand assignments are always null.

    ReEscape result doesn't match ACF

    Classes getting cleared in debug mode

    Simplify CLI to install modules

    cgi items not being found until you access them

    encrypt not working with AES and UU

    Encrypt Fails when salt is below 16 bytes in length

    bx-mail not reading mail configurations

    HTTP - Ensure all exceptions are caught and handled

    Mail Module not Loading root-level boxlang.json Mail Server Settings

    StructUtil.deepMerge wraps arrays in nested array if left hand side contains the same array

    Can't set cookies using a struct

    Mail: Classloader issues when sending MultiPart email in Servlet Context

    `.duplicate()` Member Method Not Available on Struct,DateTime objects, Queries and Arrays

    DirectoryCopy Does not Allow Closure for Filter Arg

    QueryNew Does not accept array of Columns as only first arg

    Compat: CachePut does not allow numeric decimal number of days for timeSpan or idleTime

    String Hash Result Different Between Text and Byte Array

    Compat: HTTP result.statusCode Does not Include the status text.

    HTTP Request for Binary Object casts fileContent to String

    Integer caster not always consistent

    HTTP Component getAsBinary attribute does not support `true` and `false` boolean arguments

    HTTP Component throws an error when `Host` is explicitly passed as a header

    HTTP Component Throws Error when sending Binary Content

    HTTP getAsBinary should be treated as an explicit request for binary content unless `never` is passed.

    HTTP: Query Params Are Being Double Encoded Even When Encode=false

    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.

    When a form is submitted but none of the inputs have names and the form scope is dumped, an error is thrown

    Type coercion of an numeric argument passed to java constructor is not being done

    Function NOT not found

    bx-orm - 'Datasource with name [defaultDatasource] not found ...'

    bx-orm - Unable to call generated methods from within class

    bx-orm - Generated method hasX() is missing support for value comparison

    bx-orm - AddX() method fails on many-to-many relationship properties with "bag is null" error

    HMAC Method not supporting binary keys

    HTTP `file` attribute not implemented

    Math Operations Leave trailing zeros after operation when result is whole number

    HTTP ACF and Lucee Treat all Unknown or malformed `Content-Type` Headers as a string response

    Compat: Default throw error not a type of `Application`

    Error compiling - 'in' was unexpected expecting one of ...

    this.customtagpaths not respected - Could not find custom tag

    Common Text Cert/Key extensions are being read as Binary data

    for loop using var and in throws parsing error

    Custom Error Thrown Is Being Wrapped in "Error invoking Supplier" exception

    FileRead should only ever return strings

    DateTime Comparison equals/isEqual discrepancies

    DateCompare Issues when Time units are specified

    DateAdd No Longer Allowing Decimals

    Allow customTagPaths to be relative

    EqualsEquals operator should use `equalTo` method of DateTime in compat mode

    Cannot pass BoxLang Functions into ScheduledTask

    Nested config values for modules do not get replaced by environment variables

    thread safety issue in feature audit

    Custom setter that assigns to this scope causes stack overflow with implicit accessor invocation

    return type of function not always parsing

    Invalid stack height when using a ternary in a context that doesn't expect a return value

    semicolon not allowed after pre annotation

    `variablename` is not supported as a type

    Compat: Date Comparisons in Compat should only be precise to the second

    len() BIF needs to treat byte arrays as an array, not a string

    return not expr parsing error

    Tasks

    CBSecurity Certification

    isWDDX BIF missing from wddx module

    Directives

    These are the global configuration settings for the runtime

    Below, you can find all the configuration directives the language supports.

    These directives will be placed in the boxlang.jsonfile at the root level:

    Application Timeout

    The default timeout for applications in BoxLang. The default is 0 = never expires. The value must be a string timespan using the syntax shown:

    Class Generation Directory

    This is the location where BoxLang will store compiled classes.

    Class Paths

    BoxLang allows you to register global locations where we can discover BoxLang classes (.bx files). These must be absolute paths or use variable substitutions.

    Class Resolver Cache

    This enables the class locations cache for the runtime, used when resolving class paths, mappings, and per-request mappings. This is recommended for production environments.

    Compiler

    The compiler to use for BoxLang files. BoxLang supports multiple compilation strategies:

    • asm (default) - Uses ASM bytecode generation for optimal performance and modern JVM features

    • java - Generates Java source code first, then compiles to bytecode (legacy approach)

    Recommendation: Use the default asm compiler for production. It provides better performance and supports modern JVM features. The java compiler is primarily maintained for backward compatibility and debugging purposes and requires the boxlang-compiler-java module.

    Clear Class Files On Startup

    This setting will remove all class files from the class generation directory on startup. Useful for debugging and testing, but not recommended for production.

    Custom Components Directory

    BoxLang allows you to register global locations where we can register custom components for use in your templates:

    Default Datasource

    The name of the default datasource to use for database operations when no datasource is explicitly specified.

    Max Tracked Completed Threads

    The maximum number of completed threads to track for a single request. This prevents memory issues by flushing old completed threads.

    Store Class Files On Disk

    Controls whether compiled class files are stored on disk for reuse between restarts. When enabled, compiled classes persist across runtime restarts, improving startup performance. When disabled, class files are stored in memory only and lost on restart.

    Performance Impact: Enabling this setting significantly improves runtime restart performance since classes don't need to be recompiled. Disable only for debugging or when disk space is extremely limited.

    Trusted Cache

    This enables the runnable loader's cache on disk for compiled BoxLang classes. When enabled, BoxLang will load a class and never inspect the file again. Enable for production, disable for development.

    Version

    The version of the BoxLang runtime (automatically populated during build).

    Whitespace Compression

    Enable whitespace compression in output. Currently only used by web runtimes.

    Debug Mode

    This is a powerful setting. It puts the runtime into debug mode, where more verbose debugging will be activated, and when exceptions occur, more information will be shown by default. The default is false an we highly discourage its use in production.

    Default Datasource

    The name of the default datasource to use for database operations when no datasource is explicitly specified.

    You can set this to the name of any datasource defined in the datasources configuration section. See the section for more details.

    Default Remote Method Return Format

    The default return format for class invocations via web runtimes.

    Invoke Implicit Accessors

    In BoxLang, implicit accessors default to true for BoxScript (.bx) files and false for CFML (.cfc) files. This means that properties on a class can be accessed externally, like field properties for mutation or access. You can override this default behavior by setting this configuration option.

    This setting is not present in the default boxlang.json as BoxLang uses intelligent defaults based on the source file type. Add this setting only if you want to override the default behavior.

    Simple example:

    Java Library Paths

    BoxLang allows you to register an array of locations or array of jars or classes that the runtime will class load into the runtime class loader. This allows you to class-load Java applications at runtime.

    By default, we look into the lib folder in your BoxLang home.

    Locale

    This is the default locale for the runtime. By default, we use the JVM locale. This value must be an IETF BCP language tag:

    Mappings

    Here is where you can create global class mappings in BoxLang. Mappings are used to discover BoxLang classes, files, and more. You can prefix the name of the mapping with / or not. Ultimately, BoxLang will add leading and trailing slashes for you (e.g., core becomes /core/).

    New in 1.6.0: Mappings now support both simple and complex formats for greater flexibility and control.

    Simple Mappings

    The simple format is a string value representing the absolute path location. These mappings default to external: true, meaning they are externally accessible.

    Complex Mappings

    The complex format is a JSON object with the following properties:

    Property
    Type
    Required
    Default
    Description

    External vs Internal Mappings

    The external flag controls whether a mapping is accessible from external requests (web requests):

    • external: true (default) - The mapping can be accessed by web requests and resolved in templates

    • external: false - The mapping is only accessible internally to the runtime and not exposed to web requests

    Security Best Practice: Use external: false for mappings that contain sensitive code, configuration, or internal utilities that should not be accessible via web requests.

    Complete Example

    Modules Directory

    BoxLang will search your home for a modules folder and register the modules found. However, you can add multiple locations to search for BoxLang modules. Each entry must be an absolute location.

    Request Timeout

    The default timeout for requests in BoxLang. The default is 0 = never expire. The value must be a string timespan using the syntax shown:

    Session Timeout

    The default timeout for sessions in BoxLang. The default is 30 minutes. The value must be a string timespan using the syntax shown:

    Session Storage

    In BoxLang, you can configure your user sessions to be stored in memory by default in a BoxLang sessions cache, or you can give it a custom cache name to store them in. If it's not memory` then it must be a valid registered cache. (See )

    Timezone

    This is the global timezone to use in the runtime. By default, it will use the JVM timezone. This value requires IANA timezone database values:

    Use High Precision Math

    By default BoxLang uses high-precision mathematics via BigDecimal operations. It analyses your operations and determines the precision accordingly. You can turn this off here for all applications and use Double based operations. If you disable this feature, then if you want high precision you will have to use the precisionEvaluate( expression ) .

    Valid Class Extensions

    This is an array of all the extensions that will be processed as BoxLang classes. By default we target bx, cfc.

    Valid Template Extensions

    This is an array of all the extensions that will be processed as BoxLang templates. Meaning you can execute them and include them. The core template extensions are bxm, bxs, bxml, cfml, cfm, cfs and are always available. Here you can add other extensions that will process as templates.

    https://github.com/ortus-boxlang/BoxLang/blob/development/src/main/resources/config/boxlang.json
    Introduction | BoxLang IDEboxlang-ide.ortusbooks.com

    BoxLang Monaco Editor

    The Monaco Editor is the code editor that powers VS Code. The BoxLang Monaco Editor package will allow you to leverage your own custom BoxLang editors powered by Monaco.

    Monaco Editor language support for BoxLang - providing syntax highlighting, IntelliSense, and custom themes for BoxLang development.

    Screenshots

    1.0.0-Beta2

    June 21, 2024

    BoxLang Betas are released weekly. This is our second beta marker. Here are the release notes.

    Bug

    Writedump expanded collapsed support

    Writedump top support

    Here are the available providers for BoxLang. The table shows the status of completion for each provider and its availability for the open-source version of BoxLang, as well as for +/++ subscribers.

    Provider
    Description
    Status
    OS
    +/++
    /bin/bash -c "$(curl -fsSL https://install.boxlang.io)"
    
    # With automatic Java 21  installation
    curl -fsSL https://install.boxlang.io | bash -s -- --with-jre
    # Single version (simple)
    powershell -NoExit -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://install-windows.boxlang.io'))"
    # Check BoxLang version
    boxlang --version
    
    # Start BoxLang REPL
    boxlang
    
    # Start MiniServer
    boxlang-miniserver --port 8080
    apk add --no-cache bash curl
    brew install curl unzip jq openjdk@21
    sudo apt update && sudo apt install curl unzip jq default-jdk
    sudo dnf install curl unzip jq java-21-openjdk
    # Prerequisites automatically installed by installer
    apk add --no-cache bash curl unzip jq openjdk21
    # Java 21 automatically installed with --with-jre option
    ~/.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)
    📦 BoxLang® Quick Installer [email protected]@
    
    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
    # 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
    # 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 [email protected]
    
    # Get help
    install-bx-module --help
    # 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
    # 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
    # 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"
    # Restart terminal or reload profile
    source ~/.bashrc  # or ~/.zshrc
    
    # Check PATH
    echo $PATH | grep boxlang
    # ✨ 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/
    # Fix permissions for user installation
    chmod +x ~/.boxlang/bin/*
    
    # Or use system installation
    sudo install-boxlang --system
    # 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
    # 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
    # Install snapshot for testing
    bvm install snapshot
    bvm use snapshot
    
    # Report any issues found
    <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>
    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 );
    > quit
    
    > exit
    "experimental" : {
        "flag1" : true|false
    }
    boxlang compile <options>
    boxlang cftranspile <options>
    boxlang featureAudit <options>
        "scripts":{
            "onServerInitialInstall":"install bx-compat-cfml"
        }
    class{
    
        property name=¨firstName¨
    
    }
    <bx:if expression>
    
    <bx:else>
    
    </bx:if>
    expression castAs type
    catch( foo.com | brad | com.luis.majano e ) {}
    @foo
    @bar( value )
    @output( true )
    function myFunc() {
    }
    /**
    * My function hint
    *
    * @output false
    * @brad wood
    * @name Luis
    *
    * @myService my hint here for the arg
    * @myService.inject
    */
    function foo( required any myService ) {}
    /**
    * 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 ) {}
    @displayName( “user” )
    class{
    
        Property name=“fullName”;
        
    }
    
    // Accessors are on by default
    user = new User()
    user.setFullName( “Luis” )
    println( user.getFullName() )
    @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 taglib="/relative/path/customTags" prefix="tags";
    import package.Class as alias
    import java:org.apache.User as jUser;
    import models.User;
    
    var oUser = new jUser()
    var testUser = new User()
    // 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
    class implements="java:java.util.List" {
    
    }
    
    class extends="java:ortus.boxlang.runtime.types.Struct"{
    
    }
    createObject( ”class”, path )
    queryExecute(
      "select quantity, item from cupboard where item_id = :itemID"
      { itemID : { value : arguments.itemID, cfsqltype : "cf_sql_numeric" } }
    );
    queryExecute(
      "select quantity, item from cupboard where item_id = :itemID"
      { itemID : { value : arguments.itemID, sqltype : "numeric" } }
    );
    queryExecute( "Select * FROM myBigTable", {}, { blockfactor : 100 } );
    queryExecute( "Select * FROM myBigTable", {}, { fetchSize : 100 } );
    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" );
    - name: Setup BoxLang
      uses: ortus-boxlang/[email protected]
    - name: Setup BoxLang
      uses: ortus-boxlang/[email protected]
      with:
        modules: bx-ai bx-orm bx-pdf
    - name: Setup BoxLang with specific version
      uses: ortus-boxlang/[email protected]
      with:
        version: snapshot
    - name: Setup BoxLang with CommandBox
      uses: ortus-boxlang/[email protected]
      with:
        with-commandbox: true
    - name: Setup BoxLang with specific CommandBox version
      uses: ortus-boxlang/[email protected]
      with:
        with-commandbox: true
        commandbox_version: 6.0.0
    - name: Setup BoxLang with CommandBox and modules
      uses: ortus-boxlang/[email protected]
      with:
        with-commandbox: true
        commandbox_modules: commandbox-cfconfig,commandbox-dotenv
    - name: Setup BoxLang with CommandBox (full setup)
      uses: ortus-boxlang/[email protected]
      with:
        with-commandbox: true
        commandbox_version: 6.0.0
        commandbox_modules: commandbox-cfconfig,commandbox-dotenv,commandbox-fusionreactor
    - name: Setup BoxLang with CommandBox and ForgeBox API Key
      uses: ortus-boxlang/[email protected]
      with:
        with-commandbox: true
        forgeboxAPIKey: ${{ secrets.FORGEBOX_API_KEY }}
    - name: Setup BoxLang with specific version
      uses: ortus-boxlang/[email protected]
      with:
        version: 1.2.0
        modules: bx-compat-cfml bx-mail
    name: BoxLang CI/CD
    
    on: [push, pull_request]
    
    jobs:
      test:
        runs-on: ubuntu-latest
    
        steps:
        - name: Checkout code
          uses: actions/checkout@v4
    
        - name: Set up BoxLang
          uses: ortus-boxlang/[email protected]
          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
    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@v4
    
        - name: Setup BoxLang ${{ matrix.boxlang-version }}
          uses: ortus-boxlang/[email protected]
          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
    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@v4
    
        - name: Setup BoxLang with Development Dependencies
          uses: ortus-boxlang/[email protected]
          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/
    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/[email protected]
          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
    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/[email protected]
          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
    modules: "bx-compat-cfml bx-orm bx-mysql bx-redis bx-mail bx-esapi"
    modules: "bx-mysql bx-redis bx-mail bx-compat-cfml"
    modules: "bx-mysql bx-derby bx-excel bx-pdf bx-mail"
    modules: "bx-compat-cfml bx-orm bx-mysql bx-redis bx-elasticsearch bx-mail bx-esapi"
    - name: Setup BoxLang with Debug
      uses: ortus-boxlang/[email protected]
      with:
        version: latest
        modules: "bx-compat-cfml"
      env:
        ACTIONS_RUNNER_DEBUG: true
    boxlang.json
    {
        "directive": value
    }
    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

  • pagebreak
    |
    header
    |
    footer
  • evalAtPrint This attribute is deprecated as all content is evaluated when the body of the tag is processed

  • - 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.

  • string

    ---

    If added, a comma-delimited list of CommandBox packages to install. Only used if with-commandbox is true.

    forgeboxAPIKey

    string

    ---

    If added, it will configure the ForgeBox API Key in CommandBox. Only used if with-commandbox is true.

    --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)

    What Gets Installed
    Help Command
    Detailed Usage
    Running Applications
    Configuration
    Troubleshooting
    Resources
    License
    Support
    Logo
    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)

  • isClosed() - Check if client disconnected

    Proxy/nginx buffering disabled for real-time delivery

    Plus all standard BoxCache properties (maxObjects, evictionPolicy, evictCount, etc.)
    Apache Derby
  • HSQLDB

  • SQLite

  • Eviction Support: Full support for LRU, LFU, and other eviction policies

  • Metadata Tracking: Stores hits, timeouts, and access timestamps

  • sourceType - Syntax type: "script" (default), "template", "cfscript", or "cftemplate"

    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

  • Better handling of recursive class references in JSON serialization

    Better validation of template URIs

    for concurrent requests
    Improved dynamic SQL type handling in CF transpiler

    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

  • BL-1808
    BL-1818
    BL-1825
    BL-1830
    BL-1836
    BL-1838
    BL-1839
    BL-1846
    BL-1848
    BL-1849
    BL-1853
    BL-1855
    BL-1863
    BL-1864
    BL-1865
    BL-1866
    BL-1867
    BL-1877
    BL-1791
    BL-1861
    BL-1875
    BL-1876
    BL-1880
    BL-1883
    BL-1376
    BL-1685
    BL-1809
    BL-1810
    BL-1811
    BL-1812
    BL-1814
    BL-1815
    BL-1816
    BL-1817
    BL-1820
    BL-1821
    BL-1822
    BL-1823
    BL-1824
    BL-1829
    BL-1831
    BL-1833
    BL-1834
    BL-1837
    BL-1840
    BL-1841
    BL-1842
    BL-1845
    BL-1847
    BL-1851
    BL-1854
    BL-1856
    BL-1857
    BL-1858
    BL-1860
    BL-1870
    BL-1871
    BL-1872
    BL-1873
    BL-1874
    BL-1878
    BL-1879
    Common Use Cases
  • Troubleshooting

  • Best Practices

  • Add C:\Program Files\Apache\maven\bin to your PATH environment variable

    Option 1: Using Homebrew (Recommended)

    Option 2: Using MacPorts

    Option 3: Using sdkman

    Ubuntu/Debian:

    CentOS/RHEL/Fedora:

    Arch Linux:

    SDKMan:

    : Easy dependency updates and rollbacks
  • 🧹 Clean Management: Simple cleanup with mvn clean

  • Overview
    Installing Maven
    Setting Up Maven Integration
    Working with Dependencies
    maven.apache.org
    Maven Central
    : Improved struct operations, hash encoding, and object creation patterns

    BL-1482 new event ON_FUNCTION_EXCEPTION

  • 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.

  • BL-1405 Add missing contexts to data interceptors

  • BL-1406 Add a `request` struct to the bxhttp result object

  • BL-1417 Add Allow Arguments to FileCopy and FileMove for granular extension security overrides

  • BL-1419 server.java.defaultLocale, server.java.availableLocales

  • BL-1420 New bif: BoxModuleReload( [name] ) to easily reload modules for testing purposes

  • BL-1421 optimize when LocalizationUtil string casts

  • BL-1422 optimize Struct.putAll()

  • BL-1423 optimize when basescope creates lockname to on demand

  • BL-1424 optimize string compare check for unicode

  • BL-1425 optimize case insensitive instanceof check

  • BL-1426 optimize isNumeric locale parsing and casting

  • BL-1427 optimize file detection/reading from disk unless needed

  • BL-1428 optimize getConfig() by caching at request context

  • BL-1429 Improve performance of string lowercasing and key creation

  • BL-1433 Only include source lines in exceptions when in debug mode

  • BL-1434 Optimize hash base 64 encoding

  • BL-1435 Optimize regex cache key generation

  • BL-1436 Move/Copy BIFs should all default to an overwrite value of true

  • BL-1437 Update the way loggers are setup and retrieved to avoid string and key lookups and accelerate the runtime

  • BL-1438 bif invocation interceptors missing the actual bif

  • BL-1439 BIF Interceptors hot code, only create events if they are states for it

  • BL-1443 order keys in struct dump alphabetically

  • BL-1445 DateTime and Duration Math Should Represent Fractional Days in Math Operations

  • BL-1446 Compat: DateAdd Should accept numeric fractional days as date argument

  • BL-1450 Exclude javaparser and other debug libraries from final jar

  • BL-1454 Optimize FQN class by removing regex usage in hot code

  • BL-1455 optimize generated setter by caching resolved file path

  • BL-1456 Optimize dynamic object by converting stream to loop in hot code

  • BL-1457 optimize output check by caching recursive lookups

  • BL-1458 optimize isEmpty code paths

  • BL-1459 optimize getting function enclosing class by caching

  • BL-1460 optimize number caster true/false string checks

  • BL-1461 optimize BoxStructSerializer class by avoiding struct.entrySet()

  • BL-1462 optimize string compare by removing unnecessary string to lower case

  • BL-1473 Update to use StatusPrinter2 from deprecated StatusPrinter using LogBack

  • BL-1481 Speed improvements for function invocation on hot code

  • BL-1486 Better handle low level parsing errors like java.util.EmptyStackException

  • BL-1489 Improve error messages when registering interceptors using the registration bifs when sending things other than interceptors

  • BL-1490 Add function name to interceptor data for ease of use

  • BL-1493 Accelerate dynamic object method handle executions

  • BL-1394 forgot to populate the `populateServerSystemScope` from the override boxlang.json

  • BL-1396 isValid Boolean Returning Incorrect Result on Struct

  • BL-1398 Move default disallowed file extensions to web support and keep CLI open

  • BL-1399 Compat: CreateTime Should Support 0 hour argument

  • BL-1401 FileSystemUtil not absoluting paths when checking existence

  • BL-1402 `replaceNoCase` does not handle `null` strings like Lucee or ACF

  • BL-1403 http not using the user agent if passed by the user

  • BL-1409 Compat: add `server.coldfusion.supportedLocales`

  • BL-1412 Add Application.bx/cfc support for overriding allowed and disallowed extensions

  • BL-1414 this.logger is null in when getting an attempt() from a box future

  • BL-1416 Compat: Support ACF/Lucee `blockedExtForFileUpload` Application Setting

  • BL-1418 parameterized QoQ with maxLength errors

  • BL-1431 function dump template doesn't work in compat

  • BL-1432 CF transpiler not turning off accessors for child classes

  • BL-1441 getPageContext().getRequest() has no getScheme()

  • BL-1442 empty file fields in forms throw error on submit

  • BL-1444 Boxlang does not pickup custom tags that are in the same folder as the file that calls them

  • BL-1447 Compat: DateDiff should support fractional days as date argument

  • BL-1449 when doing a boxlang {action} command it should break and execute

  • BL-1451 Custom tag search is case-sensitive

  • BL-1452 inline annotation errors when literal value is a negative number

  • BL-1463 parser errors on class annotation called abstract

  • BL-1466 self-closing defaultcase tag not parsing

  • BL-1467 if you use options or params that include file extensions, the runner explodes

  • BL-1468 cfqueryparam tag not allowed outside of cfquery tag

  • BL-1469 Building query fails when part of the query is build inside function that outputs directly

  • BL-1470 query escaping of single quotes only escapes the first one, not all

  • BL-1475 `this.sessionStorage` assignment with Application-defined cache throws error.

  • BL-1477 Errors within application startup leave app in unusable state

  • BL-1479 Compat: Error thrown in QueryCompat interception when null param is encountered

  • BL-1483 calling java method with invoke() and no args fails

  • BL-1484 filewrite operations on existing files were not truncating it and leaving content behind.

  • BL-1488 isSimpleValue doesn't work with Keys

  • BL-1453
    BL-1464
    BL-1474
    BL-1476
    BL-1393
    BL-1397
    BL-1400
    BL-1404
    BL-1356
    BL-1357
    BL-1385
    BL-1386
    Maven Home Integration

    onSessionCreated

    Session

    When a new session is created and registered

    onSessionDestroyed

    Session

    When a session is about to be destroyed

    CFConfig
    DataNavigator
    navigator
    BL-320
    BL-322
    BL-324
    Attempts
    BL-325
    BL-338
    BL-326
    BL-330
    BL-339
    BL-340
    BL-341
    BL-342
    BL-343
    BL-344
    BL-209
    BL-318
    BL-321
    BL-323
    BL-329
    BL-332
    BL-164
    BL-252
    BL-306
    BL-308
    BL-316
    BL-317
    BL-331
    BL-333
    BL-334
    BL-335
    BL-336
    BL-337
    ortussolutions/boxlang:cli-alpine-snapshot - Development snapshot on Alpine Linux

    ortussolutions/boxlang:miniserver-alpine-snapshot - Development snapshot on Alpine Linux

    Health checks: Built-in health monitoring for container orchestration
  • Hot reload: Development mode with automatic code reloading

  • http://127.0.0.1:8080/
    )
    bx-redis - Redis cache and session storage
  • bx-mail - Email functionality

  • bx-derby - Derby database (development)

  • /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)

  • )
  • 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)

  • BOXLANG_RUNTIME_CLASSGENERATION_ENABLED=false
  • BOXLANG_RUNTIME_CUSTOMTAGSPATHS=/custom/tags

  • Custom SSL: Mount your certificates to /etc/nginx/ssl/
  • Optimizations: Production-tuned Nginx configuration for BoxLang

  • Documentation and contribution guidelines

    Testing: Automated testing for all image variants

    ortussolutions/boxlang:cli
    ortussolutions/boxlang:miniserver
    ortussolutions/boxlang:miniserver-nginx
    Environment Variable Substitution
    https://github.com/ortus-boxlang/boxlang-docker
    boxlang.io/plans
    BoxLang Docker

    path

    string

    ✅ Yes

    -

    The absolute path location of the mapping

    external

    boolean

    No

    true

    Whether this mapping is externally accessible

    Datasources
    https://www.oracle.com/java/technologies/javase/jdk21-suported-locales.html
    Caches
    https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
    BIF instead
    // Simple synchronous streaming
    SSE( ( emitter ) => {
        emitter.send( "Hello from server!" );
        emitter.send( { status: "processing", progress: 25 }, "update" );
        emitter.close();
    } );
    // 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
    );
    // 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"
    );
    // Configure JDBC cache store in boxlang.json
    {
      "caches": {
        "distributedCache": {
          "provider": "BoxCache",
          "properties": {
            "objectStore": "JDBCStore",
            "datasource": "myDatasource",
            "table": "boxlang_cache",
            "autoCreate": true
          }
        }
      }
    }
    {
      "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
          }
        }
      }
    }
    // 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"
    );
    http url="https://secure-api.com" {
      httpparam type="certificate" file="client-cert.p12" password="secret";
    }
    // Use custom class loader for dynamic object creation
    customLoader = createObject( "java", "java.net.URLClassLoader" )
      .init( [ url ] );
    
    proxy = createDynamicProxy(
      listener,
      [ "com.example.Interface" ],
      customLoader
    );
    struct = { "code": "A" };
    charValue = struct.getAsChar( "code" ); // Returns Character 'A'
    // Old
    array.dump();
    
    // New
    array.bxDump();
    brew install maven
    sudo port install maven3
    sdk install maven {version}
    sudo apt update
    sudo apt install maven
    sudo yum install maven
    # or for newer versions
    sudo dnf install maven
    sudo pacman -S maven
    sdk install maven {version}
    choco install maven
    scoop install maven
    mvn -version
    
    cd $BOXLANG_HOME
    
    // or
    cd ~/.boxlang
    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>io.boxlang</groupId>
        <artifactId>runtime-library</artifactId>
        <version>@build.version@</version>
    
        <dependencies>
            <!-- Add your Java dependencies here -->
        </dependencies>
    
        <build>
            <directory>${project.basedir}/.tmp</directory>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>3.1.2</version>
                    <executions>
                        <execution>
                            <id>copy-dependencies</id>
                            <phase>install</phase>
                            <goals>
                                <goal>copy-dependencies</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>${project.basedir}/lib</outputDirectory>
                                <includeScope>runtime</includeScope>
                                <excludeScope>test</excludeScope>
                                <excludeScope>provided</excludeScope>
                                <overWriteReleases>true</overWriteReleases>
                                <overWriteSnapshots>true</overWriteSnapshots>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    <dependencies>
        <!-- Apache Commons Text for string manipulation -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>1.12.0</version>
        </dependency>
    
        <!-- QR Code generation -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.5.2</version>
        </dependency>
    
    </dependencies>
    mvn install
    mvn clean
    <!-- Add to pom.xml -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.12.0</version>
    </dependency>
    // Use in BoxLang after mvn install
    stringEscapeUtils = new org.apache.commons.text.StringEscapeUtils()
    wordUtils = new org.apache.commons.text.WordUtils()
    
    // Escape HTML
    safeHTML = stringEscapeUtils.escapeHtml4( "<script>alert('xss')</script>" )
    println( "Safe HTML: " & safeHTML )
    
    // Capitalize words
    title = wordUtils.capitalizeFully( "the quick brown fox" )
    println( "Title: " & title ) // "The Quick Brown Fox"
    
    // Text similarity
    similarity = new org.apache.commons.text.similarity.JaroWinklerSimilarity()
    score = similarity.apply( "BoxLang", "BoxScript" )
    println( "Similarity: " & score )
    <!-- Add to pom.xml -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.5.2</version>
    </dependency>
    // QR Code generator utility
    function createQRCodeGenerator() {
        return {
            "generate": ( text, size = 300 ) -> {
                var writer = new com.google.zxing.qrcode.QRCodeWriter()
                var bitMatrix = writer.encode(
                    text,
                    new com.google.zxing.BarcodeFormat().QR_CODE,
                    size,
                    size
                )
    
                return new com.google.zxing.client.j2se.MatrixToImageWriter()
                    .toBufferedImage( bitMatrix )
            },
    
            "saveToFile": ( text, filePath, size = 300 ) -> {
                var image = this.generate( text, size )
                var file = new java.io.File( filePath )
    
                new javax.imageio.ImageIO().write( image, "PNG", file )
                return filePath
            },
    
            "generateDataURL": ( text, size = 300 ) -> {
                var image = this.generate( text, size )
                var baos = new java.io.ByteArrayOutputStream()
    
                new javax.imageio.ImageIO().write( image, "PNG", baos )
                var bytes = baos.toByteArray()
                var encoder = new java.util.Base64().getEncoder()
    
                return "data:image/png;base64," & encoder.encodeToString( bytes )
            }
        }
    }
    
    // Usage
    qrGenerator = createQRCodeGenerator()
    
    // Generate QR code for a URL
    qrFile = qrGenerator.saveToFile(
        "https://boxlang.ortussolutions.com",
        "/tmp/boxlang-qr.png",
        400
    )
    println( "QR code saved to: " & qrFile )
    
    // Generate QR code as data URL for web use
    dataURL = qrGenerator.generateDataURL( "BoxLang is awesome!" )
    println( "Data URL: " & dataURL.left( 50 ) & "..." )
    <!-- Add Bouncy Castle for cryptography -->
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk18on</artifactId>
        <version>1.77</version>
    </dependency>
    // Encryption utility
    function createEncryptionUtil() {
        // Add Bouncy Castle as security provider
        var provider = new org.bouncycastle.jce.provider.BouncyCastleProvider()
        var security = new java.security.Security()
        security.addProvider( provider )
    
        return {
            "generateKeyPair": () -> {
                var keyGen = new java.security.KeyPairGenerator().getInstance( "RSA", "BC" )
                keyGen.initialize( 2048 )
                return keyGen.generateKeyPair()
            },
    
            "encrypt": ( data, publicKey ) -> {
                var cipher = new javax.crypto.Cipher().getInstance( "RSA/ECB/PKCS1Padding", "BC" )
                cipher.init( new javax.crypto.Cipher().ENCRYPT_MODE, publicKey )
                return cipher.doFinal( data.getBytes() )
            },
    
            "decrypt": ( encryptedData, privateKey ) -> {
                var cipher = new javax.crypto.Cipher().getInstance( "RSA/ECB/PKCS1Padding", "BC" )
                cipher.init( new javax.crypto.Cipher().DECRYPT_MODE, privateKey )
                var decrypted = cipher.doFinal( encryptedData )
                return new java.lang.String( decrypted )
            }
        }
    }
    
    // Usage
    encryption = createEncryptionUtil()
    keyPair = encryption.generateKeyPair()
    
    message = "Secret BoxLang message"
    encrypted = encryption.encrypt( message, keyPair.getPublic() )
    decrypted = encryption.decrypt( encrypted, keyPair.getPrivate() )
    
    println( "Original: " & message )
    println( "Decrypted: " & decrypted )
    <dependencies>
    
        <!-- QR Code Generation -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.5.2</version>
        </dependency>
    
        <!-- Cryptography -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk18on</artifactId>
            <version>1.77</version>
        </dependency>
    </dependencies>
    <properties>
        <zxing.version>3.5.2</zxing.version>
        <commons.version>1.12.0</commons.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>${zxing.version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>${commons.version}</version>
        </dependency>
    </dependencies>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext7-core</artifactId>
        <version>8.0.2</version>
        <type>pom</type>
        <exclusions>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    mvn versions:display-dependency-updates
    <!-- Good -->
    <version>2.16.0</version>
    
    <!-- Avoid -->
    <version>[2.0,3.0)</version>
    <dependencies>
        <!-- Apache Commons Text - Used for advanced string manipulation in templates -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>1.12.0</version>
        </dependency>
    
        <!-- ZXing - Required for QR code generation in reports -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.5.2</version>
        </dependency>
    
        <!-- Bouncy Castle - Cryptography for secure operations -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk18on</artifactId>
            <version>1.77</version>
        </dependency>
    </dependencies>
    // Test that dependencies loaded correctly
    function testDependencies() {
        try {
            // Test ZXing (QR Codes)
            var qrWriter = new com.google.zxing.qrcode.QRCodeWriter()
            println( "✅ ZXing QR Code library loaded successfully" )
    
            // Test Bouncy Castle
            var provider = new org.bouncycastle.jce.provider.BouncyCastleProvider()
            println( "✅ Bouncy Castle loaded successfully" )
    
            return true
        } catch ( any e ) {
            println( "❌ Dependency loading failed: " & e.message )
            return false
        }
    }
    
    testDependencies()
    # Check total size of dependencies
    du -sh lib/
    
    # List individual JAR sizes
    ls -lh lib/*.jar
    mvn dependency:tree
    # Check Java version
    java -version
    
    # Check Maven version
    mvn -version
    mvn install
    Configuration
        .navigate( "modules" )
        .ifPresent( "security", value -> this.name = Key.of( value ) );
    var renderInHtml = Configuration
        .navigate( "originalConfig", "modules", "pdf" )
        .getAsBoolean( "htmlREnder", false )
    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"
        } );
    }
    var userFound = attempt( userService.findBy( rc.id ) ).isNull()
    myInstance = new myClass();
    myInstanceMethod = myInstance.myMethod;
    myInstanceMethod();
    myStaticUDF = src.test.java.TestCases.phase3.StaticTest::sayHello;
    myStaticUDF();
    import java:java.lang.String;
    javaStaticMethod = java.lang.String::valueOf;
    result = javaStaticMethod( "test" ) // New string of "test"
    javaInstanceMethod = "my string".toUpperCase
    result = javaInstanceMethod() // "MY STRING"
    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 ]
    // 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"
    	// }
    },
    return getBoxCache()
        .get( "maybeExists" )
        .orElse( "not found" );
    // 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() );
    // 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",
    # 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
    # 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
    
    # 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
    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
    # 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
    // Use Timespan syntax: "days, hours, minutes, seconds"
    "applicationTimeout": "0,0,0,0",
    "classGenerationDirectory": "${boxlang-home}/classes"
    // A collection of directories to lookup box classes in (.bx files), they must be absolute paths
    "classPaths": [
    	"${boxlang-home}/global/classes"
    ]
    // This enables the class locations cache for the runtime.  It's used when resolving class paths
    // mostly using mappings, per request mappings, etc.
    // We recommend you always enable this setting, unless debugging a very specific issue
    "classResolverCache": true
    // The compiler to use for BoxLang files
    // Valid values are: "java", "asm"
    // This can be other things later on as we expand the compiler options
    "compiler": "asm"
    // This setting if enabled will remove all the class files from the class generation directory
    // This is useful for debugging and testing, but not recommended for production
    "clearClassFilesOnStartup": false
    // A collection of BoxLang custom components directories, they must be absolute paths
    "customComponentsDirectory": [
    	"${boxlang-home}/global/components"
    ]
    "defaultDatasource": ""
    // The maximum number of completed threads to track for a single request. Old threads will be flushed out to prevent memory from filling.
    // This only applies to the "thread" component bx:thread name="mythread" {} which tracks execution status and scopes for the remainder of the request that fired it.
    // ONLY threads which have been completed will be eligible to be flushed.
    // Note: when the limit is reached, the thread component and related BIFs will no longer throw exceptions on invalid thread names, they will silently ignore attempts to interrupt or join those threads
    "maxTrackedCompletedThreads": 1000
    // Store the compiled class files on disk for reuse between restarts
    // If disabled, the class files will be stored in memory only and lost on restart
    "storeClassFilesOnDisk": true
    // This enables the runnable loader's cache on disk for compiled BoxLang classes
    // This means that it will load a Boxlang class and never inspect the file again
    // Turn this on for production, but off for development so you can see your changes
    "trustedCache": false
    // The version of the runtime
    "version": "@build.version@"
    // Enable whitespace compression in output.  Only in use by the web runtimes currently.
    "whitespaceCompressionEnabled": true
    // This puts the entire runtime in debug mode
    // Which will produce lots of debug output and metrics
    // Also the debugging error template will be used if turned on
    "debugMode": false,
    "defaultDatasource": ""
    // The default return format for class invocations via web runtimes
    "defaultRemoteMethodReturnFormat": "json",
    "invokeImplicitAccessor": true
    // Class has implicit accessors and mutators by default in BoxLang (.bx files)
    class{
        property firstName
        property lastName
        property email
    }
    
    // Example
    p = new Person()
    // This calls the generated setters in the class
    p.firstName = "luis"
    p.lastname = "majano"
    p.email = "[email protected]"
    // This calls the generated getters in the class
    println( p.firstName );
    // A collection of directories we will class load all Java *.jar files from
    "javaLibraryPaths": [
    	"${boxlang-home}/lib"
    ],
    // The default locale for the runtime; defaults to the JVM locale if empty
    // Please use the IETF BCP 47 language tag values
    "locale": "es_sv",
    
    // You can also use hypens
    "locale": "es-sv",
    
    // Or just the first part
    "locale": "es",
    "mappings": {
    	"/": "${user-dir}",
    	"/core": "/opt/core",
    	"/models": "${user-dir}/models",
    	"/services": "/var/www/shared/services"
    }
    "mappings": {
    	// External mapping (default)
    	"/public": {
    		"path": "${user-dir}/public",
    		"external": true
    	},
    	// Internal-only mapping (not accessible externally)
    	"/internal": {
    		"path": "${user-dir}/internal",
    		"external": false
    	},
    	// Mix simple and complex formats
    	"/api": "/var/www/api",
    	"/secure": {
    		"path": "/var/www/secure",
    		"external": false
    	}
    }
    "mappings": {
    	// Root mapping (simple)
    	"/": "${user-dir}",
    
    	// Public assets (simple, external by default)
    	"/assets": "${user-dir}/public/assets",
    
    	// Application code (complex, external)
    	"/app": {
    		"path": "${user-dir}/app",
    		"external": true
    	},
    
    	// Internal utilities (complex, internal-only)
    	"/utils": {
    		"path": "${user-dir}/internal/utils",
    		"external": false
    	},
    
    	// Shared libraries (complex, internal-only)
    	"/lib": {
    		"path": "/opt/shared/libraries",
    		"external": false
    	}
    }
    // A collection of BoxLang module directories, they must be absolute paths
    "modulesDirectory": [
        "${boxlang-home}/modules"
    ],
    // Use Timespan syntax: "days, hours, minutes, seconds"
    "requestTimeout": "0,0,0,0",
    // Use Timespan syntax: "days, hours, minutes, seconds"
    "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": "redis",
    "timezone": "UTC"
    // By default BoxLang uses high-precision mathematics via BigDecimal operations
    // You can turn this off here for all applications
    "useHighPrecisionMath": true,
    // Extensions BoxLang will process as classes
    "validClassExtensions": [
    	"bx",
    	// Moving to compat at final release
    	"cfc"
    ],
    // Extensions BoxLang will process as templates.
    // This is used by the RunnableLoader
    "validTemplateExtensions": [],
    /**
     * BoxLang Configuration File
     *
     * Here are some of the available variables you can use in this file:
     * ${boxlang-home} - The BoxLang home directory
     * ${user-home} - The user's home directory
     * ${user-dir} - The user's current directory
     * ${java-temp} - The java temp directory
     * ${env.variablename:defaultValue} - The value of a valid environment variable or the default value. Example: ${env.CFCONFIG_HOME:/etc/cfconfig}
     */
    {
    	// The version of the runtime
    	"version": "@build.version@",
    	// Extensions BoxLang will process as classes
    	"validClassExtensions": [
    		"bx",
    		// Moving to compat at final release
    		"cfc"
    	],
    	// The compiler to use for BoxLang files
    	// Valid values are: "java", "asm"
    	// This can be other things later on as we expand the compiler options
    	"compiler": "asm",
    	// Additional Extensions BoxLang will process as templates.  The default extensions such as bxm, bxs, cfm, cfs, etc. are always processed as templates
    	// This is used by the RunnableLoader
    	"validTemplateExtensions": [],
    	// Where all generated classes will be placed
    	"classGenerationDirectory": "${boxlang-home}/classes",
    	// This puts the entire runtime in debug mode
    	// Which will produce lots of debug output and metrics
    	// Also the debugging error template will be used if turned on
    	"debugMode": false,
    	// This setting if enabled will remove all the class files from the class generation directory
    	// This is useful for debugging and testing, but not recommended for production
    	"clearClassFilesOnStartup": false,
    	// This enables the class locations cache for the runtime.  It's used when resolving class paths
    	// mostly using mappings, per request mappings, etc.
    	// We recommend you always enable this setting, unless debugging a very specific issue
    	"classResolverCache": true,
    	// This enables the runnable loader's cache on disk for compiled BoxLang classes
    	// This means that it will load a Boxlang class and never inspect the file again
    	// Turn this on for production, but off for development so you can see your changes
    	"trustedCache": false,
    	// Store the compiled class files on disk for reuse between restarts
    	// If disabled, the class files will be stored in memory only and lost on restart
    	"storeClassFilesOnDisk": true,
    	// 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": "",
    	// Enable whitespace compression in output.  Only in use by the web runtimes currently.
    	"whitespaceCompressionEnabled": true,
    	// By default BoxLang uses high-precision mathematics via BigDecimal operations
    	// You can turn this off here for all applications
    	"useHighPrecisionMath": 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",
    	// The maximum number of completed threads to track for a single request. Old threads will be flushed out to prevent memory from filling.
    	// This only applies to the "thread" component bx:thread name="mythread" {} which tracks execution status and scopes for the remainder of the request that fired it.
    	// ONLY threads which have been completed will be eligible to be flushed.
    	// Note: when the limit is reached, the thread component and related BIFs will no longer throw exceptions on invalid thread names, they will silently ignore attempts to interrupt or join those threads
    	"maxTrackedCompletedThreads": 1000,
    	// A collection of BoxLang mappings, the key is the prefix and the value is the directory
    	// The key can also be a struct containing a "path" and "external" property
    	// A non-external mapping will not be used in the web runtimes to resolve incoming file paths
    	"mappings": {
    		"/": "${user-dir}"
    	},
    	// A collection of BoxLang module directories, they must be absolute paths or expanded paths
    	"modulesDirectory": [
    		"${user-dir}/boxlang_modules",
    		"${boxlang-home}/modules"
    	],
    	// A collection of BoxLang custom component directories, they must be absolute paths
    	"customComponentsDirectory": [
    		"${boxlang-home}/global/components"
    	],
    	// A collection of directories to lookup box classes in (.bx files), they must be absolute paths
    	"classPaths": [
    		"${boxlang-home}/global/classes"
    	],
    	// A collection of directories we will class load all Java *.jar files from
    	"javaLibraryPaths": [
    		"${boxlang-home}/lib"
    	],
    	// 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",
    		// Activate the status printer on load to print out the logging configuration
    		// Turn on to debug LogBack and BoxLang logging configurations
    		"statusPrinterOnLoad": false,
    		// 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": "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": false
    			},
    			// All async operations and facilities will log here.
    			"async": {
    				// 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": false
    			},
    			// All cache operations and facilities will log here.
    			"cache": {
    				// 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": false
    			},
    			// The datasource log is used by the creation, debugging, and management of datasources
    			"datasource": {
    				// 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": false
    			},
    			// The modules log is used by the module service and records all module activity
    			"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": "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": false
    			},
    			// All applications will use this logger for any custom logging
    			"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": "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": false
    			},
    			// All scheduled tasks logging will go here
    			"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": false
    			},
    			// All http related logging will go here
    			"http": {
    				// 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": false
    			}
    		}
    	},
    	// This is the experimental features flags.
    	// Please see the documentation to see which flags are available
    	"experimental": {
    		// If enabled, it will generate AST JSON data under the project's /grapher/data folder
    		"ASTCapture": false
    	},
    	// 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": {
    		// Use this for IO bound tasks, does not support scheduling
    		// This is also the default when requestion an executor service via executorGet()
    		"io-tasks": {
    			"type": "virtual",
    			"description": "Unlimited IO bound tasks using Java Virtual Threads"
    		},
    		// Use this for CPU bound tasks, supports scheduling
    		"cpu-tasks": {
    			"type": "scheduled",
    			"threads": 20,
    			"description": "CPU bound tasks using a fixed thread pool with scheduling capabilities"
    		},
    		// Used for all scheduled tasks in the runtime
    		"scheduled-tasks": {
    			"type": "scheduled",
    			"threads": 20,
    			"description": "Scheduled tasks using a fixed thread pool with scheduling capabilities"
    		}
    	},
    	// BoxLang Scheduler
    	// These are managed by the SchedulerService and registered upon startup
    	// or via a boxlang schedule [scheduler.bx] call
    	"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": {}
    	},
    	"defaultDatasource": "",
    	// 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"
    		// }
    	},
    	// The default return format for class invocations via web runtimes
    	"defaultRemoteMethodReturnFormat": "json",
    	/**
    	* Register any named caches here.
    	* The key is the name of the cache and the value is the cache configuration.
    	*
    	* A `provider` property is required and the value is the name of the cache provider or the fully qualified class name.
    	* The `properties` property is optional and is a struct of properties that are specific to the cache provider.
    	*/
    	"caches": {
    		// The configuration for the BoxLang `default` cache.  If empty, we use the defaults
    		// See the ortus.boxlang.runtime.config.segments.CacheConfig for all the available settings
    		// This is used by query caching, template caching, and other internal caching.
    		// You can use the cache() BIF in order to get access to the default cache.
    		"default": {
    			"provider": "BoxCacheProvider",
    			"properties": {
    				// How many to evict at a time once a policy is triggered
    				"evictCount": 1,
    				// The eviction policy to use: Least Recently Used
    				// Other policies are: LRU, LFU, FIFO, LIFO, RANDOM
    				"evictionPolicy": "LRU",
    				// The free memory percentage threshold to trigger eviction
    				// 0 = disabled, 1-100 = percentage of available free memory in heap
    				// If the threadhold is reached, the eviction policy is triggered
    				"freeMemoryPercentageThreshold": 0,
    				// The maximum number of objects to store in the cache
    				"maxObjects": 1000,
    				// The maximum in seconds to keep an object in the cache since it's last access
    				// So if an object is not accessed in this time or greater, it will be removed from the cache
    				"defaultLastAccessTimeout": 1800,
    				// The maximum time in seconds to keep an object in the cache regardless if it's used or not
    				// A default timeout of 0 = never expire, careful with this setting
    				"defaultTimeout": 3600,
    				// The object store to use to store the objects.
    				// The default is a ConcurrentStore which is a memory sensitive store
    				"objectStore": "ConcurrentStore",
    				// The frequency in seconds to check for expired objects and expire them using the policy
    				// This creates a BoxLang task that runs every X seconds to check for expired objects
    				"reapFrequency": 120,
    				// If enabled, the last access timeout will be reset on every access
    				// This means that the last access timeout will be reset to the defaultLastAccessTimeout on every access
    				// Usually for session caches or to simulate a session
    				"resetTimeoutOnAccess": false,
    				// If enabled, the last access timeout will be used to evict objects from the cache
    				"useLastAccessTimeouts": true
    			}
    		},
    		// This is the holder of all sessions in a BoxLang runtime.
    		// The keys are prefixed by application to create separation.
    		"bxSessions": {
    			"provider": "BoxCacheProvider",
    			"properties": {
    				// How many objects to evict when the cache is full
    				"evictCount": 1,
    				// The eviction policy to use: FIFO, LFU, LIFO, LRU, MFU, MRU, Random
    				"evictionPolicy": "LRU",
    				// The maximum number of objects the cache can hold
    				"maxObjects": 100000,
    				// How long should sessions last for in seconds. Default is 60 minutes.
    				"defaultTimeout": 3600,
    				// The object store to use to store the objects.
    				// The default is a ConcurrentStore which is a thread safe and fast storage.
    				// Available Stores are: BlackHoleStore, ConcurrentSoftReferenceStore, ConcurrentStore, FileSystemStore, Your own.
    				"objectStore": "ConcurrentStore",
    				// The free memory percentage threshold to start evicting objects
    				// Only use if memory is constricted and you need to relieve cache pressure
    				// Please note that this only makes sense depending on which object store you use.
    				"freeMemoryPercentageThreshold": 0,
    				// The frequency in seconds to check for expired objects and expire them using the policy
    				// This creates a BoxLang task that runs every X seconds to check for expired objects
    				// Default is every 2 minutes
    				"reapFrequency": 120,
    				// This makes a session extend it's life when accessed.  So if a users uses anything or puts anything
    				// In session, it will re-issue the timeout.
    				"resetTimeoutOnAccess": true,
    				// Sessions don't rely on the last access timeouts but on the default timeout only.
    				"useLastAccessTimeouts": false
    			}
    		},
    		// Stores all dynamic regular expressions used in the runtime
    		"bxRegex": {
    			"provider": "BoxCacheProvider",
    			"properties": {
    				"evictCount": 1,
    				"evictionPolicy": "LRU",
    				"freeMemoryPercentageThreshold": 0,
    				"maxObjects": 500,
    				// 30 minutes ifnot used
    				"defaultLastAccessTimeout": 1800,
    				// 60 minutes default
    				"defaultTimeout": 3600,
    				"objectStore": "ConcurrentSoftReferenceStore",
    				"reapFrequency": 120,
    				"resetTimeoutOnAccess": false,
    				"useLastAccessTimeouts": true
    			}
    		}
    	},
    	// These are the security settings for the runtime
    	"security": {
    		// All regex patterns are case-insensitive
    		// A list of regex patterns that will match class paths, and if matched, execution will be disallowed
    		// This applies to import statements, createObject, new, and class creation
    		// Ex: "disallowedImports": ["java\\.lang\\.(ProcessBuilder|Reflect", "java\\.io\\.(File|FileWriter)"]
    		"disallowedImports": [],
    		// A list of BIF names that will be disallowed from execution
    		// Ex: "disallowedBifs": ["createObject", "systemExecute"]
    		"disallowedBifs": [],
    		// A list of Component names that will be disallowed from execution
    		// Ex: "disallowedComponents": [ "execute", "http" ]
    		"disallowedComponents": [],
    		// This is a boolean flag that determines if the server.system scope will be populated with the
    		// Java system properties and environment variables. By default this is set to true.
    		"populateServerSystemScope": true,
    		// An explicit whitelist of file extensions that are allowed to be uploaded - overrides any values in the disallowedWriteExtensions
    		"allowedFileOperationExtensions": [],
    		// The list of file extensions that are not allowed to be uploaded. Also enforced by file relocation operations ( e.g. copy/move )
    		"disallowedFileOperationExtensions": []
    	},
    	/**
    	 * The BoxLang module settings
    	 * The key is the module name and the value is a struct of settings for that specific module
    	 * The `enabled` property is a boolean that determines if the module should be enabled or not.  Default is true
    	 * The `settings` property is a struct of settings that are specific to the module and will be override the module settings
    	 */
    	"modules": {
    		// The Compat Module
    		// "compat": {
    		// 	"enabled": true,
    		// 	"settings": {
    		// 		"isLucee": true,
    		// 		"isAdobe": true
    		// 	}
    		// }
    	}
    }

    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

  • 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

  • BoxLang Script Syntax Highlighting

    BoxLang Template Syntax Highlighting

    Installation

    Quick Start

    Features

    • Syntax Highlighting: Full support for BoxLang script (.bx, .bxs) and template (.bxm) files

    • IntelliSense: Auto-completion for BoxLang keywords, functions, and constructs

    • Custom Theme: BoxLang-branded color theme featuring the signature cyan-blue gradient from the official logo

    • Template Support: Mixed HTML/BoxLang template highlighting

    • Code Folding: Intelligent folding for functions, classes, and blocks

    • Bracket Matching: Automatic bracket and quote pairing

    API Reference

    Core Functions

    initializeBoxLangSupport()

    Initializes BoxLang language support in Monaco Editor. This registers the language, sets up syntax highlighting, and applies the theme.

    createBoxLangEditor(container, options)

    Creates a Monaco Editor instance configured for BoxLang.

    Parameters:

    • container (HTMLElement): DOM element to host the editor

    • options (Object): Monaco Editor configuration options

    Returns: Monaco Editor instance

    getBoxLangLanguage()

    Returns the registered BoxLang language configuration.

    Constants

    Language IDs

    • BOXLANG_LANGUAGE_ID: 'boxlang' - For script files (.bx, .bxs)

    • BOXLANG_TEMPLATE_LANGUAGE_ID: 'boxlang-template' - For template files (.bxm)

    File Extensions

    • BOXLANG_EXTENSIONS: ['.bx', '.bxs'] - BoxLang script file extensions

    • BOXLANG_TEMPLATE_EXTENSIONS: ['.bxm'] - BoxLang template file extensions

    MIME Types

    • BOXLANG_MIME_TYPES: ['text/x-boxlang']

    • BOXLANG_TEMPLATE_MIME_TYPES: ['text/x-boxlang-template']

    Individual Components

    If you need more control, you can import and configure individual components:

    Development

    1. Install dependencies:

    2. Start development server:

      This will start Vite's development server at http://localhost:3000 with hot module replacement for fast development.

    3. Build library for production:

      This builds the library for production using Rollup.

    4. Preview production build:

      This serves the demo locally for testing. Note: The demo is for development purposes only and doesn't produce a production build.

    File Structure

    Integration Guide

    Basic Setup

    To integrate BoxLang support into your own Monaco Editor instance:

    File Extension Mapping

    Configure your application to map file extensions to the appropriate language:

    Custom Completion Provider

    The integration includes a basic completion provider. You can extend it with your own completions:

    Supported Features

    BoxLang Script Files (.bx, .bxs)

    • Component declarations

    • Function definitions

    • Class syntax with inheritance

    • Interface definitions

    • Property declarations

    • Annotations (@inject, @cacheable, etc.)

    • Control flow (if/else, loops, switch)

    • Exception handling (try/catch/finally)

    • Variable declarations and scoping

    • Operators and expressions

    BoxLang Template Files (.bxm)

    • HTML markup

    • BoxLang script blocks (<bx:script>)

    • BoxLang components (<bx:if>, <bx:loop>, etc.)

    • String interpolation (#variable#)

    • BoxLang comments (<!--- comment --->)

    • Mixed HTML/BoxLang syntax

    Customization

    Themes

    You can create custom themes by extending the base theme:

    Language Configuration

    Modify boxlang-language-config.js to customize:

    • Comment styles

    • Bracket pairs

    • Auto-closing pairs

    • Folding rules

    • Indentation rules

    Syntax Highlighting

    Update boxlang-monarch-tokens.js to add or modify:

    • Keywords

    • Operators

    • Token patterns

    • Syntax rules

    Development

    Testing Changes

    1. Make your changes to the source files

    2. Run npm run dev to start the Vite development server

    3. Open http://localhost:3000 to test your changes

    4. The page will automatically reload when you save changes thanks to Vite's fast HMR (Hot Module Replacement)

    Adding New Keywords

    To add new BoxLang keywords:

    1. Edit boxlang-monarch-tokens.js

    2. Add the keyword to the keywords array

    3. If it's a type keyword, also add it to typeKeywords

    4. Test the highlighting in the demo

    Troubleshooting

    Common Issues

    Q: Monaco Editor shows "Language 'boxlang' is not configured" error

    A: Make sure you call initializeBoxLangSupport() before creating the editor:

    Q: Syntax highlighting doesn't work

    A: Verify the language is set correctly when creating the editor:

    Q: Custom theme not applied

    A: Ensure the theme is set after initialization:

    Q: TypeScript errors when importing

    A: The package includes TypeScript definitions. If you encounter issues, try:

    Performance Tips

    • Use automaticLayout: true for responsive editors

    • Consider lazy loading for large applications

    • Use tokenization.colorValidation: false for better performance with many colors

    Contributing

    We welcome contributions! Here's how you can help:

    Reporting Issues

    • Use the GitHub issue tracker

    • Include a clear description and steps to reproduce

    • Provide code samples when possible

    • Mention your browser and Monaco Editor version

    Development Setup

    1. Fork the repository

    2. Clone your fork: git clone https://github.com/YOUR_USERNAME/boxlang-monaco-editor.git

    3. Install dependencies: npm install

    4. Start development server: npm run dev

    5. Make your changes

    6. Test thoroughly using the demo at http://localhost:3000

    7. Run linting: npm run lint

    8. Create a pull request

    Areas for Contribution

    • New Language Features: Add support for additional BoxLang syntax

    • Theme Improvements: Enhance the color scheme or add new themes

    • IntelliSense: Expand autocompletion with more BoxLang functions

    • Performance: Optimize tokenization and parsing

    • Documentation: Improve examples and API documentation

    • Testing: Add unit tests and integration tests

    Code Style

    • Follow the existing ESLint configuration

    • Use meaningful commit messages

    • Add JSDoc comments for new functions

    • Update README for new features

    License

    Apache 2.0 - see the LICENSE file for details.

    Related Projects

    • BoxLang - The BoxLang programming language

    • Monaco Editor - The code editor that powers VS Code

    • TextMate - The original editor supporting TextMate grammars

    listdeleteAt
    returns a list with multiple delimiters as a list with whole delimiters

    BL-231 StructNew with localeSensitive flag throws error

    BL-235 structKeyTranslate returns void

    BL-241 StructGet does not create struct when missing

    BL-245 StructFindValue returning null owner

    BL-246 no named applications not auto creating name

    BL-247 application listener requests interception points not registered

    BL-248 ambiguous if statements when not using curly braces

    BL-249 this.javasettings not expanding / to correct pathing

    BL-250 this.javasettings ignores paths to actual jars and classes

    BL-257 cfdirectory fails on centos, converting datetime

    BL-263 dateAdd() modifies its argument!

    BL-265 `toString` not formatting doubles correctly

    BL-266 Attempt to cast instead of expecting strings inside `isValid`

    BL-270 Regression on JSON serialization of box classes with JSON exclude annotations

    New Features

    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 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 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.

    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.

    BL-260 Add parallel streams from BoxLang arrays

    All BoxLang arrays have native stream support, and you get native parallel support as well.

    BL-264 Truthy / Falsey completion for boolean caster

    Our truthy/false evaluations for arrays, structs, queries, Java lists, and collections are complete.

    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.

    Here are the current functions available to you in this beta. There are more coming to make it more fluent.

    • 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 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:

    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.

    This will allow framework developers to collaborate with first-class methods in any BoxLang class.

    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 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.

    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.

    BL-274 writedump abort support

    More work towards compatibility is completed.

    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.

    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

    BL-140
    BL-141
    BL-193

    RedisCluster

    A Redis cluster cache provider

    Done

    MongoDB

    A MongoDB based Provider

    In Progress

    Couchbase

    A Couchbase based provider

    In Progress

    ElasticSearch

    An Elastic Search provider

    In Progress

    EhCache

    An EhCacheProvider

    In Progress

    You can also find more providers through third-party providers at www.forgebox.io.

    BoxLang

    The enterprise BoxLang native cache provider can leverage many different object stores.

    Done

    Redis

    A Redis single-node provider

    Done

    Object stores are the foundational storage layer of the BoxLang cache engine. They provide the actual mechanism for storing, retrieving, and managing cached objects. While cache providers coordinate user interactions and act as a service layer, object stores handle the low-level data persistence and retrieval operations.

    Type
    Description

    BlackHoleStore

    Mocking store, just simulates a store, nothing is stored.

    ConcurrentSoftReferenceStore

    Memory-sensitive storage leveraging Java Soft References.

    ConcurrentStore

    Leverages concurrent hashmaps for storage.

    FileSystemStore

    Stores the cache items in a serialized fashion on disk

    JDBCStore

    Each store can have different configuration properties as well.

    Read More
    https://forgebox.io/view/bx-redis
    https://www.boxlang.io/plans
    trusted cache settings
    BL-1021
    BL-1084
    BL-1089
    BL-1090
    BL-1093
    BL-1143
    BL-1147
    BL-1148
    BL-1149
    BL-1153
    BL-1155
    BL-1158
    BL-1159
    BL-1018
    BL-1024
    BL-1026
    BL-1036
    BL-1056
    BL-1063
    BL-1064
    BL-1077
    BL-1078
    BL-1079
    BL-1080
    BL-1082
    BL-1085
    BL-1086
    BL-1087
    BL-1088
    BL-1092
    BL-1094
    BL-1095
    BL-1096
    BL-1097
    BL-1099
    BL-1100
    BL-1101
    BL-1102
    BL-1103
    BL-1104
    BL-1105
    BL-1106
    BL-1109
    BL-1110
    BL-1111
    BL-1112
    BL-1113
    BL-1114
    BL-1115
    BL-1116
    BL-1117
    BL-1118
    BL-1120
    BL-1121
    BL-1122
    BL-1124
    BL-1125
    BL-1126
    BL-1128
    BL-1129
    BL-1130
    BL-1132
    BL-1133
    BL-1134
    BL-1135
    BL-1137
    BL-1138
    BL-1139
    BL-1140
    BL-1142
    BL-1144
    BL-1146
    BL-1150
    BL-1151
    BL-1152
    BL-1156
    BL-1157
    BL-1160
    BL-814
    BL-1076
    Planswww.boxlang.io
    www.boxlang.io/plans

    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

    Implement nested transactions

    npm install
    npm run dev
    npm run build
    npm install boxlang-monaco-editor monaco-editor
    import * as monaco from 'monaco-editor';
    import { initializeBoxLangSupport, createBoxLangEditor } from 'boxlang-monaco-editor';
    
    // Initialize BoxLang support
    initializeBoxLangSupport();
    
    // Create a BoxLang editor
    const editor = createBoxLangEditor(document.getElementById('editor'), {
        value: 'class { function init() { return this; } }',
        language: 'boxlang',
        theme: 'boxlang-theme'
    });
    import { initializeBoxLangSupport } from 'boxlang-monaco-editor';
    initializeBoxLangSupport();
    import { createBoxLangEditor } from 'boxlang-monaco-editor';
    
    const editor = createBoxLangEditor(document.getElementById('editor'), {
        value: 'component { function init() { return this; } }',
        language: 'boxlang',
        theme: 'boxlang-theme',
        automaticLayout: true
    });
    import { getBoxLangLanguage } from 'boxlang-monaco-editor';
    const language = getBoxLangLanguage();
    import { boxlangLanguageConfig } from 'boxlang-monaco-editor';
    import { boxlangMonarchTokens } from 'boxlang-monaco-editor';
    import { boxlangTheme } from 'boxlang-monaco-editor';
    
    // Manual setup
    monaco.languages.register({ id: 'boxlang' });
    monaco.languages.setLanguageConfiguration('boxlang', boxlangLanguageConfig);
    monaco.languages.setMonarchTokensProvider('boxlang', boxlangMonarchTokens.script);
    monaco.editor.defineTheme('boxlang-theme', boxlangTheme);
    boxlang-monaco-editor/
    ├── src/
    │   ├── demo/
    │   │   ├── index.html          # Demo page
    │   │   └── index.js            # Demo application
    │   ├── index.js                # Main library entry point
    │   ├── boxlang-language-config.js   # Language configuration
    │   ├── boxlang-monarch-tokens.js    # Syntax tokenizer
    │   └── boxlang-theme.js        # Custom color theme
    ├── dist/                       # Production build output
    ├── package.json
    ├── vite.config.js              # Vite configuration
    └── rollup.config.js           # Rollup config for library builds
    import * as monaco from "monaco-editor";
    import { boxlangLanguageConfig } from "boxlang-monaco-editor/boxlang-language-config";
    import { boxlangMonarchTokens } from "boxlang-monaco-editor/boxlang-monarch-tokens";
    import { boxlangTheme } from "boxlang-monaco-editor/boxlang-theme";
    
    // Register BoxLang language
    monaco.languages.register( { id: "boxlang" } );
    monaco.languages.register( { id: "boxlang-template" } );
    
    // Set language configuration
    monaco.languages.setLanguageConfiguration( "boxlang", boxlangLanguageConfig );
    monaco.languages.setLanguageConfiguration( "boxlang-template", boxlangLanguageConfig );
    
    // Set syntax highlighting
    monaco.languages.setMonarchTokensProvider( "boxlang", boxlangMonarchTokens.script );
    monaco.languages.setMonarchTokensProvider( "boxlang-template", boxlangMonarchTokens.template );
    
    // Define custom theme
    monaco.editor.defineTheme( "boxlang-theme", boxlangTheme );
    
    // Create editor
    const editor = monaco.editor.create( document.getElementById( "container" ), {
        value: "component { function init() { return this; } }",
        language: "boxlang",
        theme: "boxlang-theme"
    } );
    function getLanguageForFile( filename ) {
        const ext = filename.split( "." ).pop().toLowerCase();
        switch ( ext ) {
            case "bx":
            case "bxs":
                return "boxlang";
            case "bxm":
                return "boxlang-template";
            default:
                return "plaintext";
        }
    }
    monaco.languages.registerCompletionItemProvider( 'boxlang', {
        provideCompletionItems: function( model, position ) {
            // Your custom completion logic here
            return {
                suggestions: [
                    {
                        label: 'myCustomFunction',
                        kind: monaco.languages.CompletionItemKind.Function,
                        insertText: 'myCustomFunction( $1 )',
                        insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                        documentation: 'My custom function'
                    }
                ]
            };
        }
    });
    const myCustomTheme = {
        base: 'vs-dark',
        inherit: true,
        rules: [
            { token: 'keyword', foreground: 'ff0000' },
            // Add your custom rules
        ],
        colors: {
            'editor.background': '#1a1a1a',
            // Add your custom colors
        }
    };
    
    monaco.editor.defineTheme('my-custom-theme', myCustomTheme);
    import { initializeBoxLangSupport } from 'boxlang-monaco-editor';
    initializeBoxLangSupport(); // Call this first
    // Then create your editor
    const editor = monaco.editor.create(container, {
        value: 'your code',
        language: 'boxlang', // For .bx/.bxs files
        // OR
        language: 'boxlang-template' // For .bxm files
    });
    initializeBoxLangSupport();
    monaco.editor.setTheme('boxlang-theme');
    import type { BoxLangMonacoEditor } from 'boxlang-monaco-editor';
    // OR
    import * as BoxLangMonaco from 'boxlang-monaco-editor';
    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() )
    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 )
        }
    }
    result = fruits
      .parallelStream()
      .filter(  fruit -> fruit.startsWith( "a" ) )
      .toList();
    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( "" )
        
    /**
     * 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;
    	}
    
    }
    
    function main( args={} ){
        return new Person()
            .setName( "Luis" )
            .setSurname( "Majano" )
            .toJSON()
    }
    boxRegisterInterceptor( ()=> listenToRequestStarts(), "onServerScopeCreation" )
    boxRegisterRequestInterceptor( ()=> listenToRequestStarts(), "onRequestStart" )
    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 )
    # OS
    install-bx-module bx-redis
    
    # CommandBox
    box install bx-redis

    Distributed cache store backed by JDBC databases for multi-instance cache sharing

    We are excited to bring the completion of nested transactions into BoxLang, something we have wanted in an open-source engine for years.

    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 queryReverse() finalized

    This BIF is now complete so you can easily reverse query data.

    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 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.

    This expression represents a first-class BoxLang function that can be invoked directly.

    You can also store the BIF static access into variables.

    You can also leverage it as a high-order function combination from methods or classes that expect function references.

    BL-351 Allow Functional binding to member functions

    In order to explain this new functionality in BoxLang, here is a Java snippet:

    This syntax is a shortcut for writing out the following Java lambda:

    (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:

    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

    So our Java example becomes like this in BoxLang

    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.

    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:

    It can be placed into a variable and invoked later:

    And it can be passed to higher-order functions. (This is the main use case)

    Additionally, we have added support for multiple-arguments as well:

    Example:

    The arguments will not be evaluated until the function is invoked, and the argument expressions will be re-evaluated for every invocation.

    The argument evaluation will have lexical binding to the declaring context.

    or

    Bound member methods can also use named params (unless they are Java methods, of course)

    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 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}

    BL-353 threadTerminate() finalized

    We have now finalized a threadTerminate( name ) BIF.

    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 queryInsertAt() BIF finalized

    This is now finalized.

    BL-356 QueryRowSwap() bif finalized

    This is now finalized.

    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 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.

    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.

    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 Configuration now supports executor registration for global usage

    You can now register your executors globally in BoxLang in the boxlang.json

    BL-124 Implement primary/foreign key columns in dbInfo

    DBInfo now returns primary and foreign key columns when you need them.

    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 "Fix" return types of BIFs that return "true" for no real reason

    One of the odd things about CFML is the following:

    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 Provide Java FI typing on all higher-order BIFs

    BL-371 make name un-required in the application component

    BL-346 DynamicObject equals() hashCode() to allow for dynamic checking

    Bugs

    BL-364 Overridden getter in parent class not being used

    BL-370 List and Delmiter Args are not correct in ListReduce callback

    BL-365 The throwable Dump table is not styled

    BL-157
    npm version
    License: Apache-2.0
    Logo

    Chromebooks

    Learn how to code with BoxLang on your Chromebook using Linux development environment!

    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.

    Requirements

    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();
        }
        
    }
    // Syntax
    ::BIF
    
    // Examples
    ::UCase
    ::hash
    (::reverse)( "darb" ); // brad
    foo = ::ucase
    foo( "test" ) // TEST
    ["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" ]
    List.of("apple", "banana", "cherry").stream().forEach(String::toUpperCase);
    List.of("apple", "banana", "cherry").stream().forEach(str -> str.toUpperCase());
    .methodName
    i -> i.methodName()
    ["apple", "banana", "cherry"].stream().forEach( .toUpperCase );
    nameGetter = .name
    data = { name : "brad", hair : "red" }
    nameGetter( data ) // brad
    (.reverse)( "darb" ); // brad
    foo = .ucase;
    foo( "test" );  // TEST
    ["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" ]
    .methodName( arg1, arg2 )
    ["brad","luis","jon"].map( .left(1) ); // [ "b", "l", "j" ]
    pendingOrders.each( .submit( generateNextOrderNumber() ) ) // Fresh order number for each submission
    local.suffix = " Sr."
    ["brad","luis","jon"].map( .concat( suffix ) ); // [ "brad Sr.", "luis Sr.", "jon Sr." "]
    children.each( .setParent( this ) )
    foo = .left( count=2 );
    foo( "test" ); // "te"
    // 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 )
    // 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" )
    )
    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();   
    // 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
    	}
    },
    myArr.append( "foo" ) // returns myArr
    arrayAppend( myArr ) // returns true??
    npm run preview
    Attempt (boxlang 1.0.0-beta2 API)s3.amazonaws.com
    https://www.npmjs.com/package/boxlang-monaco-editorwww.npmjs.com
    Not found
    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)

    Enable Linux Development Environment

    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.

    📋 Table of Contents

    • Requirements

    • Accessing the Linux Terminal

    • Installing Java

    • Installing BoxLang

    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"

    Terminal Application

    Click on the Penguin tab to access your Linux environment:

    Linux Terminal Environment

    Setting Up the Development Environment

    Step 1: System Updates and Essential Tools

    Start by updating your system and installing essential development tools:

    Step 2: Installing Java 21

    Modern Debian distributions now include OpenJDK 21. Try the simple installation first:

    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:

    Modern Note: Most current Debian-based distributions now include OpenJDK 21 in their repositories, making the simple apt install method the preferred approach.

    Step 3: Installing BoxLang

    BoxLang installation is straightforward with the official installer script:

    Verify the installation:

    BoxLang REPL on Chromebook

    The REPL (Read-Eval-Print Loop) opens, allowing you to start coding immediately, run BoxLang files, start web servers, and much more!

    Setting Up VS Code with BoxLang

    Step 4: 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

    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

    Architecture Check: If unsure about your Chromebook's processor type, run dpkg --print-architecture in the terminal to verify.

    Install the downloaded package:

    VS Code Installation

    Step 5: 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

    VS Code Extensions Marketplace
    BoxLang Extension Installation

    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

    Creating Your First BoxLang Application

    Step 6: 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:

    2. Open VS Code in this folder:

    3. Create a new file called Hello.bx

    Add the following code:

    BoxLang Hello World Class

    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:

    Step 7: Creating a Web Application

    Now let's create a web application using BoxLang's templating system.

    Create a template file called index.bxm:

    Step 8: 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"

    BoxLang VS Code Commands

    You'll see output in the debug console:

    Access your web application:

    VS Code will automatically open your browser, or you can manually navigate to http://localhost:8080

    BoxLang Web Application Running

    Congratulations! 🎉 You've successfully created and deployed your first BoxLang web application on a Chromebook!

    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

    Additional Resources

    • 📚 BoxLang Documentation - Complete language reference

    • 🌐 BoxLang GitHub - Source code and issues

    • 💬 Community Discord - Get help from the community

    • 🎓 BoxLang Examples - Sample applications and tutorials

    Troubleshooting Common Issues

    Java-related issues:

    BoxLang server issues:

    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.

    Pro Tip: This entire guide was written and tested on a Lenovo Duet 5 Chromebook, proving that Chromebooks are excellent development machines for BoxLang! 💻✨

    Happy coding with BoxLang on your Chromebook! 🚀

    https://www.google.com/chromebook/

    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

    📋 BoxAST() BIF

    The BoxAST() function parses BoxLang or CFML source code and returns its AST representation.

    Syntax

    Parameters

    Parameter
    Type
    Required
    Default
    Description

    * 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.

    json

    Returns the AST as a JSON string, perfect for passing to external tools or storing for later analysis.

    text

    Returns a human-readable text representation of the AST structure, useful for debugging and visualization.

    Source Types

    script (default)

    Parse BoxLang script syntax (.bx, .bxs files).

    template

    Parse BoxLang template syntax (.bxm files with <bx:> tags).

    cfscript

    Parse CFML/ColdFusion script syntax for migration and compatibility tools.

    cftemplate

    Parse CFML/ColdFusion template syntax (.cfm files with <cf> tags) for migration tools.

    💡 Usage Examples

    Basic AST Generation

    Using String Member Method

    BoxLang strings have a convenient toAST() member method:

    Parsing Files

    JSON Export for External Tools

    Text Visualization

    🎯 Use Cases

    Code Analysis Tools

    Build custom linters and static analysis tools to enforce coding standards:

    Code Formatters

    Create custom code formatting utilities:

    Documentation Generators

    Extract function signatures, parameters, and documentation comments:

    Migration Tools

    Parse and analyze CFML code for BoxLang migration:

    Refactoring Tools

    Analyze and transform code structures:

    IDE Tooling

    Power syntax highlighting, code intelligence, and autocomplete features:

    🔍 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

    Example AST Structure

    For code: x = 1 + 2

    📊 Best Practices

    When to Use BoxAST():

    • Building code analysis and quality tools

    • Creating custom formatters and linters

    Performance Tips:

    • Use filepath parameter for large files instead of reading into memory first

    • Cache AST results for files that don't change frequently

    Important Considerations:

    • Parsing Errors: Invalid syntax will throw an exception - wrap in try/catch

    • Large Files: Parsing very large files can consume significant memory

    🔗 Related Resources

    🛠️ Building Tools with BoxAST()

    The BoxAST() BIF opens up powerful possibilities for the BoxLang ecosystem:

    Example: Simple Linter

    Example: Function Extractor

    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.

    FORGEBOX: Boxlang Redis Moduleforgebox.io

    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.

    mkdir ~/boxlang-projects
    cd ~/boxlang-projects
    code .
    # 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
    # Try the easy installation first
    sudo apt install -y openjdk-21-jdk
    
    # Verify installation
    java -version
    # 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
    # Run the BoxLang installer
    sudo /bin/bash -c "$(curl -fsSL https://downloads.ortussolutions.com/ortussolutions/boxlang/install-boxlang.sh)"
    # Check BoxLang version
    boxlang --version
    
    # Test the REPL
    boxlang
    # 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
    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! 🎉";
        }
    
    }
    🚀 Hello from Chromebook and BoxLang!
    📅 Current time: {ts '2024-05-23 18:27:33'}
    💻 System architecture: aarch64
    BoxLang is running perfectly on your Chromebook! 🎉
    <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>
    🚀 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.
    # 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
    # Verify Java installation
    java -version
    echo $JAVA_HOME
    
    # If Java isn't found, source your profile
    source ~/.bashrc
    # Check if port is in use
    netstat -tulpn | grep :8080
    
    # Stop any running BoxLang processes
    pkill -f boxlang
    Logo
    Common Use Cases
  • AST Analysis Examples

  • Best Practices

  • string

    No

    "struct"

    Output format: "struct", "json", or "text"

    sourceType

    string

    No

    "script"

    Syntax type: "script", "template", "cfscript", or "cftemplate"

    comments - Associated comments

  • Additional Properties - Node-specific data (name, value, operator, statements, etc.)

  • Developing migration utilities from CFML to BoxLang

  • Generating documentation from source code

  • Implementing refactoring tools

  • Powering IDE features and code intelligence

  • 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

  • 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

  • BoxLang Language Reference

    source

    string

    Yes*

    -

    BoxLang/CFML source code to parse

    filepath

    string

    Yes*

    -

    Path to file to parse (alternative to source)

    What is an AST?
    BoxAST() BIF
    Output Formats
    Node Types
    BoxLang Compiler
    CFML Transpiler
    BoxLang IDE
    Release Notes 1.7.0

    returnType

    BoxAST(
        source: string,
        returnType: string = "struct",
        sourceType: string = "script"
    )
    
    BoxAST(
        filepath: string,
        returnType: string = "struct",
        sourceType: string = "script"
    )
    ast = BoxAST( source: "x = 1 + 2;" );
    // Returns: struct with nodes, positions, types, etc.
    astJson = BoxAST(
        source: "function hello() { return 'world'; }",
        returnType: "json"
    );
    // Returns: JSON string representation of the AST
    astText = BoxAST(
        source: "x = 1 + 2;",
        returnType: "text"
    );
    // Returns: Pretty-printed text tree structure
    ast = BoxAST(
        source: "function hello() { return 'world'; }",
        sourceType: "script"
    );
    ast = BoxAST(
        source: "<bx:output>#now()#</bx:output>",
        sourceType: "template"
    );
    ast = BoxAST(
        source: "cfset x = 1; cfloop from='1' to='10' index='i' { writeOutput(i); }",
        sourceType: "cfscript"
    );
    ast = BoxAST(
        source: "<cfset x = 1><cfoutput>#x#</cfoutput>",
        sourceType: "cftemplate"
    );
    // Parse simple BoxLang code
    code = "x = 1 + 2; y = x * 3;";
    ast = BoxAST( source: code );
    
    // Inspect the AST structure
    println( ast.toString() );
    // 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" );
    // 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"
    );
    // 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 );
    // 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
    // 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 );
    // 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 );
    // Parse component file
    componentCode = fileRead( "MyComponent.bx" );
    ast = componentCode.toAST();
    
    // Extract all functions with their metadata
    docs = extractFunctionDocumentation( ast );
    
    // Generate API documentation
    generateMarkdownDocs( docs );
    // 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 );
    // 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 );
    // Parse current file for IDE features
    currentCode = editor.getCurrentCode();
    ast = currentCode.toAST();
    
    // Provide intelligent autocomplete based on AST analysis
    suggestions = getAutocompleteSuggestions( ast, cursorPosition );
    {
        "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
                        }
                    }
                }
            }
        ]
    }
    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;
    }
    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;
    }
    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

    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:

    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

    You can learn more about virtual threads here: https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html

    This now allows us to create Java-based virtual threads using BoxLang constructs threadNew()BIF or the threadcomponent:

    The default for parallel executions in map(), filter(), each()have also been updated to leverage virtual threads by default. You can use the virtual = falseso they can execute in the cpu-tasksexecutor 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:

    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 schedulecommand. Just tell it which scheduler to spin up and forget about CRON.

    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.jsonthat once the runtime starts, it will startup your schedulers.

    You can now also choose the default executor and cache to use for server fixations. The schedulersis 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.bxfile and the this.schedulerssetting.

    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 Command to schedule Schedulers: boxlang schedule {path.bx}

    BL-1265 Allows for an array of BoxLang schedulers to be loaded on the startup of the runtime

    BL-1269 this.schedulers for Application.bx loading of schedulers

    BL-1268 Scheduler BIFS for managing schedulers programmatically

    BL-1264 configuration for `schedulers` in the `boxlang.json`

    BL-1212 Add parser methods to report on and clear ANTLR cache

    BL-1207 this.moduleDependencies for Modules so they can activate module dependencies

    BL-1170 New convention boxlang_modules wherever you start a BoxLang app it loads those modules first

    BL-1171 Added Liberica JDK as a supported version of our language

    BL-1172 Add HttpVersion key to http component

    BL-1176 add missing "hex" validation to isValid()

    BL-1181 executorGet() with no params must return the default executor

    BL-1182 Allow throw; with no expression

    BL-1183 change listener improvements

    BL-1193 Support @module-name suffix for class loading

    BL-1195 missing bifs: BoxUnregisterInterceptor(), BoxUnregisterRequestInterceptor()

    BL-1196 Added isVirtual, isDaemon, threadGroup, id to the thread metadata

    BL-1197 Threading Improvements: isThreadAlive(), isThreadInterrupted(), threadInterrupt() bifs

    BL-1206 modules directories being created unecesarrily if not found

    BL-1208 enable transparent anchors in java regex

    BL-1209 Ensure implicit onRequest() method allows output, even if output=false at the application level

    BL-1239 Add Virtual Attribute to Thread Component

    BL-1240 Solidify all the executors that ship with the runtime: io-tasks, cpu-tasks, and scheduled-tasks

    BL-1251 Put debug mode cache clearing behind a config flag: clearClassFilesOnStartup

    BL-1258 Make Java interop varargs optional

    BL-1259 only populate form.fieldNames on POST method

    BL-1260 Add `modules` key to server.boxlang struct

    BL-1263 Add `BoxCache` annotation to allow aliasing cache providers

    Bugs

    BL-1023 When First Request to Application is a CFC, the application scope is undefined

    BL-1083 cliRead adds a line break

    BL-1107 Dump of XML Object Does not Include Node Names

    BL-1145 When calling a remote Bx method, specifying returnformat in the pseudo-constructor does not work

    BL-1154 ASM BoxPiler is setting up properties after pseudoconstructor runs instead of before

    BL-1162 BoxLang BIF Proxy losing context of execution

    BL-1163 Key instance not being coerced to string

    BL-1164 Super Scope is Lost When UDF in child class from closure in parent class

    BL-1165 Static method calling static method loses static context

    BL-1166 application.applicationName is a Key instance, not a string

    BL-1168 GetContextRoot Returning Slash-Prefixed Root

    BL-1169 Strings which contain invalid octals are not casting correctly in the NumberCaster

    BL-1174 access remote not recognised

    BL-1175 Unable to compile/call box class with java override

    BL-1177 `expandPath` not expanding mappings when used in the Application pseudo constructor

    BL-1178 Compat: reMatchNoCase should find matches but generates error

    BL-1179 expandPath() matches partial folders when mapping path doesn't have trailing slash

    BL-1185 getMetata getClass().getSimpleName()|.getName() on IBoxRunnable returns Struct class names

    BL-1187 NPE when passing null to first constructor arg of a box class

    BL-1188 Space missing when cfquery in function

    BL-1189 bx:zip doesn't implement result

    BL-1191 Add support for `this.caches` in Application.bx|cfc

    BL-1192 Can't create box class with literal @ symbol in name

    BL-1198 CGI Scope should check variable name before attempting http_header_name convention

    BL-1200 DynamicObject does not support dereference and invocation of non-static BoxLang class methods

    BL-1201 Invoke BIF No Longer Functioning on Java Objects in Compat mode

    BL-1202 java list dump template breaks in compat mode when expand is not passed

    BL-1203 Java Interop - Typed Primitive Arrays passed as Java Args are always `Object[]`

    BL-1204 Compiler error - Non-literal value in BoxExpr type with hash expression

    BL-1205 ClassMetaDataVisitor cannot find super class in same directory

    BL-1210 cfhttp port attribute is not supported

    BL-1211 servlet runtime using wrong getPageContext() BIF

    BL-1213 Error accessing Map<String,Object> when the key doesn't exist

    BL-1215 directoryList has odd behavior when using 'dot' paths

    BL-1220 Java Interop - StringBuilder usage is incorrectly passed through to String `replace` BIF

    BL-1221 Error in cfdump when dumping a xml variable

    BL-1222 Array Index Assignment for appending XML Children Not Working

    BL-1223 class java.lang.Integer cannot be cast to class java.lang.String

    BL-1224 Error serializing to JSON

    BL-1225 getPageContext Lucee compatibility

    BL-1226 DateConvert BIF Not Locale Aware

    BL-1227 cftransaction - Failed to set savepoint

    BL-1228 Can't cast [] to a DateTime

    BL-1229 Illegal class name

    BL-1230 ListToArray on a Null value Throws Exception

    BL-1231 ReplaceNoCase with Integer Replacement throws Exception

    BL-1232 Compat - can't cast Short month with time to date

    BL-1233 Java Interop - Explicit java.time.Duration is cast to BigDecimal upon use

    BL-1234 current template not set in static initializer block

    BL-1236 apparent connection leak detected

    BL-1237 Issue with Java interop and var args

    BL-1238 Array element type mismatch when using primitive arrays of non-well-known classes

    BL-1241 Modify dump when dumping a class instance

    BL-1242 Default cache was not being defaulted

    BL-1243 Default cache should only allow properties to be overriden, not type

    BL-1244 system cache clear now can clear query caching

    BL-1245 Cache Component Not Accepting Timespan Timeout and IdleTime Args Correctly

    BL-1246 Replace BIF fails when replacement argument is numeric

    BL-1247 cfcatch key detail is missing

    BL-1248 Can't cast [Tue Nov 22 11:01:51 CET 2022] to a DateTime

    BL-1249 class java.lang.Integer cannot be cast to class java.lang.String

    BL-1250 Invoke Throws Error When Null Value is Assigned on Generated Setter

    BL-1252 Consider renaming jsonDeserialize member function

    BL-1255 JDBC - SQL Server Error When Using Date Time in Query Param

    BL-1256 Incorrect parsing of string times when used in time format when Zone is different from system

    BL-1257 Unsupported isolation level: READ_COMMITTED

    BL-1261 Miniserver getPageContext().getResponse().reset() not clearing status code and headers

    Installing VS Code
    Creating Your First App
    Troubleshooting
    Best Practices

    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.

    BoxLang Version Manager

    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.)

    The only difference is that BVM adds version management capabilities on top.

    📋 Table of Contents

    🛠️ 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

    🚀 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.

    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):

    Ubuntu/Debian:

    RHEL/CentOS/Fedora:

    Alpine Linux:

    ⬇️ Installation

    💻 Basic Usage

    📂 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

    🔒 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

    Force Reinstallation

    Use the --force flag to reinstall existing versions:

    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:

    Automatic Snapshot Updates

    BVM automatically ensures you have the latest development builds:

    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)

    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

    Example

    Before (old behavior):

    After (new behavior):

    📁 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

    Creating .bvmrc Files

    Using .bvmrc Files

    .bvmrc File Format

    The .bvmrc file is simple - just put the version on the first line:

    Example Workflow

    Directory Hierarchy

    BVM searches for .bvmrc files starting from the current directory and walking up the directory tree:

    ⌨️ 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.,

    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

    Execution

    • bvm exec <args> - Execute BoxLang with current version

      • Alias: bvm run <args>

    • bvm miniserver <args> - Start BoxLang MiniServer with current version

    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

    🔄 Keeping BVM Updated

    BVM includes a built-in update checker that helps you stay current with the latest version.

    Checking for Updates

    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

    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:

    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

    Completely Uninstalling BVM

    Use bvm uninstall to completely remove BVM and all installed BoxLang versions:

    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

    Complete Uninstall Process

    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:

    1. Uninstall Current BoxLang (Recommended)

    2. Install BVM

    3. Install Your Preferred BoxLang Version

    4. Verify Everything Works

    Note: Your BoxLang home directory (~/.boxlang) with modules, settings, and data will be preserved during migration.

    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

    install-bx-module bx-orm
    "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
    	}
    },
    threadNew( 
      runnable: () => {},
      virtual: true
    )
    
    bx:thread name="virtualTest" virtual=true{
      // A virtual thread.
    }
    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" ) );
    	}
    
    }
    boxlang schedule MyScheduler.bx
    "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": {}
    },
    class{
    
        ...
        
        this.schedulers = [ "path.to.Scheduler" ]
    
    }
    BoxFuture (boxlang 1.0.0-beta6 API)s3.amazonaws.com

    ✅ Same installation quality and reliability

    Installation
  • Basic Usage

  • What BVM Installs

  • Examples

  • Security & Reliability

  • Project-Specific Versions (.bvmrc)

  • Commands

  • Keeping BVM Updated

  • Uninstalling BoxLang Versions and BVM

  • Migrating from Single-Version Installer to BVM

  • Troubleshooting

  • Contributing

  • License

  • Support

  • 🌐 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

  • 🎯 Smart version detection - automatically detects actual version numbers from installations

  • 🆙 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.

  • 🔧 Multiple tools - Supports both sha256sum (Linux) and shasum (macOS)

  • Creates appropriate symlinks (only for "latest" - points to the actual version)
    🔗 Smart symlinks - "latest" symlink for convenience, actual versions for clarity
    🚀 Seamless switching - Use bvm use without arguments to activate the project version
    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

  • 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

  • Aliases: bvm mini-server <args>, bvm ms <args>

    Aliases: bvm performance, bvm usage

  • bvm doctor - Check BVM installation health

    • Alias: bvm health

  • bvm help - Show help message

    • Aliases: bvm --help, bvm -h

  • 🗑️
    Version symlinks
    -
    latest
    and other version links
    Submit a pull request
    BVM vs Single-Version Installer
    Features
    Quick Start
    Prerequisites
    apk add --no-cache bash curl
    brew install curl unzip jq openjdk@21
    sudo apt update && sudo apt install curl unzip jq default-jdk
    sudo dnf install curl unzip jq java-21-openjdk
    # Prerequisites automatically installed by installer
    apk add --no-cache bash curl unzip jq openjdk21
    # Java 21 automatically installed with --with-jre option
    # 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
    # Install the latest stable BoxLang version
    bvm install latest
    
    # 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
    # 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
    # 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
    # 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
    # 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 list
    Installed BoxLang versions:
      * latest (current)
        snapshot
        1.1.0
    $ bvm list
    Installed BoxLang versions:
      * 1.2.0 (current)
        latest → 1.2.0
        1.3.0-snapshot
        1.1.0
    # 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
    # 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 examples
    
    # Use latest stable
    latest
    
    # Use specific version
    1.3.0
    
    # Comments (lines starting with #) are ignored
    # Empty lines are also ignored
    # 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
    /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
    # Check if a newer version of BVM is available
    bvm check-update
    $ 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
    # 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
    $ 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
    bvm uninstall
    $ 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
    # Remove system-wide installation
    sudo install-boxlang.sh --uninstall
    
    # Or remove user installation
    install-boxlang.sh --uninstall
    curl -fsSL https://install-bvm.boxlang.io | bash
    # Install the same version you had before
    bvm install latest  # or specific version like 1.2.0
    bvm use latest
    bvm doctor
    boxlang --version
    
    ## 🔧 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
    
    ## 📄 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

    BoxLang TextMate Bundle

    Welcome to BoxLang support for TextMate grammars.

    A comprehensive TextMate bundle that provides rich language support for BoxLang development, including syntax highlighting, code execution, documentation lookup, intelligent code navigation, and extensive code snippets.

    You can find the repository here: https://github.com/ortus-boxlang/boxlang.tmbundle

    🌟 Key Highlights:

    • 315+ Built-In Functions automatically updated from BoxLang API

    • 52+ Code Snippets for rapid development

    • 3 Beautiful Themes with BoxLang's signature green-cyan palette

    • Full HTML Integration in template files (.bxm)

    • Automated CI/CD Pipeline for always up-to-date releases


    Features

    🎨 Syntax Highlighting

    • BoxLang Script (.bx, .bxs) - Full syntax highlighting for BoxLang script files

    • BoxLang Templates (.bxm) - Template syntax with embedded script support and HTML integration

    • HTML Markup Support - Complete HTML syntax highlighting within template files with proper comment handling

    🎭 Custom Themes

    Beautiful themes designed with BoxLang's signature green-cyan gradient colors:

    Theme Dark

    Theme High Contrast

    Theme Light

    • BoxLang Light - Clean, professional light theme with vibrant accents

    • BoxLang Dark - Modern dark theme perfect for extended coding sessions

    • BoxLang High Contrast - Accessibility-focused theme with enhanced readability

    All themes feature:

    • Brand Consistency - Uses BoxLang's signature green-cyan color palette

    • Semantic Highlighting - Different colors for keywords, functions, strings, and components

    • BoxLang-Specific - Special highlighting for bx: components and built-in functions

    🚀 Code Execution

    • Run Current File - Execute the current BoxLang file with a single command

    • Run with Arguments - Execute files with custom command-line arguments

    • Run Selected Code - Execute only the selected code snippet

    • BoxLang REPL - Launch an interactive BoxLang Read-Eval-Print Loop

    ⚡ Code Snippets (52 Available)

    Comprehensive snippet collection for rapid development:

    Core Language Constructs

    • class - Class definition with inheritance and interfaces

    • interface - Interface definition

    • function - Function declaration with modifiers

    Control Flow

    • if / ife - If and if-else statements

    • for / forin - Traditional and for-in loops

    • while / do

    Function Types

    • anon - Anonymous function: function(params) {}

    • closure - Closure with =>: (params) => {}

    • lambda

    Access Modifiers

    • public / private / static / final / abstract / remote - Method and property modifiers

    Data Structures & Collections

    • array / struct - Literal declarations

    • each / seach - Array and struct iteration

    • map / filter

    BoxLang Components

    • bxhttp - HTTP request component

    • bxfile - File operation component

    • bxquery - Database query component

    Development & Testing

    • test - Test case template with Given-When-Then structure

    • doc - JavaDoc comment template

    • todo - TODO comment

    📚 Documentation & Help

    • API Documentation - Quick access to BoxLang API documentation

    • Context-Sensitive Help - Get documentation for the word under cursor

    • Built-in Examples - Sample files demonstrating BoxLang features

    • Auto-Updated BIFs - Built-In Functions automatically extracted from latest API docs

    🧭 Code Navigation

    • Symbol Lists - Navigate through classes, methods, and variables

    • Smart Folding - Intelligent code folding for better readability

    • Go to Symbol - Quick navigation to class definitions and method declarations

    🤖 Automated Release Process

    • CI/CD Pipeline - Automated builds and releases via GitHub Actions

    • Version Management - Automatic version bumping and changelog generation

    • Multi-format Releases - Both .zip and .tar.gz formats available

    Installation

    Prerequisites

    • TextMate 2.0 or later (also compatible with VS Code, Sublime Text, and other TextMate-compatible editors)

    • BoxLang runtime is installed and available in your PATH

    Install via Git

    Install Latest Release

    Recommended: Download the latest stable release for the most up-to-date features and BIF definitions.

    1. Visit the

    2. Download the latest release (available in .zip and .tar.gz formats)

    3. Extract the bundle to ~/Library/Application Support/TextMate/Bundles/

    Install Development Snapshots

    For the latest features and fixes (may be unstable):

    1. Check the for snapshot builds

    2. Download the latest snapshot build

    3. Follow the same extraction steps as above

    Verify Installation

    After installation, verify the bundle is working:

    1. Create a new file with .bx extension

    2. Type class and press Tab - you should see a class template

    3. The syntax should be highlighted in BoxLang colors

    4. ⌘R

    Usage

    File Types Supported

    • .bx - BoxLang script files

    • .bxs - BoxLang script files

    • .bxm - BoxLang template files

    Key Commands

    Execution Commands

    • ⌘R - Run current file

    • ⌘⇧R - Run with arguments

    • ⌃⌘R - Run selected code

    Code Snippets (Tab Triggers)

    • class + Tab - Class definition

    • function + Tab - Function declaration

    • anon + Tab - Anonymous function

    Themes

    The bundle includes three custom themes optimized for BoxLang development:

    Applying Themes

    1. Open TextMate Preferences (⌘,)

    2. Go to the Themes tab

    3. Select from the available BoxLang themes:

      • BoxLang Light - For bright, comfortable daytime coding

    Theme Features

    • Consistent Branding - All themes use BoxLang's signature color palette

    • Syntax-Aware - Distinct colors for keywords, functions, strings, and comments

    • Component Highlighting - Special treatment for bx: components and attributes

    File Templates

    The bundle includes several file templates to help you quickly create new BoxLang files. Access them via File → New From Template → BoxLang:

    • BoxLang Class (.bx) - Basic class template with constructor

    • BoxLang Component (.bx) - Component template with initialization

    • BoxLang Service (.bx) - Service layer template with singleton annotation

    All templates include:

    • Proper file headers with author and date placeholders

    • Basic structure and common patterns

    • Cursor positioning for immediate coding ($0 placeholder)

    Code Examples

    The bundle includes sample files in the Samples/ directory:

    • Class.bxm - Class definition example

    • UserService.bx - Service layer example

    • Scheduler.bx - Task scheduling example

    Configuration

    BoxLang Runtime

    Ensure BoxLang is installed and the boxlang command is available in your PATH. You can verify installation by running:

    Custom Commands

    You can customize the execution commands by editing the .tmCommand files in the Commands/ directory.

    Bundle Development & Maintenance

    Automated Release Pipeline

    The BoxLang TextMate bundle features a sophisticated CI/CD pipeline that ensures always up-to-date releases:

    • Automated BIF Extraction - Built-In Functions are automatically extracted from the latest BoxLang API documentation

    • Version Management - Versions are read from box.json and automatically applied to bundle metadata

    • Multi-Branch Releases - Snapshot builds from development branch, stable releases from main

    Bundle Structure

    Staying Current

    The bundle automatically stays current with BoxLang development:

    • BIF Synchronization - Built-In Functions are extracted fresh from API docs with each release

    • Grammar Updates - Language grammar updated to match BoxLang language evolution

    • Feature Additions - New language features and capabilities added as BoxLang grows

    • Community Feedback - Regular updates based on developer community needs

    Language Features

    Syntax Elements Supported

    • Classes and Interfaces - Full OOP support with inheritance and implementations

    • Methods and Functions - Named functions, anonymous functions, lambda expressions, arrow functions

    • Variables and Scoped Variables - var, final, static declarations with proper scoping

    • Annotations and Metadata - @annotation support with parameter passing

    Advanced Language Features

    • Functional Programming - map, filter, reduce, each operations on collections

    • Concurrency - lock, thread, transaction components

    • Type System - Dynamic typing with optional type hints

    • Module System - import statements with aliasing and module references

    Template Features

    • HTML Integration - Seamless mixing of HTML and BoxLang code

    • Embedded Script Blocks - <bx:script> tags for server-side logic

    • Component Islands - ``` delimited component blocks

    • Tag-based Syntax

    Built-In Functions (BIFs)

    • 315+ Built-In Functions - Automatically extracted from BoxLang API documentation

    • Auto-Updated - BIF list refreshed with each release from official API docs

    • Categorized Functions - Array, String, Math, Date, Decision, Conversion, Struct, Query, System, Cache, Encryption, XML, and Zip functions

    • Intelligent Completion - All BIFs available for syntax highlighting and completion

    Troubleshooting

    BoxLang Command Not Found

    If you receive a "BoxLang command not found" error:

    1. Verify BoxLang is installed: which boxlang

    2. Add BoxLang to your PATH in your shell profile

    3. Restart TextMate after updating your PATH

    Syntax Highlighting Issues

    1. Ensure the file extension is recognized (.bx, .bxs, .bxm)

    2. Manually set the language: View → Language → BoxLang

    3. Reload bundles: Bundles → Bundle Editor → Reload Bundles

    Contributing

    We welcome contributions! Please see CONTRIBUTING.md for guidelines on:

    • Reporting bugs

    • Suggesting features

    • Submitting pull requests

    • Code style guidelines

    Changelog

    See CHANGELOG.md for a detailed history of changes and updates.

    License

    Apache License, Version 2.0.

    Open-Source & Professional Support

    This project is a professional open source project and is available as FREE and open source to use. Ortus Solutions, Corp provides commercial support, training and commercial subscriptions which include the following:

    • Professional Support and Priority Queuing

    • Remote Assistance and Troubleshooting

    • New Feature Requests and Custom Development

    • Custom SLAs

    Visit us at for more information.

    classes

    Dynamic BIF Recognition - Automatically updated Built-In Functions from BoxLang API documentation

  • Modern Language Features - Support for lambda functions, arrow functions, and advanced syntax

  • Eye Comfort - Carefully chosen contrast ratios for reduced eye strain
    property - Property declaration with attributes
  • import - Import statement with module support

  • var - Variable declaration

  • new - Object instantiation

  • - While and do-while loops
  • switch / case / default - Switch statements

  • try / tryf - Try-catch and try-catch-finally blocks

  • break / continue - Loop control statements

  • - Lambda with
    ->
    :
    (params) -> {}
    /
    reduce
    - Functional programming methods
    lock / thread / transaction - Concurrency components
    main - Main method template
  • println / dump - Debugging utilities

  • S3 Distribution - Fast global distribution via AWS S3
  • Snapshot Builds - Development builds from development branch

  • Restart TextMate or reload bundles with Bundles → Bundle Editor → Reload Bundles
    should be available to run BoxLang files
    ⌃H - Show documentation for current word
  • ⌃⌥⌘H - Open BoxLang API documentation

  • closure + Tab - Closure with =>
  • lambda + Tab - Lambda with ->

  • if + Tab - If statement

  • for + Tab - For loop

  • try + Tab - Try-catch block

  • each + Tab - Array iteration

  • bxhttp + Tab - HTTP component

  • test + Tab - Test case template

  • And 44 more snippets for rapid development!

  • BoxLang Dark - For reduced eye strain and night coding

  • BoxLang High Contrast - For maximum accessibility and readability

  • BIF Recognition
    - Built-in functions styled for easy identification
  • Template Support - Optimized for both script and template file types

  • BoxLang Interface (.bx) - Interface template with sample method signature

  • BoxLang Test (.bx) - TestBox-compatible test template

  • BoxLang Script (.bxs) - Executable script template with shebang

  • BoxLang Template (.bxm) - HTML template with embedded BoxLang script

  • generatePrimes.bxs - Algorithm example
  • Input.bx - User input handling

  • Multiple Distribution Channels - Released to both GitHub Releases and AWS S3 for global availability

  • Quality Assurance - All releases include automated testing and validation

  • Components and Templates - bx: prefixed components with attribute support

  • String Interpolation - #variable# expressions within strings

  • Comments - Single-line (//), multi-line (/* */), and documentation (/** */) comments

  • Keywords and Operators - Complete BoxLang keyword set and operator precedence

  • Numbers and Literals - Integer, float, string, boolean, and null literals

  • Collection Literals - Array [] and struct {} literal syntax

  • Control Structures - if/else, for/while/do-while, switch/case, try/catch/finally

  • Component Architecture - Reusable components with attribute binding

    - XML-style component syntax with attributes
  • Expression Interpolation - #expression# evaluation within templates

  • Application Modernization and Migration Services
  • Performance Audits

  • Enterprise Modules and Integrations

  • Much More

  • releases page
    S3 bucket
    BoxLang.io Plans

    JSR-223 Scripting

    Integrate BoxLang into Java applications using JSR-223 Scripting

    🚀 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.

    📋 Table of Contents

    📦 Adding BoxLang to Your Project

    Maven Dependency

    Add BoxLang to your Maven project's pom.xml:

    Gradle Dependency

    For Gradle projects, add to your build.gradle:

    Direct JAR Download

    Download the latest BoxLang JAR from:

    • Releases:

    • Snapshots:

    Add the JAR to your project's classpath:

    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:

    🔧 Architecture Overview

    BoxLang offers complete JSR-223 compliance for seamless integration with JVM applications. Understanding the core components helps Java developers leverage BoxLang effectively.

    💡 Common Use Cases for Java Developers

    Configuration & Rules Engine

    Template Processing

    Data Transformation

    📚 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 ()

    • BoxScopeBindings - Implements the JSR Bindings interface ()

    • BoxScriptingContext - Implements the JSR

    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 so you can declare functions and classes (coming soon) and then execute them from the calling language.

    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

    Discovering Engines

    To find out what engines are available in your platform you can run the following:

    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.

    You can also cast it to our class to get enhanced methods and functionality:

    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.

    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:

    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:

    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:

    Multiple Runtime Instances

    For applications requiring isolated BoxLang environments, you can create separate instances:

    Configuration Override

    You can also override specific configuration settings using system properties or environment variables by prefixing with boxlang. or 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.

    You can use eval with the following signatures

    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.

    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.

    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.

    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.

    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.

    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.

    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.

    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.

    Runtime Source Code

    The runtime source code can be found here:

    We welcome any pull requests, testing, docs, etc.

    🏭 Production Considerations

    Performance Optimization

    Thread Safety

    Error Handling

    🔗 Integration Patterns

    Spring Framework Integration

    Maven Build Integration

    Gradle Build Integration

    Google Chromebooks: Do More Everyday with Google AIgooglechrome

    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

    cd ~/Library/Application\ Support/TextMate/Bundles/
    git clone https://github.com/ortus-boxlang/boxlang.tmbundle.git
    boxlang --version
    boxlang.tmbundle/
    ├── Commands/           # Execution and utility commands
    ├── Preferences/        # Editor behavior and folding rules
    ├── Samples/           # Example BoxLang files
    ├── Snippets/          # 52+ code snippets for rapid development
    ├── Support/           # Utilities and extracted BIF lists
    ├── Syntaxes/          # Language grammar definitions
    ├── Templates/         # File templates for new documents
    └── info.plist        # Bundle metadata and configuration
    Logo
    bxorm.ortusbooks.com
    Common Use Cases for Java Developers
  • Core Scripting Classes

  • BoxLang Home Configuration

  • Production Considerations

  • Integration Patterns

  • ScriptContext
    interface (
    )
  • 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

  • BoxScriptingFactory - implements the JSR ScriptEngineFactory https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/ScriptEngineFactory.html

  • 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.

  • server
    scope
    Getting Started for Java Developers
    Adding BoxLang to Your Project
    Quick Start Example
    Architecture Overview
    https://github.com/ortus-boxlang/BoxLang/releases
    https://s3.amazonaws.com/downloads.ortussolutions.com/boxlang/
    https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/CompiledScript.html
    https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/Bindings.html
    interface
    https://github.com/ortus-boxlang/BoxLang/tree/development/src/main/java/ortus/boxlang/runtime/scripting
    https://docs.oracle.com/en/java/javase/17/docs/api/java.scripting/javax/script/ScriptContext.html
    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, including detailed sections on Executors, BoxFutures, Async Pipelines, Parallel Computations, and Scheduled Tasks.

    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.

    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.

    ⚡Miniserver Updates

    Read all about the new miniserver features in our MiniServer Guide.

    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.

    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 - Complete miniserver setup and configuration

    • Components Guide - In-depth component development

    • Transactions Guide - Database transaction management

    • XML Processing Guide - Working with XML in BoxLang

    • - Configuration and property management

    • - Testing best practices and frameworks

    Comprehensive Asynchronous Programming Documentation

    • Asynchronous Programming Overview

    • Executors - Thread pool management

    • BoxFutures - Future-based programming

    • Async Pipelines - Chaining async operations

    • - CPU-intensive parallel processing

    • - 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 Update the feature audit tool with the correct modules

    BL-1518 Remove all JavaParser dependencies externally unless you check if it exists

    BL-1565 improve error message on expression interpreter

    BL-1566 Handle attempt.orThrow() better

    BL-1571 Support some more natural date parsing masks which aren't case sensitive

    BL-1577 lookup of custom componets and classes refactoring for performance

    BL-1579 String performance and optimizations improvements for toScript() bif

    BL-1581 Bump org.semver4j:semver4j from 5.8.0 to 6.0.0

    BL-1601 avoid calling unputStream.available() due to FusionReactor bug

    BL-1604 make module classes visible to context classloader

    BL-1618 Update jackson-jr to latest patch

    BL-1625 skip type coercion for === operator

    BL-1636 default non-existent request bodies to an empty string

    BL-1642 Ignore extra padding on base64 encoded strings

    BL-1647 remove JSON serialization limit

    BL-1648 Improve JSON serialization of throwable

    BL-1651 org.apache.commons:commons-fileupload2-jakarta-servlet5

    BL-1653 Re-organize and add validation to loaded miniserver config options

    BL-1656 Bump org.apache.commons:commons-text from 1.13.1 to 1.14.0 (#288)

    BL-1657 Bump commons-io:commons-io from 2.19.0 to 2.20.0

    BL-1659 Re-instate parsing errors for unclosed brackets

    Bug

    BL-1214 Documentation of Image module

    BL-1367 BX Compiler Issues

    BL-1415 Cast error on BoxFuture.all()

    BL-1496 Can't cast a Java Array to a modifiable Array.

    BL-1539 DateFormat vs TimeFormat vs DateTimeFormat BIF Separations

    BL-1548 Private static struct function not found

    BL-1555 round does not accept second argument for number of places, despite being documented

    BL-1562 Issue with clone when using zonedatetimes

    BL-1564 dump template for Java class not handling static field

    BL-1567 java boxpiler not always compiling array literal

    BL-1568 JDBC - Unable to execute query in nested transaction unless outer transaction has a query that executes first

    BL-1569 JDBC - Failed to set savepoint... is too long

    BL-1570 date mask when parsing string dates

    BL-1573 Fix for this scope access from function in custom tag

    BL-1575 stack overflow in session shutdown cache interceptor

    BL-1578 ToscriptTest not accounting for the timezone of the tests

    BL-1580 ParseDateTimeTest using non timezone tests and would be unpredictable on certain conditions

    BL-1582 bx:component is missing attributecollection argument

    BL-1584 DateTimeCaster does not handle request timezones Zones correctly

    BL-1585 CFML Compat with partial years

    BL-1587 Different return type when calling `getTime()` on `java.util.GregorianCalendar`

    BL-1588 StructSort numeric not sorting on values

    BL-1589 Regular expression back reference is being ignored

    BL-1592 ASM not compiling self-closing custom components the same as Java boxpiler

    BL-1593 outer loop loses query context after inner loop

    BL-1594 Issue with JSON serialization of dates in a BL class

    BL-1596 session cookie - samesite handling

    BL-1597 ArrayResize does not accept long

    BL-1598 WriteDump Error on Null Array Values

    BL-1606 Compat: DeSerializeJSON strictMapping ignored

    BL-1607 SessionRotate and SessionInvalidate null out JSessionId

    BL-1610 ACF parseDateTime compat

    BL-1611 Casting ortus.boxlang.runtime.types.DateTime to java.util.Date

    BL-1612 outer for loop loses query context with inner for loop

    BL-1613 queryDeleteColumn deletes the column but not the data from the query object

    BL-1615 fileRead should handle relative files

    BL-1616 now isn't being cast to java.util.Date

    BL-1620 Grouped looping is not showing expected output when not inner grouping

    BL-1621 JDBC - Query caching into bx-redis throws 'failed to serialize object'

    BL-1622 Httpparam formfield is adding a break line on values when multipart is true

    BL-1623 FileGetMimeType with strict should be based on file content

    BL-1624 Deserialized Query Columns are Invalid because they no longer contain query reference

    BL-1626 DateTime does not properly deserialize because formatter is transient

    BL-1627 val() with negative value returns 0

    BL-1628 regex replacement backreferences greater than 9 don't wor

    BL-1629 regex upper/lower case escapes should apply to all replacement text

    BL-1630 JDBC race conditions present in threaded (or Future-ed) query execution

    BL-1632 Zip includes target directory as first level parent.

    BL-1633 queryObject.columnnames not supported

    BL-1634 cfcontent is causing files to be corrupted

    BL-1635 java double[] not handled by writeoutput / SerializeJSON

    BL-1639 `max` and `min` member functions missing

    BL-1641 list BIFs have inconsistent support for multiCharacterDelimiter

    BL-1652 PlacehbolderReplacer was not using the String Caster when dealing with map bindings.

    BL-1658 Servlet: Missing UTF-8 encoding for form fields with multipart/form-data

    New Feature

    BL-842 .env support for the BoxLang miniserver

    BL-1464 implement nested grouped output/looping

    BL-1515 Add zipparam support for ZIP functionality

    BL-1525 BoxLang mappings need to have an extra definition: external which defaults to false

    BL-1595 runAsync is the alias, the main method is asyncRun() so we can use the `asyncX` namespace

    BL-1609 asyncAll, asyncAllApply, asyncAny bifs and constructs for parallel programming

    BL-1654 Add simple health checks for miniserver, especially for container based loading

    BL-1655 Basic hidden file protection in MiniServer

    Task

    BL-1576 Refactor customTagsDirectory to customComponentsDirectory and add shim to support it

    BL-1637 Rename thisTag scope to thisComponent scope for consistency and transpile the old scope

    AWS Lambda

    BoxLang Runtime for AWS Lambda! Serverless for the win!

    What is AWS Lambda?

    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

    📋 Table of Contents

    BoxLang Lambda Handler

    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

    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:

    You can see the code for the handler here:

    The handler will look for a Lambda.bxin your package and execute the run()method by convention.

    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

    You can also leverage ANY environment variable to configure the BoxLang runtime using our runtime .

    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: . The structure of the project is the following:

    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

    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

    Building and Testing

    Lambda.bx

    The Lambda function is a BoxLang class with a single function called run().

    Arguments

    It accepts three arguments:

    Argument
    Type
    Description

    You can find more information about the AWS Context object here:

    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 ()

    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 of 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.

    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:

    Connection Pooling

    Database connections are pooled and reused across Lambda invocations:

    Performance Monitoring

    Enable debug mode to get performance metrics:

    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:

    Example Multi-Class Structure

    Each class should implement a run function:

    URI to Class Name Conversion

    The routing follows these conventions:

    • /products → Products.bx

    • /home-savings → HomeSavings.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:

    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.

    Local Development & Testing

    The template provides comprehensive local development and testing capabilities:

    SAM CLI Integration

    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:

    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

    Example configuration:

    Deployment Scripts

    The template provides several deployment scripts:

    GitHub Actions Deployment

    Below is the enhanced GitHub Action that uses the new configuration system:

    The Lambda function will be created automatically via CloudFormation if it doesn't exist, or updated if it does.

    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

    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

    The {functionName} comes from your FUNCTION_NAME configuration setting.

    Log in to the Lambda Console and click on Create function button.

    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

    TIP: If you choose ARM processors, you can save some money.

    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:

    Now important, let's choose the AWS Lambda Runtime Handler in the Edit runtime settings

    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.

    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+.

    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!

    Runtime Source Code

    The AWS Runtime source code can be found here:

    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

    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

    We welcome any pull requests, testing, documentation contributions, and feedback.

    1.6.0

    October 3, 2025

    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

    <dependency>
        <groupId>io.boxlang</groupId>
        <artifactId>boxlang</artifactId>
        <version>1.5.0</version>
    </dependency>
    dependencies {
        implementation 'io.boxlang:boxlang:1.5.0'
    }
    # Compile with BoxLang
    javac -cp "boxlang-1.5.0.jar:." MyApp.java
    
    # Run with BoxLang
    java -cp "boxlang-1.5.0.jar:." MyApp
    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 );
        }
    }
    // 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 );
    // 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 );
    // 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 );
    ScriptEngineManager mgr = new ScriptEngineManager();
    List<ScriptEngineFactory> factories = mgr.getEngineFactories();
    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();
    BoxScriptingEngine engine = (BoxScriptingEngine) new BoxScriptingFactory().getScriptEngine();
    import ortus.boxlang.runtime.scripting.BoxScriptingFactory;
    
    ScriptEngine engine = new BoxScriptingFactory().getScriptEngine( true );
    {user.home}/.boxlang/
    // 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
    // Access runtime configuration through the engine
    BoxScriptingEngine boxEngine = ( BoxScriptingEngine ) engine;
    BoxRuntime runtime = boxEngine.getRuntime();
    // Configuration is automatically loaded from {BOXLANG_HOME}/config/boxlang.json
    // 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
    // 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" );
    boxlang.eval( "println( 'hello world' )" )
    /**
     * 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 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" );
    engine.eval( """
        function sayHello( name ) {
            return 'Hello, ' & name & '!'
        }
    """);
    
    Invocable	invocable	= ( Invocable ) engine;
    Object		result		= invocable.invokeFunction( "sayHello", "World" );
    assertThat( result ).isEqualTo( "Hello, World!" );
    // 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 );
    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" );
    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();
    // 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();
    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 );
    // 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...
    }
    // 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 );
        }
    }
    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() );
        }
    }
    @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 );
            }
        }
    }
    <!-- 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>
    // 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
    // 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
    // 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" );
    }
    bx:loop( query="salesData", group="region,quarter" ) {
        writeOutput( "<h2>#region# - #quarter#</h2>" );
    
        bx:loop() {
            writeOutput( "<p>Sale: #amount# on #date#</p>" );
        }
    }
    # .env file
    DATABASE_URL=jdbc:mysql://localhost:3306/mydb
    API_KEY=your-secret-key
    DEBUG_MODE=true
    Property Files Guide
    Testing Guide
    Parallel Computations
    Scheduled Tasks
    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

  • Lambda.bx
  • Performance Enhancements

  • Convention-Based URI Routing

  • Multiple Functions Header

  • Lambda Modules

  • Local Development & Testing

  • Deploy to AWS

  • Runtime Source Code

  • 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

  • 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

  • Pascal case routing patterns

  • Configuration management

  • Testing strategies and file locations

  • This enables more accurate and contextual assistance when developing BoxLang Lambda functions.

    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 for the function.

  • /user_profile → UserProfile.bx

  • AWS_LAMBDA_BUCKET - S3 bucket for deployment artifacts

    Enhanced Error Handling: Better error messages and stack traces

  • Configuration Flexibility: Hierarchical configuration system

  • SAM Integration: Full AWS SAM support for local development

  • Static Initialization: Use static blocks for expensive one-time setup

  • Early Returns: Validate input early and return immediately on errors

  • 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

    event

    Struct

    All the incoming JSON as a BoxLang struct

    context

    com.amazonaws.services.lambda.runtime.Context

    The AWS context object. You can find much more information here.

    response

    Struct

    A BoxLang struct convention for a response.

    What is AWS Lambda?
    BoxLang Lambda Handler
    Environment Variables
    BoxLang AWS Template
    https://github.com/ortus-boxlang/boxlang-aws-lambda/blob/development/src/main/java/ortus/boxlang/runtime/aws/LambdaRunner.java#L161
    environment conventions
    https://github.com/ortus-boxlang/boxlang-starter-aws-lambda
    https://docs.aws.amazon.com/lambda/latest/dg/java-context.html
    https://docs.aws.amazon.com/lambda/latest/dg/java-context.html
    version
    https://github.com/ortus-boxlang/boxlang-aws-lambda
    AWS Lambda Console
    Create a function
    Upload Test Code
    Code Uploaded
    📚 BoxLang Documentation MCP Server

    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

    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.

    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

    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.

    🤖 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:

    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 Update the feature audit tool - Part 2

    BL-1735 Bad link on dateformat in docs

    BL-1741 Performance optimizations for DateTime class

    BL-1742 HTTP Param - Change URL param handling to Encode Always

    BL-1747 defer intercept data creation based on hasState()

    BL-1748 avoid synchronized modifier on singleton getInstance() methods

    BL-1749 Convert context config to non-concurrent maps for performance

    BL-1750 assorted small performance fixes

    BL-1752 Disable JDBC connection leak detection by default

    BL-1753 Add weak reference disk class caching

    BL-1754 Cache Application descriptor lookups when trusted cache is enabled

    BL-1755 Provide overloaded internal expandpath method for known mappings to avoid context.getConfig()

    BL-1758 bx:cookie did not try to process `expires` as a date before a string

    BL-1765 Improve exception handling on miniserver when arguments are invalid

    BL-1767 Added verbose mode to the cftranspile command to see issues or potential data

    BL-1775 calling getCachedObjectMetadata registers as a hit

    BL-1785 Improve type names in error messages

    BL-1786 modify getInstance pattern in ASM compiler to avoid method-level synchronization

    BL-1793 Configuration mappings registration needs to be updated to detect between a simple and a complex mapping

    BL-1794 Add `context` to intercept data whenever you can find interception calls that require it

    BL-1795 The key to the datasource needs to be searched for env replacements in the configuraiton

    BL-1802 Update feature audit to output list of missing modules

    BL-1805 return STOMP heartbeat responses from miniserver

    Bugs

    BL-1586 ImageRead does not expand the path

    BL-1672 imageRead with URIs

    BL-1690 When using compatibility mode and set to Lucee, handling of unquoted keys in json is not consistent with Lucee.

    BL-1695 duplication util doesn't use correct class loader when serializing classes

    BL-1710 Cannot use structKeyExists on closure

    BL-1727 small files not uploaded in servlet

    BL-1729 Compare Operations Should Not Use Collations unless Locale Sensitivity is Specified

    BL-1731 Change Deprecated Uses of StringUtils compare and contains functions to use new Strings API

    BL-1732 number caster doesn't trim spaces on incoming strings

    BL-1736 Native toString output of ZonedDateTime object not being parsed/cast correctly

    BL-1737 HTTP Component not returning result if `file` and `path` are specified

    BL-1738 File/Path compat differences between BL/Lucee/Adobe

    BL-1739 Add Immutability Flag to DateTime Objects to Prevent Timezone Mutation on Format

    BL-1740 Inconsistent default formats between parsed date results

    BL-1743 Can't create application caches on Windows

    BL-1744 Ensure Two-Digit Year is Always Assumptive of Current Millenium in Date Parsing

    BL-1745 Dates with Mask `yyyy/M/d` are not parsed natively

    BL-1751 cache component announcing wrong interception point

    BL-1756 Compat behavior - ListDeleteAt should retain leading delimiters

    BL-1763 CF compat nulls need to equal empty string

    BL-1766 Compat: IsValid does not support `number` as a type

    BL-1769 XMLAttribute usage on node produced by XMLElemNew Throws Error

    BL-1771 Empty xmlNew Result produces an XML object with no node

    BL-1776 ASM bug on loading a pre-compiled class when doing renaming of identifiers: illegalArgumentException null

    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 boxlang run compiled template gets confused when doing shebang detection

    BL-1784 pre-compiled classes not getting their name metadata set properly

    BL-1789 bx-mariadb throwing NPE checking for results on DDL statement

    BL-1797 Extra space in tag close not parsing

    BL-1798 Use of return keyword as variable

    BL-1799 Use of component keyword as annotation name

    BL-1800 FQN starting with _

    BL-1801 property shortcut with FQN as type

    BL-1803 Parsing fails on files with multiple BOMs

    BL-1804 Compat - For DateFormat BIF treat all `m` letters as `M`

    New Features

    BL-1498 Enhance executor stats

    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 ExecutorRecord becomes a class BoxExecutor due to instance data required for stats and health metrics

    BL-1726 Enhance BoxLang BoxExecutor with Health Monitoring, Activity Tracking, and Advanced Statistics

    BL-1746 Bump com.amazonaws:aws-lambda-java-core from 1.3.0 to 1.4.0

    BL-1760 this.mapping for modules needs to support simple string and a struct of mapping options

    BL-1762 Introduce this.publicMapping for modules to allow for public mapping by convention

    BL-1764 Repl Improvements + MiniConsole Framework

    BL-1779 Adding a description to the BoxBif and BoxComponent annotations for short inline descriptions

    BL-1780 Add a boxlang-miniserver --version to spit out the version information

    BL-1783 BIFS and Components now include a runtime description

    Tasks

    BL-1759 remove unused variables in the module record that's not implemented

    ortus.boxlang.runtime.aws.LambdaRunner::handleRequest
    Lambda.bx
    class {
    
        function run( event, context, response ){
    
    
        }
    
    }
    /.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
    # 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
    /**
     * My BoxLang Lambda
     */
    class{
    
    	function run( event, context, response ){
    		response.body = {
    			"error": false,
    			"messages": [],
    			"data": "====> Incoming event " & event.toString()
    		};
    		response.statusCode = 200;
    	}
    }
    response : {
      statusCode : 200,
      headers : {
        content-type :  "application/json",
        access-control-allow-origin : "*",
      },
      body : YourLambda.run() results
    }
    /**
     * 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 ]
        };
      }
    
    }
    // Your Lambda classes are compiled once and cached
    class {
        function run( event, context, response ) {
            // This class is cached after first compilation
            return processEvent( event );
        }
    }
    // 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;
    }
    # Set environment variable for performance monitoring
    BOXLANG_LAMBDA_DEBUGMODE=true
    // URL: /products -> Products.bx
    // URL: /home-savings -> HomeSavings.bx
    // URL: /user-profile -> UserProfile.bx
    /src/main/bx/
      ├── Lambda.bx          # Default handler (fallback)
      ├── Products.bx        # Handles /products
      ├── HomeSavings.bx     # Handles /home-savings
      └── UserProfile.bx     # Handles /user-profile
    // 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" }
            ];
        }
    }
    x-bx-function=methodName
    # 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
    # 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
    // Example from LambdaRunnerTest.java
    @Test
    public void testLambdaExecution() {
        LambdaRunner runner = new LambdaRunner();
        String result = runner.handleRequest(sampleEvent, testContext);
        assertThat(result).contains("success");
    }
    # Create your local configuration
    cp workbench/config.env workbench/config.local.env
    
    # Edit your settings
    vim workbench/config.local.env
    # 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
    # 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
    - 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' }}
    // 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
    // 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...
    // 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
        }
    }
    @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 {
        // ...
    }
    Not found
    Scripting for the Java Platformwww.oracle.com
    ortus.boxlang.runtime.scripting (boxlang 1.0.0 API)s3.amazonaws.com
    API Documentation
    Scripting for the Java PlatformWikipedia

    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:

    BoxLang now caches compiled lambda classes to avoid expensive recompilations on subsequent invocations, dramatically improving cold start performance.

    Configurable Connection Pooling

    Ticket:

    Control AWS runtime connection pool size via the new environment variable:

    Performance Metrics Logging

    Ticket:

    Enable detailed performance metrics in debug mode to monitor Lambda execution times and resource usage.

    Convention-Based URI Routing

    Ticket:

    Automatic routing using PascalCase conventions. You can now build multi-class Lambda functions with BoxLang easily following our conventions.


    🔧 Core Runtime Improvements

    Enhanced File Upload Support

    Tickets: ,

    FileUpload now includes blockedExtensions argument and correctly populates file name properties:

    Improved Error Handling for Primitive Returns

    Ticket:

    Better error messages when proxied UDFs return null where primitives are expected:

    Memory Leak Prevention

    Ticket:

    Enhanced thread management prevents memory leaks with unbounded thread usage in long-running applications.

    Virtual Thread Support for Parallel Operations

    Ticket:

    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.

    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:

    Type
    Methods

    📊 Database & Query Enhancements

    Multiple SQL Statement Support

    Ticket:

    QueryExecute now properly handles multiple SQL statements:

    Enhanced Generated Key Capture

    Ticket:

    Update Count Tracking

    Ticket:

    Improved Parameter Handling

    Ticket:

    Better handling of queries with both loose colons and positional parameters:


    🔗 Java Interoperability Improvements

    Better Method Resolution

    Ticket:

    Improved matching for overloaded Java methods:

    Ticket:

    Better preference handling when Java methods accept Object arguments:


    🏗️ CFML Compatibility Enhancements

    Script Custom Tag Support

    Ticket:

    Added support for Adobe ColdFusion script-based custom tags:

    Encrypted Datasource Password Support

    Ticket:

    Support for Lucee-style encrypted datasource passwords:

    Component Name Annotation Fix

    Ticket:

    The name annotation on components now correctly sets metadata without overwriting:


    🛠️ Developer Experience Improvements

    Enhanced List Functions

    Ticket:

    List BIFs now preserve custom delimiters when reassembling:

    Tickets: ,

    Duration objects can now be compared with integers and other numeric values:

    Class Metadata Enhancement

    Ticket:

    Box Class metadata now includes "output" key for better introspection:


    🐛 Notable Bug Fixes

    Query of Queries Parsing

    Ticket: Fixed parsing errors in Query of Queries when using parentheses in expressions.

    Super Reference Resolution

    Ticket: Corrected super reference resolution for mixin UDFs in parent classes.

    HTTP Header Handling

    Ticket: Resolved HTTP errors when Accept-Encoding and TE headers are set as HTTP parameters.

    Module Management

    Ticket: Fixed module unload process to properly remove and unregister module resources.

    Thread Context Handling

    Ticket: Ensured threads consistently use the correct context classloader.

    SQL Formatting

    Ticket: 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:

    Resolved collision between Docker env var BOXLANG_MODULES and the config modules key.

    Cache Settings

    Ticket:

    Cache settings now properly replaced by environment variables:


    ⚡ 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

    Bump org.semver4j:semver4j from 5.8.0 to 6.0.0.

    fileUpload missing blockedExtensions argument

    Better error if proxied UDF returns null where primitive is expected

    add "output" key to Box Class Meta

    Add `Virtual` Argument to BIF supporting parallel operations

    DynamicObject not unwrapping arguments passed to method

    Remove query column map from query metadata

    Prevent memory leak with unbounded thread usage

    Capture all generated keys

    Capture update counts

    AWS Runtime - Cache compiled lambda classes to avoid recompilations

    AWS Runtime - Add aws runtime pool configuration via new ENV variable: BOXLANG_LAMBDA_CONNECTION_POOL_SIZE which defaults to 2

    Bugs

    queryExecute multiple statements

    List BIFs which reassemble the list don't preserve delimiters

    queryExecute - cannot execute query containing loose ':' and positional parameters

    fileUpload: serverFileName, serverFile, clientFile, clientFileName are not correct per the spec

    Interop service when dealing with methods with `Object` arguments, would give preference to coercionable arguments. Ex: Formatter.format( BoxLang DateTime ) would fail

    Trying to load module class before module is registered errors

    duration can't compare against an integer

    Compare operator cannot cast Duration to Number

    JDBC - "driver not registered" log on engine startup despite being installed

    Miniserver: Docker env var BOXLANG_MODULES collides with modules key in config

    super reference incorrect for mixin UDF in parent class

    string caster not obeying fail flag when inputStream errors

    HTTP Error When Accept-Encoding and TE Headers are being set as HTTP Params

    Parsing error in QoQ with parentheses

    Missing support for ACF script custom tags

    Ignore extraneous return values from void proxies

    Usage of quoted operators fails to compile.

    sqlPrettify is broken

    CFML Compat - `name` annotation on Component overwrites the metadata name

    Threads not always using context classloader

    JDBC not handling raised errors

    Module unload fails to remove/unregister module resources

    Issues with numberFormat masks

    Cache settings do not get replaced by environment variables

    Java interop matching in correct overloaded methods

    New Features

    Add support for Lucee's encrypted datasource passwords in compat

    AWS Runtime - Log performance metrics when in debug mode

    AWS Runtime - URI Routing by convention using PascalCase: /products -> Products.bx, /home-savings -> HomeSavings.bx

    Array

    arrayEach(), arrayEvery(), arrayFilter(), arrayMap(), arrayNone(), arraySome()

    List

    listEach(), listEvery(), listFilter(), listMap(), listNone(), listSome()

    Query

    queryEach(), queryEvery(), queryFilter(), queryMap(), queryNone(), querySome()

    Struct

    structEach(), structEvery(), structFilter(), structMap(), structNone(), structSome()

    BL-1712
    BL-1716
    BL-1713
    BL-1714
    BL-1664
    BL-1663
    BL-1680
    BL-1697
    BL-1687
    BL-1186
    BL-1700
    BL-1701
    BL-1661
    BL-1715
    BL-1667
    BL-1679
    BL-1127
    BL-1684
    BL-1660
    BL-1669
    BL-1670
    BL-1686
    BL-1678
    BL-1674
    BL-1676
    BL-1705
    BL-1696
    BL-1683
    BL-1673
    BL-1709
    BL-1556
    BL-1664
    BL-1680
    BL-1686
    BL-1687
    BL-1688
    BL-1693
    BL-1697
    BL-1700
    BL-1701
    BL-1712
    BL-1716
    BL-1186
    BL-1660
    BL-1661
    BL-1663
    BL-1667
    BL-1668
    BL-1669
    BL-1670
    BL-1671
    BL-1673
    BL-1674
    BL-1675
    BL-1676
    BL-1678
    BL-1679
    BL-1681
    BL-1682
    BL-1683
    BL-1684
    BL-1696
    BL-1699
    BL-1705
    BL-1706
    BL-1709
    BL-1715
    BL-1127
    BL-1713
    BL-1714
    // 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 ) )
        };
    }
    # Set connection pool size (defaults to 2)
    BOXLANG_LAMBDA_CONNECTION_POOL_SIZE=2
    // 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()
        };
    }
    // 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 );
    // Before: Cryptic casting error
    // After: Clear error message
    function getScore() {
        return; // null return
    }
    
    numeric score = getScore(); // Now provides clear error about null->numeric conversion
    // 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", "[email protected]" ],
        [ 2, "Jane", "[email protected]" ],
        [ 3, "Bob", "[email protected]" ]
    ] );
    
    // 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
    // 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" }
    } );
    // 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 );
    // 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" );
    // 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 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"
    // 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 );
    // 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";
    // BoxLang.json datasource configuration
    {
        "datasources": {
            "myDB": {
                "driver": "mysql",
                "host": "localhost", 
                "database": "myapp",
                "username": "dbuser",
                "password": "encrypted:ABC123DEF456", // Encrypted password support
                "port": 3306
            }
        }
    }
    /**
     * @name CustomService
     * @description Provides custom business logic
     */
    component {
        // Component metadata.name is now correctly set to "CustomService"
        
        function init() {
            return this;
        }
    }
    // 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
    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
    metadata = getMetadata( myComponent );
    if ( metadata.output ) {
        writeOutput( "Component generates output" );
    }
    # Environment variables now correctly override cache settings
    BOXLANG_CACHE_DEFAULT_TIMEOUT=3600
    BOXLANG_CACHE_MAX_ELEMENTS=1000
    Not found

    CLI Scripting

    The core runtime allows you to build CLI scripting applications

    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 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

    BoxLang will automatically detect and run the correct entry point, including shebang scripts and classes with a main() method.

    Script Files

    With BoxLang, you can execute a few types of files right from any OS CLI by adding them as the second argument to our boxlangbinary:

    File
    OS
    Hint

    Please note that you will need the bx-compat-cfmlmodule if you want to execute CFML scripts

    Here are some examples of executing the files. Just pass in the file by relative or absolute path location.

    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.bxfile 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

    For CLI applications, we recommend you use the serveror request scope for singleton persistence. Also note that you can use all the as well for persistence. You can use applicationscope if you have an Application.bx.

    Executing Classes

    BoxLang allows you to execute any *.bxclass 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 argsargument.

    The argsargument is an array and it will contain all the arguments passed to the execution of the class.

    If you execute this function above, the output will be:

    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 *.bxsscripts 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.

    Then, if we execute it, we can see this output:

    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

    You can also get the arguments via the server.cli.parsedvariable, which already contains this structure.

    Here is the output:

    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.)

    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.

    A SheBang script is just basically a *.bxsscript.

    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 boxlangbinary 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.

    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

    Environment Variables

    You can also control BoxLang behavior using environment variables:

    Environment Variable
    Description

    Examples of CLI Options

    Action Commands

    BoxLang includes several powerful action commands for development workflows:

    Compile Command

    Pre-compile BoxLang templates to class files for improved performance:

    CF Transpile Command

    Transpile ColdFusion code to BoxLang syntax:

    Feature Audit Command

    Audit your code for BoxLang feature compatibility:

    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:

    CLI-Specific Information

    When running in CLI mode, additional CLI-specific information is available:

    Inline Code Execution

    You can execute BoxLang code directly from the CLI using the --bx-code flag:

    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.

    For more on schedulers, see the .

    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

    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

    Please note that you have a wealth of built-in functions and components that you can use to build your scripts.

    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

    Multi-Character Shorthand Options

    You can combine multiple single-character options:

    Parsing Examples

    For the following CLI command:

    The parsed structure will be:

    Accessing Parsed Arguments

    Advanced CLI Information

    The server.cli structure provides comprehensive CLI context:

    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-

    Reading Input

    You can easily read input from users by using our handy CLIRead( )bif. You can also pass in a promptas part of the method call.

    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)

    I get the output:

    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.

    You can now call it with zero or more arguments!

    Piping code

    You can also pipe statements into the BoxLang binary for execution as well. This assumes script, not tags.

    or

    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:

    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

    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.

    For more on modules and conventions, see the .

    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:

    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:

    Your CLI scripts and classes can then use any embedded modules as if they were installed globally.

    For more on embedding and using modules, see the .

    Additional Resources and Examples

    Modern Development Workflow

    BoxLang's CLI capabilities make it ideal for modern development workflows:

    Usage:

    Integration Examples

    BoxLang CLI can integrate with various tools and workflows:

    Performance and Debug Information

    When using --bx-debug, BoxLang provides detailed performance metrics:

    This outputs:

    • Execution timing information

    • Memory usage statistics

    • Runtime initialization details

    • AST parsing time

    Community Resources

    • 📚 Documentation:

    • 💬 Community Forum:

    • 💾 GitHub Repository:

    • 🌐 Official Website:

    Dad Joke Script

    Thanks to our evangelist Raymond Camden, we have a cool dad joke script you can find in our demos:

    Now you execute it

    Let's modify it now so that we can prompt the user for the term using the CLIRead( )BIF instead of passing it:

    *.cfs / *.cfm — CFML script/template (requires bx-compat-cfml module)

  • *.sh — Shebang script (with #!/usr/bin/env boxlang)

  • *.cfm

    All

    CFML templates (If using the bx-compat-cfmlmodule)

    *.sh

    Mac + *Nix

    Shebang scripts using boxlangas the environment

    - 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.

    --bx-printAST

    Print Abstract Syntax Tree for code analysis

    --bx-transpile

    Transpile BoxLang code to Java

    CLIExit( [ exitCode=0 ] )- Do a System.exit( )with the passed-in exit code

    -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

    prefix
  • Values can be assigned with = and optionally quoted

  • Repeated options will override previous values

  • Everything after options are treated as positional arguments

  • writeDump( )- Takes any incoming output and will serialize to a nice string output representation. This will also do complex objects deeply.

    Module loading performance

    🎯 Examples Repository: https://github.com/ortus-boxlang/bx-demos

    *.bx

    All

    BoxLang classes with a main()method

    *.bxs

    All

    BoxLang scripts

    *.bxm

    All

    BoxLang Templating Language

    *.cfs

    All

    CFML scripts (If using the bx-compat-cfmlmodule)

    -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

    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

    --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'

    BoxLang CLI Entry Points & Conventions
    Script Files
    Other Scopes
    Executing Classes
    Executing Scripts / Templates
    SheBang Scripts
    BoxLang CLI Options and Flags
    Action Commands
    Runtime Mode Detection
    Inline Code Execution
    Scheduler Files
    REPL Mode
    CLI Built-In Functions
    Parsed Arguments
    Reading Input
    Producing Output
    Piping code
    Module CLI Apps
    Embedding Modules in a CLI App
    Additional Resources and Examples
    caches
    Scheduler documentation
    BoxLang Modules documentation
    BoxLang Modules documentation
    https://boxlang.ortusbooks.com/
    https://community.ortussolutions.com/c/boxlang/42
    https://github.com/ortus-boxlang
    https://boxlang.io
    https://github.com/ortus-boxlang/bx-demos
    boxlang task.bx
    boxlang myscript.bxs
    boxlang mytemplate.bxm
    
    boxlang /full/path/to/test.bxs
    boxlang /full/path/to/Task.bx
    boxlang.bat task.bx
    boxlang.bat myscript.bxs
    boxlang.bat mytemplate.bxm
    java -jar boxlang-1.0.0.jar task.bx
    java -jar boxlang-1.0.0.jar /full/path/to/test.bxs
    task.bx
    class {
    
        function main( args = [ ] ) {
            println( "Hola from my task! #now()#" );
            println( "The passed args are: " );
            println( args );
        }
    
    }
    boxlang task.bx hola --many options=test
    Hola from my task! { ts '2025-02-11 22:15:44' }
    The passed args are:
    [
      hola,
      --many,
      options=test
    ]
    hello.bxs
    message = "Hola from my task! #now()#";
    println( message );
    println( "The passed args are: " );
    println( CLIGetArgs( ) );
    ╰─ 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
      }
    }
    message = "Hola from my task! #now()#";
    println( message );
    println( "The passed args are: " );
    println( server.cli.parsed );
    ╰─ 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
      }
    }
    hola.sh
    #!/usr/bin/env boxlang
    
    println( "Hello World! #now()#" );
    println( CLIGetArgs( ) );
    # Execute the script
    ./hola.sh
    
    # Execute it with a name argument and a simple option
    ./hola.sh --name=luis -d
    # 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 code analysis
    boxlang --bx-printAST --bx-code "x = 1 + 2"
    
    # Combined options
    boxlang --bx-debug --bx-config ./custom.json myapp.bx
    # Get help for compile command
    boxlang compile --help
    
    # Compile source directory to target
    boxlang compile --source ./src --target ./compiled
    # Get help for cftranspile command
    boxlang cftranspile --help
    
    # Transpile legacy CF code to BoxLang
    boxlang cftranspile --source ./legacy --target ./modern
    # Get help for featureaudit command
    boxlang featureaudit --help
    
    # Audit code and generate report
    boxlang featureaudit --source ./myapp --output report.json
    // Check if running in CLI mode
    if ( server.boxlang.cliMode ) {
        println( "Running in CLI 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 );
    // 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( ) );
    boxlang --bx-code "println( 'Hello from BoxLang!' )"
    boxlang schedule ./schedulers/MainScheduler.bx
    # Start REPL mode
    boxlang
    
    # You'll see the REPL prompt
    BoxLang> println( "Hello from REPL!" )
    Hello from REPL!
    BoxLang>
    # This creates: a=true, b=true, c=true
    boxlang myscript.bxs -abc
    boxlang myscript.bxs --debug --!verbose --config=prod.json -o='/path/to/file' -v my/path/template
    {
      "options": {
        "debug": true,
        "verbose": false,
        "config": "prod.json",
        "o": "/path/to/file",
        "v": true
      },
      "positionals": [ "my/path/template" ]
    }
    // 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 );
    } );
    // 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( ) );
    var exit = cliRead( "Do you want to continue? (Y/N)" ).trueFalseFormat( );
    if ( exit ) {
      cliExit( );
    }
    println( "Time is #now()#" );
    ╰─ boxlang test.bxs
    Time is { ts '2024-05-22 22:09:56' }
    class {
    
            function main( args=[ ] ) {
    
                   println( "Task called with " & arguments.toString( ) );
    
                    writedump( args );
    
            }
    
    }
    ╰─ boxlang Task.bx
    Task called with { ARGS=[ ] }
    
    ╰─ boxlang Task.bx boxlang rocks
    Task called with { ARGS=[ boxlang, rocks ] }
    echo "2+2" | java -jar boxlang-1.0.0.jar
    echo "2+2" | boxlang
    # 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
    boxlang module:mytools arg1 --option=value
    class {
    
        function main( args = [ ] ) {
            println( "Module CLI called with args:" );
            writedump( args );
            // Your CLI logic here
        }
    
    }
    install-bx-module bx-pdf bx-image --local
    mycliapp/
      myscript.bxs
      boxlang_modules/
        bx-pdf/
        bx-image/
    // 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
        }
    }
    # Development mode with debug
    boxlang --bx-debug example-workflow.bx --env=development --debug
    
    # Production mode
    boxlang example-workflow.bx --env=production
    # 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
    boxlang --bx-debug myapp.bx
    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 );
        }
    
    }
    // Random joke
    boxlang DadJoke.bx
    
    // Term jokes
    boxlang DadJoke.bx ice
    var term = ( CLIRead( "What search term would you like to use? (Leave blank for random joke)" ) ).trim( );
    Logo

    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.

    If you are a CFML developer, check out also our

    MiniServer

    BoxLang includes a lightning fast web server powered by Undertow!

    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 desire a more robust and feature-rich servlet server implementation, we offer our open-source FREE and with a BoxLang Subscription.

    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.

    Logo
    📋 Table of Contents
    • Dynamic & Loose Typing

    • Any by default

    • High Precision Mathematics

    • Numeric Literal Separators

    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.

    File Types:

    • bx - A BoxLang class

    • bxs - A BoxLang scripting file

    • bxm - A BoxLang templating markup file

    You can also add types to arguments within functions or omit them, and it will default to any, which means, well, anything:

    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:

    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.

    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.

    You can change this setting in the configuration to false and it will use basic Double mathematics and it will be up to you when to use high precision evaluations.

    You can store a larger number like:

    in a Double, but behind the scenes, not all of that is stored. All Java tracks is

    which means some digits of the original number are gone. So, if you run the math equation

    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:

    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.

    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

    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:

    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:

    and in the exponent of scientific notation

    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

    Internally we leverage a Key class that provides us with case insensitivity. Each map has a Key as the, well, key.

    BIFs = Built-In Functions

    BoxLang is inspired by many languages and offers 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.

    Please check out the reference section for all the contributed core BIFs.

    To get a sense of all the BIFs registered in your runtime, do a

    writedump( getFunctionList() ) or println( getFunctionList() )

    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).

    You can find all the collection of member functions in our types section.

    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 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.

    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.

    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 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.

    Multi-Line Strings

    In Java, you can declare a multi-line string easily (JKD15+) by using the triple (""") quote marks.

    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!

    Multi-Variable Assignments

    BoxLang supports the concept of multi-variable declaration and assignments by just cascading variables using the = operator.

    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

    Catch `any` exception

    BoxLang allows you to catch any exception using our any operator

    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:

    No Semicolons, almost

    Semicolons are almost always optional except in some situations:

    • property definitions in classes

    • Component calls with no body

    • Component child calls

    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.

    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)

    Please visit our scopes section to find out much more about scopes in BoxLang.

    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:

    Check out our 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.

    You can also use our handy 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 on our operator's page.

    Symbol Operator
    Human Operator
    Hint

    ==

    eq

    !=, <>

    neq

    >

    gt

    >=

    gte

    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.

    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.

    Tip: Also remember you can nest arrays into structs and structs into arrays

    Trailing Commas

    BoxLang supports trailing commas when defining array and struct literals. If you miss a dangling comma, we won't shout at you!

    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

    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.

    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)

    You can also remove the java: prefix and BoxLang will try to locate the class for you. Careful, as it will scan all locations.

    Import Aliases

    You can also alias imports to provide less ambiguity when dealing with classes with the same name:

    All the object resolvers prefixes can be used anywhere a class or path is expected:

    • Creating classes and instances: createObject(), new

    • Using imports

    • Extending classes

    • Implementing interfaces

    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.

    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

    Imagine how tedious this code is

    Now let's transform this code:

    Assert

    BoxLang offers an assert operators that will evaluate an expression and if the expression is falsey it will throw an assert exceptions.

    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.

    Let's write up another script that leverages closures and lambdas.

    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:

    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.

    Default Arguments

    You can create defaults for arguments, which can be literal or actual expressions:

    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.

    This is a great time saver.

    Auto-casting Arguments & Return Values

    In BoxLang, we actively cast the incoming argument value to the specified declared argument.

    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.

    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 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];

    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.

    Check out our 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

    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.

    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.

    If you create your own init() then it's your job to initialize your class :)

    Annotations

    BoxLang annotations can be added to properties, functions, and classes. Using the following pattern:

    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.

    Tip: Remember that string literals you can use quotes, single quotes or none.

    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.

    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.

    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.

    CFML Guide.

    CommandBox is our open-source servlet server implementation. However, with a Boxlang +/++ subscription, it becomes a powerhouse for mission-critical applications. Check out all that you get with CommandBox Pro: https://www.ortussolutions.com/products/commandbox-pro

    📋 Table of Contents

    • Start a Server

    • JSON Configuration

    • Security Features

    • Health Check Endpoints

    ▶️ Start a Server

    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, 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.

    Please note that our VSCode BoxLang Extension can also assist you in managing and starting/stopping servers.

    Once you run the command, the following output will appear in your console:

    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 system properties

    • Built-in security protection - Blocks access to hidden files and directories (starting with .) for security

    • WebSocket support enabled by default at /ws endpoint

    • This configures the web server with some default welcome files and no rewrites.

    • BoxLang will process any BoxLang or CFML files

    • Uses the user's BoxLang home as the default for configuration and modules: ~/.boxlang

    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).

    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.

    Command Palette
    Manage your Servers

    📋 JSON Configuration

    The BoxLang MiniServer supports loading configuration from a JSON file. This allows you to store all server settings in one place instead of passing them as command-line arguments every time.

    Automatic Loading

    If you run boxlang-miniserver with no arguments, it will automatically look for a miniserver.json file in the current directory:

    Explicit Path

    You can also specify the path to a JSON configuration file:

    Override with CLI

    Command-line arguments always override JSON configuration:

    Configuration Options

    All the following options are supported in the JSON configuration file:

    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

    Example Configuration Files

    Basic Configuration

    Development Configuration

    Production Configuration

    Complete Configuration

    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 current directory) or absolute

    • Environment variables are loaded as system properties and can be used throughout the application

    Example:

    or

    🔧 Arguments

    These are the supported arguments you can pass into the binary to configure the server.

    Argument
    Value

    --configPath path/boxlang.json -c path/boxlang.json

    Relative/Absolute location of the boxlang.json to use. By default it uses the ~/.boxlang/boxlang.json

    --debug -d

    Put the runtime into debug mode. This will also render detailed error messages in the browser. By default we use false

    --help -h

    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)

    --port 8080 -p 8080

    The port to bind the mini server to. By default we use port 8080

    --rewrites [index.bxm] -r [index.bxm]

    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

    🛡️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

    Environment variables are scanned first, then the command arguments. Thus, the command arguments take precedence.

    🔒 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.

    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.

    🩺 Health Check Endpoints

    The MiniServer provides comprehensive health monitoring capabilities through dedicated endpoints:

    Basic Health Checks

    Enable health checks with the --health-check flag:

    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:

    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

    The /health endpoint returns comprehensive JSON information:

    The health check provides:

    • Status - Current server status (UP/DOWN)

    • Timestamp - Current server time in ISO format

    • Uptime - Human-readable server uptime

    • UptimeMs - Server uptime in milliseconds

    • Version - BoxLang version information

    • Build Date - When BoxLang was built

    • Java Version - JVM version information

    • Memory Usage - Current memory usage in bytes

    • Memory Max - Maximum available memory in bytes

    🌍 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:

    .env File Format

    Your .env file should contain key-value pairs:

    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

    It is important to note that these variables will not exist as "proper" environment variables due to how BoxLang's runtime loads. 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.

    Privacy Note: Environment variables are NOT exposed through health check endpoints. Health checks only return basic server metrics and status information for security purposes.

    🔌 WebSocket Support

    The BoxLang MiniServer includes built-in WebSocket support for real-time communication:

    WebSocket Endpoint

    WebSocket connections are available at the /ws endpoint:

    New in 1.6.0: The MiniServer now properly returns STOMP heartbeat responses, ensuring reliable WebSocket connections with STOMP protocol support.

    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:

    SocketBox is available on ForgeBox: https://forgebox.io/view/socketbox

    SocketBox provides:

    • High-level WebSocket abstractions for BoxLang applications

    • Event-driven architecture with listeners and handlers

    • Room and namespace management for organizing connections

    • Built-in authentication and authorization support

    • Message broadcasting to multiple clients

    • Connection lifecycle management with automatic reconnection

    • Integration with BoxLang frameworks like ColdBox

    Installing SocketBox

    SocketBox Example

    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:

    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.

    🏠 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

    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.

    🔀 URL Rewrites

    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:

    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

    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:

    Rewrite Note: URL rewrites work best for dynamic applications and frameworks. Static websites typically don't need URL rewriting enabled.

    🛑 Server Management

    Graceful Shutdown

    The BoxLang MiniServer supports graceful shutdown for safe server termination:

    When you stop the server, you'll see:

    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:

    Production Note: For production deployments, consider using process managers like systemd, supervisor, or Docker containers for better service management and automatic restarts.

    ⚡ Performance Features

    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

    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.

    Using 3rd Party Jars

    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.

    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.

    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.

    🌐 Reverse Proxy Setup

    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.

    🔧 Nginx Configuration

    Nginx is a popular choice for reverse proxying BoxLang applications:

    Basic Nginx Configuration

    Load Balancing with Multiple MiniServers

    🔥 Apache Configuration

    Apache HTTP Server with mod_proxy for reverse proxying:

    Basic Apache Configuration

    Required Apache Modules

    🪟 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:

    Site-Level web.config

    🚀 Production Setup Recommendations

    1. Configure MiniServer for Production

    2. System Service Setup

    Create a systemd service for automatic startup:

    3. 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

    4. 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

    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.

    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.

    CommandBox server
    CommandBox PRO
    // 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"
    }
    
    function add( required numeric a, required numeric b, boolean print = false ){
    
    }
    // we auto cast 1 to numeric, "true" to boolean
    add( "1", 345, "true" )
    // Variables declared in a script are of any type and inferred
    name = "luis"
    
    function hello( name ){
        // argument name can be anything
    }
    123123123123123123123123123
    1.2312312312312312 E 26
    11111111111111111111 + 22222222222222222222
    import ortus.boxlang.runtime.types.util.MathUtil;
    MathUtil.setPrecision( 100 );
    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
    n = 1000000000
    n = 1_000_000_000
    n = 3.141_592_653_59
    1e2_345
    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#" )
    // Runs the println() bif and the now() bif
    println( "Hola from #now()#" )
    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 )
    bx:http url=apiURL result="result" {
      bx:httpparam type="header" name="Accept" value="application/json";
    }
    
    bx:timer variable="myTimer"{
      .. this code to time...
    }
    <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>
    "#now()# is a bif, and this #12 % 2# is a math expression, and more!"
    public String getText(){
       return """
       My text block
          with nice identation
    
          -- Luis Majano""";
    }
    function getText(){
       return "
       My text block
          with nice identation
    
          -- Luis Majano";
    }
    name = threadname = taskName = "I am Spartacus!"
    switch( expression ) {
        case value : case value2 :{
            break;
        }
    
        default : nothing
    }
    try{
        .. funky code here
    } catch( any e ){
    
        // We just caught every single exception known to man!
    
    }
    catch( foo.com | brad | com.luis.majano e ) {}
    // Properties
    class{
    
        property name="hello";
        property lastName;
    
    }
    // 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";
    }
    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;
    }
    myJavaClass( value castAs long )
    
    return {
        age : value castAs int,
        tags : value castAs String[],
        isActive : "#value#" castAs Boolean
        spam : value castas "#DynamicType#"
    }
    isInstanceOf( obj, "Map" )
    
    if( obj instanceOf "String" )
    if( obj instanceOf "MyUser" )
    if( obj not instanceOf "Integer" )
    
    // 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 );
    myArray = [
        "BoxLang",
        "ColdBox",
        "TestBox",
        "CommandBox",
    ]
    println( myArray )
    
    myStruct = {
        name: "BoxLang",
        type: "JVM Dynamic Language",
        version: "1.0.0",
    }
    println( myStruct )
    myArray = [ 1, 2, 3, 4, 5].toUnmodifiable()
    myData = { id: 1, when: now() }.toUnmodifiable()
    // 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
    // Import java classes
    import java:java.nio.file.Path as jPath
    import models.utils.Path
    
    myJavaPath = new jPath()
    myBxPath = new Path()
    class implements="java:java.util.List" {
    
    }
    
    class extends="java:ortus.boxlang.runtime.types.Struct"{
    
    }
    ( expression ) ?: 'value or expression'
    age = form.userdata?.age;
    
    fullName = userClass?.getFullName()
    if( order ){
    
        if( order.hasCustomer() ){
            if( order.getCustomer().hasAddress() ){
                println( order.getCustomer().getAddress() )
            }
        }
    
    }
    println( order?.getCustomer()?.getAddress() )
    // 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 }
    
    hola.bxs
    // This is a script that can define functions
    
    // A scripting UDF
    function sayHello(){
        return "Hola!"
    }
    
    // Execute the UDF
    println( sayHello() )
    MyClass.bx
    // Some class UDFs
    class{
    
        function init(){
            return this
        }
    
        function sayHello(){
            return "Hola!"
        }
    
    }
    test.bxs
    // 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() )
    test.bxs
    // 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 )
    function hello(){}
    // Same as:
    public function hello(){}
    
    // private
    private function getData(){}
    
    // protected
    protected function bindData(){}
    function save( required user, boolean transactional = false, Logger logger ){
    
    }
    function save( transactional = true, data = {}, scope = "#expression#" ){
    }
    
    function hello( name = variables.defaultName ){
        println( "Hola #arguments.name#" )
    }
    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 )
    function setAge( numeric age )
    function Boolean isAlive(){
        return "yes"
    }
    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() };
    
    }
    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() };
    
    }
    User.bx
    class{
    
    	property name;
    	property email;
    	property isActive;
    
    }
    
    // Create a new user with no data
    user = new User()
    
    // Create one with named params
    user = new User( name: "BoxLang", email: "[email protected]", isActive: true )
    
    // Create one with an arg collection
    myArgs = { name: "BoxLang", email: "[email protected]", isActive: true }
    user = new User( argumentCollection: myArgs )
    @annonationName
    // or...
    @annonationName( value, value, value )
    @singleton
    class{
    
        @inject
        property name="wirebox";
    
    
        @returnFormat( json )
        function getData(){
            return data
        }
    
        @cache( true )
        @returnFormat( "xml" )
        function getXMLData(){
    
        }
    
    }
    @singleton
    @transientCache( false )
    @myMetadata( hello, "another value" )
    class{
    
    }
    
    myClass = new MyClass()
    writeOutput( myClass.$bx.meta ) or println( myClass.$bx.meta )
    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" );
    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"
    }
    # Mac / *unix
    cd mySite
    boxlang-miniserver
    # Windows
    cd mySite
    boxlang-miniserver.bat
    # Native Jar execution
    cd mySite
    java -jar /usr/local/lib/boxlang-miniserver-1.0.0.jar
    + 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.4.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.
    boxlang-miniserver
    boxlang-miniserver /path/to/config.json
    boxlang-miniserver miniserver.json --port 9090 --debug
    {
      "port": 8080,
      "webRoot": "./www"
    }
    {
      "port": 8080,
      "host": "127.0.0.1",
      "webRoot": "./src/webapp",
      "debug": true,
      "rewrites": true,
      "rewriteFileName": "index.bxm"
    }
    {
      "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"
    }
    {
      "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"
    }
    {
      "envFile": ".env.local"
    }
    {
      "envFile": "/etc/myapp/.env.production"
    }
    # 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
    boxlang-miniserver --health-check
    boxlang-miniserver --health-check --health-check-secure
    {
      "status": "UP",
      "timestamp": "2025-08-01T17:05:47.587438Z",
      "uptime": "1m 47s",
      "uptimeMs": 107245,
      "version": "1.4.0-snapshot+0",
      "buildDate": "2025-08-01 16:03:36",
      "javaVersion": "17.0.2",
      "memoryUsed": 152093696,
      "memoryMax": 4294967296
    }
    # If webroot contains a .env file, you'll see:
    + Loaded environment variables from: /path/to/webroot/.env
    # .env file example
    DATABASE_URL=jdbc:mysql://localhost:3306/mydb
    API_KEY=your-secret-api-key
    DEBUG_MODE=true
    CUSTOM_SETTING=value
    // 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');
    };
    # Install via CommandBox
    box install socketbox
    
    # Or download from ForgeBox
    # https://forgebox.io/view/socketbox
    // BoxLang server-side WebSocket handler using SocketBox
    class {
    
        function onConnect( socket, data ) {
            // Handle new WebSocket connection
            socket.join( "chatRoom" )
            socket.broadcast( "userJoined", { user: data.username } )
        }
    
        function onMessage( socket, message ) {
            // Handle incoming messages
            socket.to( "chatRoom" ).emit( "newMessage", {
                user: socket.data.username,
                text: message.text,
                timestamp: now()
            })
        }
    
        function onDisconnect( socket ) {
            // Handle client disconnection
            socket.broadcast( "userLeft", { user: socket.data.username } )
        }
    }
    + WebSocket Server started
    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
    # 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
    // 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";
    }
    + Enabling rewrites to /index.bxm
    # Stop the server gracefully
    Press Ctrl+C
    Shutting down BoxLang Server...
    BoxLang Server stopped.
    # 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
    # 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
    # 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
    BOXLANG_MINISERVER_OPTS="-Xmx512m"
    boxlang-miniserver
    # /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;
        }
    }
    # 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;
        }
    }
    # /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>
    # 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
    <!-- 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>
    <!-- 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>
    # 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
    # /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
    # Enable and start the service
    sudo systemctl enable boxlang-miniserver
    sudo systemctl start boxlang-miniserver
    sudo systemctl status boxlang-miniserver

    <

    lt

    <=

    lte

    contains, ct

    Returns true if the left operand contains the right one. 'hello' contains 'lo'

    does not contain, nct

    Negated Contains

    !

    not

    &&

    and

    ||

    or

    XOR

    Exclusive OR

    EQV

    Equivalence

    IMP

    Implication

    %

    mod

    Modulus

    Case Insensitive Functionality
    BIFs = Built-In Functions
    BoxLang Components
    Expression Interpolation
    Multi-Line Strings
    Multi-Variable Assignments
    Switch Statements
    Catch any exception
    Multi-Catch Exceptions
    No Semicolons, almost
    Scopes
    Full Null Support
    CastAs Operator
    Human Operators
    InstanceOf Operator
    Data Types
    Arrays are Human
    Array/Struct Literal Initializers
    Unmodifiable Objects
    Truthy/Falsey
    Imports & Class Locators
    Null Coalescing aka Elvis Operator
    Safe Navigation Operator
    Assert
    Functional
    BoxLang Classes

    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)

    --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.

    --serverHome path/ -s path/

    The location of the BoxLang home for the miniserver. This is where it will look for the boxlang.json, place to put the log files, the compiled classes, load modules, and much more. By default, we use the OS home via the BOXLANG_HOME environment variable which usually points to the user's home: ~/.boxlang/

    --version -v

    Display version information and exit

    --webroot path/ -w path/

    The webserver root. By default, we use the directory from where you started the command.

    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

    Environment Files
    WebSocket Support
    Default Welcome Files
    URL Rewrites
    Server Management
    Performance Features
    Reverse Proxy Setup

    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

    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)

    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.

    🔌 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

    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

    🚀 Revolutionary IBoxpiler Interface

    The new IBoxpiler interface enables true plug-and-play compiler development:

    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

    Example Use Cases:

    💼 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

    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

    Deployment Scenarios:

    Scenario
    Recommended Runtime
    Compiler

    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.

    🎓 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

    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:

    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

    Completely Rewritten bx:http Component

    The bx:http component has been completely rewritten to match the fluent BIF capabilities while maintaining CFML compatibility:

    New Features:

    • Streaming Callbacks: onChunk, onMessage, onError, onComplete, onRequestStart

    • SSE Support: Native Server-Sent Events handling with sse attribute

    HTTP Service - Connection Lifecycle Management

    A new HttpService manages HTTP client instances, connection pooling, and lifecycle:

    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:

    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

    Implementation Details:

    • Parses WSDL using DOM XML parser

    • Extracts operations, bindings, and port types

    • Handles XSD schema for parameter discovery

    • Builds SOAP envelopes dynamically

    🎯 Context Shutdown Listeners

    New lifecycle hooks for graceful application shutdown:

    Use Cases:

    • Database connection cleanup

    • Cache flushing

    • File handle closing

    • External service disconnection

    📚 Enhanced Metadata & Reflection

    Class metadata now includes simpleName for easier reflection:

    🤖 Core Runtime Updates

    Configuration Improvements

    Compiler Configuration: The experimental compiler setting has been refactored to a top-level directive in boxlang.json:

    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:

    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

    📡 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:

    Explicit Path:

    Override with CLI:

    Example Configuration Files:

    Supported Configuration Options:

    Option
    Type
    Default
    Description

    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:

    or

    • 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

    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

    🚀 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"

    Query Operations (15+ fixes)

    • queryFilter(): Fixed returning unexpected rows

    • querySlice(): Fixed offset handling

    • structFindKey(): Now returns proper references (not copies)

    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

    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

    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

    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

    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

    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

    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

    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

    🔧 Configuration Updates

    Compiler Configuration

    The experimental compiler setting is now a top-level directive:

    Valid values: "asm" (default), "java", "noop"

    JDBC Configuration

    Enhanced placeholder support in datasource URLs:

    ⚡ 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:

    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:

    Configuration: Update your boxlang.json to use the new top-level compiler directive if you were using the experimental setting.


    🎶 Release Notes

    Bugs

    this.timezone not respected in Application.bx

    jsessionid cookie value set to null - breaks AWS WAF

    Compat: GetTempDirectory Does not Contain Trailing Slash

    ByteCode Versioning on Upgrade - clear BL home classes folder

    DateAdd changes date when added 0 'w'

    parseDateTime - Can't cast [Nov-05-2025 8:43am] to a DateTime.

    HTTP request fails with exception when server response with duplicate headers

    stored proc component not respecting "null" attribute

    cfdump breaks when column names have comma

    servlet runtime is not using the real page context

    QueryFilter returning unexpected rows

    sorting an array of numerics errors on decimals

    querysclice mishandles offset

    calling custom tag from catch block errors

    Parser: semicolons after empty statement block don't end the statement

    xmlSearch doesn't return correct value for xpath expression

    Datasources need to lead first, then caches to avoid chicken and egg issues

    When using SQLite with BoxLang, database errors (like creating a table that already exists) are not handled properly.

    StructFindKey doesn't seem to return references

    Application can shutdown mid request

    captured variable not available when capture is performed in catch block

    Boxlang server does not start if one datasource has connection issues

    reMatchNoCase result is an array with 2 elements

    Can't compare [String] against [Array]

    Date Casting issues when JVM locale is `de_DE` or `en_DE`

    Can't cast [0] to a DateTime

    FileUpload fails allowed extension check when periods are present

    list / array find BIFs returning unexpected matches

    acf/lucee compat -- numberFormat( "", '_.00' ) throws

    acf/lucee compat - numberFormat(0, "_.00") returns ".00"

    Can't cast [Jul 17, 2017 9:29:40 PM] to a DateTime.

    number format omits leading zero with _.00 mask

    isDate(0) returns true

    isValid - Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null

    isDate - can't cast '0000009' to a BigDecimal

    SessionScope in distributed cache not persisting when request ends

    Dynamic Interop getField() issue when trying to access a public class parent package/private class fields

    bad parse (?) on static function invocation

    can't use `continue` inside `switch` inside `for`

    For CFML compatibility CGI values should be java,lang.string

    Nested queries ignore JSONSerialize query options

    Don't compare numbers to booleans

    lsIsCurrency - can't cast java.lang.Integer to java.lang.String

    `timeFormat` can produce strings containing non-ascii whitespace

    CF compat: allow whitespace in / > tag closing

    Parsing CF template CFC

    assingment inside ternary parses wrong

    val() sometimes returns scientific notation

    array append throws java.lang.UnsupportedOperationException when array originates from struct.keyArray()

    values not coerced when setting Java fields

    {}.putAll(Map) throws ClassCastException

    Can't cast [Jun-30-2010 04:33] to a DateTime

    Optimize DateTimeFormatter Usage

    Cannot map/filter an unmodifiable array

    query with user/pass override doesn't use connection pooling

    query with user/pass override doesn't override on-the-fly struct

    asyncRun() executor argument was not detecting BoxExecutors directly.

    Regression: isDefined returning false on struct key

    CF transpiler doesn't catch variables inside isDefined args

    CFCookie Expires crashes if using CreateTimeSpan

    Object Component - Type Default Not Being Set

    Can't cast [Jun-3-2010 04:33] to a DateTime.

    Can't cast [11/21/2025 1:05] to a DateTime

    isNumeric("true") is true on boxlang, false on lucee/acf

    Refactor 3 dangling core references to the Java Boxpiler

    CFTag support for thisTag scope behaves differently than ACF/Lucee

    You cannot declare a variable using BoxExpressionInvocation

    Compat: `format` member function undocumented but supported for DateTime objects

    Compat: `component` attribute not handled correctly by Object component

    Incorrect line number reported in tag context

    header component should add header, not replace

    Regression: HTTP Component Basic Auth no longer sending proper header

    Compat: Add handling for null dates in formatting methods

    New Features

    context shutdown listeners

    Add mechanism for runtimes to wait until BoxRuntime instance is started

    Add onServerStart support to compat module

    ServerSideEventConsumer(), SSEConsume() bif to allow from the core to connect and consume events. This is imperative for LLM integrations

    ServerSideEventConsumer to allow for any BoxLang app to consume SSE events in a streaming fashion, especially tuned for LLMs

    Fluent HTTP Client with http() bif

    HTTP Service for managing and controlling http client life-cycles

    Ability for our HTTP calls to persist connection and state across executions

    HTTP Streaming capabilities for the http components (SSE, Regular Streams)

    SOAP Client Consumer

    added simpleName to metadata for classes for ease of use

    StructFindValue breaks if any key is an array

    Improvements

    Create a way to load jars dynamically - enhanced DynamicClassLoader with addPaths()

    Remove all JavaParser dependencies externally unless you check if it exists

    Refactor the experimental compiler setting to a top-level directive in the boxlang.json: compiler

    More robust placeholder replacements in JDBC URLs

    Rename SSE BIF to ServerSideEvent and add Alias to SSE

    Added descriptions to web support bifs/components

    Add support for query type of text, map to varchar

    Enhance feature audit to find REST classes

    Support rowID/generatedKey for Oracle

    Make datasource URL placeholder replacements case-insensitive

    Faster bx:thread joining

    Allow JDBC Drivers to override query column types

    variableName type allows periods

    Preserve whitespace in error messages in default web Error page

    track original JDBC col type and make available in query meta

    varchar param doesn't match char field in Oracle driver

    Support BLOB and CLOB properly

    Compat-- upper case outer struct keys when serializing query

    Use background thread to check app timeouts

    Micro optimizations to promote speed when creating metadata by using imperative programming

    println() better handling of java native arrays

    Oracle stored procs support for ref cursors

    rereplace() ignore invalid backreference groups

    Default choice for most applications

    Reduced attack surface - no compiler means no compilation exploits

  • Immutable deployments - code cannot be modified at runtime

  • Perfect for production environments requiring security certifications

  • Default compiler for production applications

    🌐 Alternative Targets - Compile BoxLang to JavaScript, WASM, native code, etc.

  • 🔬 Research & Innovation - Experiment with new compilation techniques

  • ✅ Eliminate entire classes of code injection vulnerabilities
    🔬
    Research-friendly
    for academic and innovation projects

    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)

    Thread-safe compilation for concurrent applications

    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)

  • 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

  • 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

  • Supports complex types and nested structures
  • Compatible with invoke() BIF and bx:invoke component

  • Logging final state
    Oracle Improvements
    :
    • VARCHAR params now match CHAR fields correctly

    • Support for generated keys (ROWID)

    • Stored procedure ref cursor support

    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)

    Environment variables are loaded as system properties and can be used throughout the application

    Session management: Fixed jsessionid cookie handling (prevents AWS WAF issues)
  • Concurrent request handling: Better handling of in-progress onApplicationStart()

  • "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

  • 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

  • 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

  • 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

  • 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)

  • : 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

  • 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

  • : Can now map/filter unmodifiable arrays
  • Native Array Printing: println() better handles Java native arrays

  • Datasource Loading
    : Datasources load first, then caches (avoids chicken/egg issues)
  • Datasource Errors: Server now starts even if one datasource has connection issues

  • 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)

  • Development

    boxlang

    ASM (hot-reload enabled)

    CI/CD Testing

    boxlang

    ASM

    Staging

    boxlang or boxlang-noop

    ASM

    Production (Standard)

    boxlang

    port

    number

    8080

    The port to listen on

    host

    string

    "0.0.0.0"

    The host to bind to

    webRoot

    string

    current directory

    BL-1850
    BL-1874
    BL-1884
    BL-1886
    BL-1888
    BL-1889
    BL-1890
    BL-1892
    BL-1896
    BL-1897
    BL-1899
    BL-1900
    BL-1901
    BL-1906
    BL-1908
    BL-1909
    BL-1910
    BL-1911
    BL-1912
    BL-1913
    BL-1914
    BL-1926
    BL-1927
    BL-1928
    BL-1929
    BL-1930
    BL-1931
    BL-1932
    BL-1933
    BL-1934
    BL-1935
    BL-1938
    BL-1939
    BL-1941
    BL-1942
    BL-1943
    BL-1946
    BL-1947
    BL-1948
    BL-1949
    BL-1950
    BL-1951
    BL-1952
    BL-1956
    BL-1958
    BL-1959
    BL-1960
    BL-1962
    BL-1963
    BL-1965
    BL-1966
    BL-1967
    BL-1969
    BL-1971
    BL-1972
    BL-1973
    BL-1976
    BL-1977
    BL-1978
    BL-1980
    BL-1981
    BL-1982
    BL-1983
    BL-1984
    BL-1985
    BL-1987
    BL-1988
    BL-1989
    BL-1994
    BL-1995
    BL-1996
    BL-1997
    BL-1998
    BL-1835
    BL-1891
    BL-1893
    BL-1895
    BL-1898
    BL-1921
    BL-1922
    BL-1923
    BL-1924
    BL-1970
    BL-1974
    BL-1990
    BL-1315
    BL-1518
    BL-1617
    BL-1868
    BL-1887
    BL-1894
    BL-1902
    BL-1903
    BL-1905
    BL-1918
    BL-1919
    BL-1920
    BL-1925
    BL-1936
    BL-1937
    BL-1940
    BL-1945
    BL-1957
    BL-1968
    BL-1975
    BL-1986
    BL-1991
    BL-1992

    ASM

    Path to the webroot directory

    # 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
    // boxlang.json - Choose your compiler
    {
      "compiler": "asm",  // Use ASM compiler (default)
      // OR
      "compiler": "java"  // Use Java source compiler
    }
    public interface IBoxpiler {
        // Compile BoxLang source to bytecode
        byte[] compile( SourceCode source );
    
        // Get compiler metadata
        String getName();
        String getVersion();
    }
    // 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();
    // 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: "[email protected]" } )
        .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
    // 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":"[email protected]"}' />
    </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" />
    // 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#" );
    // 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.getOperationNames();
    println( "Available operations: #operations.toList()#" );
    
    // Get operation details
    opInfo = ws.getOperationInfo( "getUserInfo" );
    println( "Parameters: #opInfo.parameters.toList()#" );
    // 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" );
            } );
        }
    }
    meta = getMetadata( myObject );
    println( "Class: #meta.fullName#" );
    println( "Simple name: #meta.simpleName#" ); // New in 1.8.0
    {
      "compiler": "asm",  // or "java" or "noop"
      "runtime": {
        // other runtime settings
      }
    }
    // 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() );
    # Looks for miniserver.json in current directory
    boxlang-miniserver
    boxlang-miniserver /path/to/config.json
    # CLI arguments override JSON configuration
    boxlang-miniserver miniserver.json --port 9090 --debug
    // 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"
    }
    {
      "envFile": ".env.local"
    }
    {
      "envFile": "/etc/myapp/.env.production"
    }
    {
      "compiler": "asm",
      "runtime": {
        // runtime settings
      }
    }
    {
      "datasources": {
        "myDB": {
          "driver": "mysql",
          "url": "jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME}",
          "username": "${DB_USER}",
          "password": "${DB_PASS}"
        }
      }
    }
    // 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
    // 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 );