Blog

Luis Majano

January 09, 2026

Spread the word


Share your thoughts

Happy New Year! The BoxLang team is excited to announce BoxLang 1.9.0, a significant stability and compatibility release focused on production-readiness thanks to our client migrations and new application deployments. This release also introduces array-based form field parsing conventions, enhanced datasource lifecycle management, improved context handling, and resolves over 50 critical bugs to ensure enterprise-grade reliability for mission-critical applications.

🚀 What's New in 1.9.0

You can find the full engineering what's new guide here: https://boxlang.ortusbooks.com/readme/release-history/1.9.0

📦 Array-Based Form Field Parsing - Modern Web Conventions

BoxLang now automatically parses query parameters and form fields as arrays using modern naming conventions—no more manual listToArray() conversions:

// HTML form with multiple selections
<form method="POST">
    <input type="checkbox" name="colors[]" value="red" />
    <input type="checkbox" name="colors[]" value="blue" />
    <input type="checkbox" name="colors[]" value="green" />
    <button type="submit">Submit</button>
</form>

// BoxLang automatically parses as array
selectedColors = form.colors;
// Result: ["red", "blue", "green"]

// Works with query parameters too
// URL: /page?tags[]=boxlang&tags[]=java&tags[]=modern
tags = url.tags;
// Result: ["boxlang", "java", "modern"]

// Traditional single values still work
name = form.name;  // Single string value

Benefits:

  • ✨ No manual conversions needed
  • 🎯 Consistent with modern web frameworks
  • 🔄 Fully backward compatible
  • 📡 Works with both POST and GET data

🔄 Enhanced Context Lifecycle Management - Proper Cleanup

Significant improvements to context management and shutdown handling ensure proper resource cleanup and prevent memory leaks in long-running applications:

Key Improvements:

  • Thread Counter Tracking - Contexts maintain active thread counts for proper cleanup
  • Exchange Detachment - Web contexts can detach during shutdown while still in use
  • ORM Cleanup - ORM context removal moved to shutdown listeners
  • Session Error Recovery - Errors in onSessionEnd no longer permanently break sessions
  • Startup Prevention - Sessions won't inadvertently start during app initialization

🗄️ Datasource Lifecycle Management - No More Connection Leaks

Critical fixes to datasource lifecycle prevent connection pool leaks and resource exhaustion:

class {
    this.name = "MyApp";
    
    this.datasources = {
        "mydb" : {
            driver : "mysql",
            host : "localhost",
            database : "appdb",
            username : "user",
            password : "pass"
        }
    };

    function onApplicationEnd() {
        // Datasources properly shutdown automatically
        // No more connection pool leaks across application restarts!
        writeLog( "Datasources cleaned up automatically" );
    }
}

Fixed Issues:

  • ✅ Application-level datasources shut down when application ends
  • ✅ Server-level datasources no longer create duplicate pools per application
  • ✅ Application caches properly removed on application end
  • ✅ Connection pool cleanup during entire application lifecycle

📊 Comprehensive Query and JDBC Enhancements

Major improvements to query handling and database operations across all drivers:

Oracle Database Improvements:

// Named parameters now work correctly
queryExecute(
    "SELECT * FROM users WHERE id = :userId AND status = :status",
    {
        userId : { value : 123, type : "integer" },
        status : { value : "active", type : "varchar" }
    },
    { datasource : "oracle_ds" }
);

// Ref cursor parameters work regardless of position
bx:storedproc procedure="getUserData" datasource="oracle_ds" {
    bx:procparam type="in" value=123 cfsqltype="cf_sql_integer";
    bx:procparam type="out" variable="result" cfsqltype="cf_sql_refcursor";
}

// Unused procresult tags properly ignored (no errors)
bx:storedproc procedure="processData" datasource="oracle_ds" {
    bx:procresult name="unused";  // Safe even if not returned
    bx:procparam type="in" value="data";
}

Parameter Handling:

// Empty lists in queryparam handled correctly (CFML compat)
bx:query name="filtered" {
    writeOutput( "
        SELECT * FROM products
        WHERE category IN (
            <bx:queryparam value='#categoryList#' list='true' />
        )
    " );
}

// Integer SQL type now properly validates instead of truncating
queryExecute(
    "INSERT INTO scores (value) VALUES (?)",
    [ { value : 95.5, type : "integer" } ]  // Now throws error (was silently truncating)
);

Query of Queries:

// NULL comparisons with LIKE now work correctly
query1 = queryNew( "name,description", "varchar,varchar", [
    [ "Product 1", null ],
    [ "Product 2", "A great product" ]
] );

result = queryExecute(
    "SELECT * FROM query1 WHERE description LIKE '%product%'",
    {},
    { dbtype : "query" }
);
// Properly handles NULL values without errors

🔢 Number Handling Improvements - Clean Serialization

Significant enhancements to numeric type handling prevent scientific notation in JSON:

// Doubles serialize without scientific notation
bigNumber = 1234567890.123456;
jsonStr = jsonSerialize( { value : bigNumber } );
// Output: {"value":1234567890.123456}
// NOT: {"value":1.234567890123456E9}

// BigDecimals also serialize cleanly
amount = preciseValue( "999999999.99" );
jsonStr = jsonSerialize( { amount : amount } );
// Output: {"amount":999999999.99}

// Scientific notation literals with leading zeros parse correctly
value = 0001.5e2;  // Now works: 150

// String-to-double conversion trims whitespace
value = toNumeric( "  42.5  " );  // Now works: 42.5

🎭 Enhanced Class Metadata - Static and Abstract Flags

Class metadata now includes static and abstract flags for functions:

abstract class {

    static function getVersion() {
        return "1.9.0";
    }

    abstract function process();
}

// Inspect metadata
meta = getMetadata( MyClass );
functionMeta = meta.functions[ "getVersion" ];

println( "Is static: #functionMeta.static#" );      // true
println( "Is abstract: #functionMeta.abstract#" );  // false

// Use in reflection scenarios
if( functionMeta.static ) {
    version = invoke( MyClass, "getVersion" );
}

Additional Metadata Improvements:

  • Component metadata returns struct for implements (not string)
  • Interface metadata properly structured
  • Doc comments preserve line breaks
  • Doc comments inside script blocks associate properly

🧹 SOAP Client Improvements

The SOAP client from 1.8.0 enhanced with proper class structure:

// SOAP client now has full class capabilities
ws = soap( "http://example.com/service.wsdl" );

// Access underlying HTTP methods
ws.setTimeout( 60 );
ws.setHeader( "Authorization", "Bearer token123" );

// Invoke SOAP methods with improved reliability
result = ws.invoke( "getUserInfo", 123 );
println( "User: #result.name#" );

📝 Mid() Function Enhancement

The mid() BIF now has optional count parameter for flexible string extraction:

// Extract from position to end of string
text = "Hello World";
result = mid( text, 5 );  // "o World"

// Extract with count (existing behavior)
result = mid( text, 5, 3 );  // "o W"

// More intuitive substring operations
greeting = "Good Morning Everyone";
timeOfDay = mid( greeting, 6, 7 );  // "Morning"
remainder = mid( greeting, 14 );     // "Everyone"

🐛 50+ Critical Bug Fixes

CFML Compatibility (15+ fixes)

  • ListDeleteAt - Retains leading delimiters (proper CFML behavior)
  • ListAppend - Behavior matches CFML exactly
  • Boolean Strings - Characters 'y' and 'n' recognized as booleans in compat mode
  • Session IDs - Properly prefixed with app identifier when J2EE sessions enabled
  • GetComponentMetaData - Returns struct for implements (not string)
  • Empty Query Params - Empty lists in cfqueryparam handled correctly
  • CreateUUID - Returns standard UUID format

File Operations (5+ fixes)

  • File Upload - result field properly populated after upload
  • Content Types - Upload contentType no longer includes contentSubType
  • File Append - action="append" correctly appends with line breaks

Date & Time (5+ fixes)

  • DateTime Parsing - Fixed casting with formats like "Dec/13/2025 08:00"
  • DateAdd - datepart parameter no longer case-sensitive
  • GetHTTPTimeString - Always returns GMT timezone
  • Session End Errors - Errors no longer leave session permanently expired
  • Session Prevention - Sessions don't start during app initialization
  • Cookie Serialization - Time serialized in GMT as expected

Core Runtime (10+ fixes)

  • Duplicate - Properly handles recursive references
  • ExpandPath - Works correctly outside request context (in onServerStart)
  • For Loops - Work properly with Java primitive arrays
  • Evaluate - Uses CF transpiler when called from CF source
  • Whitespace - Preserve whitespace no longer consumes excessive line breaks
  • Class Loading - Fixed race conditions with concurrent class loading

Database and ORM (5+ fixes)

  • Redis Query Caching - Fixed serialization with cached queries
  • ORM Datasources - ORM properly finds datasources without errors
  • Stored Procedure Return Codes - Use correct key names

Memory and Threading (5+ fixes)

  • Stream Handling - Fixed "Stream is closed" errors (UT010029)
  • Context Threading - Proper handling with multiple active threads
  • Comparison Sorting - Fixed "Comparison method violates its general contract"

String Operations (5+ fixes)

  • ReReplace - Fixed index out of bounds errors
  • String Comparison - Better error handling in comparisons
  • Class Inspection - Improved error handling for complex object dumps

🔧 Configuration Updates

HTTP Multipart Simplification

File uploads no longer require explicit multipart() call in many cases:

// Automatic multipart detection
http( "https://api.example.com/upload" )
    .post()
    .file( "document", "/path/to/file.pdf" )
    .send();
// multipart() automatically applied when files present

Transaction Component Cleanup

Removed unused nested attribute from transaction component:

// Simplified transaction syntax
transaction {
    queryExecute( "INSERT INTO users (name) VALUES (?)", [ "John" ] );
    queryExecute( "INSERT INTO logs (action) VALUES (?)", [ "user_created" ] );
}

// Nested transactions work automatically
transaction {
    queryExecute( "UPDATE accounts SET balance = balance - 100 WHERE id = 1" );
    
    transaction {
        queryExecute( "UPDATE accounts SET balance = balance + 100 WHERE id = 2" );
    }
}

📡 MiniServer JSON Configuration

MiniServer configuration via JSON files (introduced in 1.8.0) is now finalized:

# Automatically loads miniserver.json
boxlang-miniserver

# Or specify custom config
boxlang-miniserver /path/to/config.json

Example Configuration:

{
    "port" : 8080,
    "webRoot" : "./www",
    "debug" : true,
    "rewrites" : true,
    "rewriteFileName" : "index.bx",
    "healthCheck" : true
}

🎯 Why This Release Matters

BoxLang 1.9.0 represents our continued commitment to production-grade reliability. The focus on lifecycle management, datasource cleanup, and CFML compatibility makes this release essential for:

  • Enterprise Applications - Running mission-critical workloads with confidence
  • CFML Migrations - Smoother transitions with enhanced compatibility
  • Long-Running Services - Proper resource cleanup prevents memory leaks
  • High-Volume Applications - Optimized connection pooling and cache management

Download

Please visit our download page or our quick installation guides to upgrade your installation.

Professional Open Source

BoxLang is a professional open-source product, with three different licences:

  1. Open-Source Apache2
  2. BoxLang +
  3. BoxLang ++

BoxLang is free, open-source software under the Apache 2.0 license. We encourage and support community contributions. BoxLang+ and BoxLang ++ are commercial versions offering support and enterprise features. Our licensing model is based on fairness and the golden rule: Do to others as you want them to do to you. No hidden pricing or pricing on cores, RAM, SaaS, multi-domain or ridiculous ways to get your money. Transparent and fair.

BoxLang Subscription Plans

BoxLang is more than just a language; it's a movement.

Join us and redefine development on the JVM Ready to learn more? Explore BoxLang's Features, Documentation, and Community.

Add Your Comment

Recent Entries

First Round of the Into the Box 2026 Agenda Is Live

First Round of the Into the Box 2026 Agenda Is Live

Into the Box 2026 marks an important moment for the CFML and BoxLang community not just because of what’s on the agenda, but because of what it represents: 20 years of Ortus Solutions helping teams move forward, modernize, and build with confidence.

Victor Campos
Victor Campos
January 21, 2026
BoxLang AI v2: Enterprise AI Development Without the Complexity

BoxLang AI v2: Enterprise AI Development Without the Complexity

One Year. 100+ Features. Unlimited Possibilities.

Just one year ago, in March 2024, we launched BoxLang AI 1.0. Today, we're thrilled to announce BoxLang AI v2—a massive leap forward that positions BoxLang as the most powerful and versatile AI framework on the JVM.

Luis Majano
Luis Majano
January 19, 2026
CommandBox: A Smarter Foundation for BoxLang and CFML Workflows

CommandBox: A Smarter Foundation for BoxLang and CFML Workflows

In day-to-day development, some tools simply do their job… and others quietly change the way you work. CommandBox falls into the second category.

It doesn’t replace your editor, framework, or existing applications. Instead, it becomes the common ground where CFML and BoxLang development meet ,giving teams a consistent, reliable way to build, run, and evolve their projects.

Victor Campos
Victor Campos
January 16, 2026