1.5.0
August 30, 2025
We're excited to announce BoxLang 1.5.0, bringing significant improvements to performance, reliability, and developer experience. This release focuses on enhanced AWS Lambda support, better Java interoperability, improved query handling, and numerous bug fixes that make BoxLang more robust for production workloads.
🚀 Major Highlights
AWS Lambda Runtime Enhancements
BoxLang 1.5.0 introduces powerful optimizations for serverless deployments, including class caching, connection pooling, and performance metrics.
Enhanced Query Operations
Improved support for multiple SQL statements, better parameter handling, and enhanced metadata capture for database operations.
Advanced Java Interop
Better method resolution for overloaded Java methods and improved handling of primitive type expectations.
🏗️ AWS Lambda Runtime Features
Lambda Class Caching
Ticket: BL-1712
BoxLang now caches compiled lambda classes to avoid expensive recompilations on subsequent invocations, dramatically improving cold start performance.
// Your BoxLang lambda handlers now benefit from automatic class caching
function handler( event, context ) {
// Compiled classes are cached automatically for faster subsequent invocations
return {
"statusCode" : 200,
"body" : serializeJSON( processEvent( event ) )
};
}
Configurable Connection Pooling
Ticket: BL-1716
Control AWS runtime connection pool size via the new environment variable:
# Set connection pool size (defaults to 2)
BOXLANG_LAMBDA_CONNECTION_POOL_SIZE=2
Performance Metrics Logging
Ticket: BL-1713
Enable detailed performance metrics in debug mode to monitor Lambda execution times and resource usage.
Convention-Based URI Routing
Ticket: BL-1714
Automatic routing using PascalCase conventions. You can now build multi-class Lambda functions with BoxLang easily following our conventions.
// URL: /products -> Products.bx
// URL: /home-savings -> HomeSavings.bx
// URL: /user-profile -> UserProfile.bx
// Products.bx
function handler( event, context ) {
return {
"statusCode" : 200,
"body" : getProductCatalog()
};
}
🔧 Core Runtime Improvements
Enhanced File Upload Support
FileUpload now includes blockedExtensions
argument and correctly populates file name properties:
// Enhanced file upload with security
result = fileUpload(
destination = "/uploads/",
fileField = "attachment",
blockedExtensions = [ "exe", "bat", "com" ],
allowedExtensions = [ "jpg", "png", "pdf", "docx" ]
);
// Correctly populated properties
writeOutput( "Client filename: " & result.clientFile );
writeOutput( "Server filename: " & result.serverFile );
writeOutput( "Original name: " & result.clientFileName );
writeOutput( "Saved as: " & result.serverFileName );
Improved Error Handling for Primitive Returns
Ticket: BL-1680
Better error messages when proxied UDFs return null where primitives are expected:
// Before: Cryptic casting error
// After: Clear error message
function getScore() {
return; // null return
}
numeric score = getScore(); // Now provides clear error about null->numeric conversion
Memory Leak Prevention
Ticket: BL-1697
Enhanced thread management prevents memory leaks with unbounded thread usage in long-running applications.
Virtual Thread Support for Parallel Operations
Ticket: BL-1687
All parallel BIFs now support a virtual
argument to leverage Java's virtual threads for improved performance and resource efficiency. You can also pass it instead of the maxThreads
argument as well.
// 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
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:
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()
📊 Database & Query Enhancements
Multiple SQL Statement Support
Ticket: BL-1186
QueryExecute now properly handles multiple SQL statements:
// Execute multiple statements in a single call
result = queryExecute( "
UPDATE users SET last_login = NOW() WHERE id = :userID;
INSERT INTO login_log (user_id, login_time) VALUES (:userID, NOW());
SELECT * FROM users WHERE id = :userID;
", {
"userID" : { value: 123, cfsqltype: "numeric" }
} );
Enhanced Generated Key Capture
Ticket: BL-1700
// Capture all generated keys from INSERT operations
result = queryExecute( "
INSERT INTO orders (customer_id, order_date)
VALUES (:customerID, NOW())
", {
"customerID" : { value: 456, cfsqltype: "numeric" }
}, {
result: "insertResult"
} );
// Access generated keys
newOrderID = insertResult.generatedKey;
writeOutput( "New order created with ID: " & newOrderID );
Update Count Tracking
Ticket: BL-1701
// Track how many records were affected
result = queryExecute( "
UPDATE products
SET price = price * 1.10
WHERE category = :category
", {
"category" : { value: "Electronics", cfsqltype: "varchar" }
}, {
result: "updateResult"
} );
writeOutput( "Updated " & updateResult.recordCount & " products" );
Improved Parameter Handling
Ticket: BL-1661
Better handling of queries with both loose colons and positional parameters:
// Now works correctly with mixed parameter styles
sql = "SELECT * FROM events WHERE start_time > '2024-01-01 00:00:00' AND user_id = ?";
result = queryExecute( sql, [ 123 ] );
🔗 Java Interoperability Improvements
Better Method Resolution
Ticket: BL-1715
Improved matching for overloaded Java methods:
// Java class with multiple format() methods
formatter = createObject( "java", "java.text.DecimalFormat" ).init( "#,##0.00" );
// Now correctly resolves the right overloaded method
boxLangNumber = 1234.56;
formatted = formatter.format( boxLangNumber ); // "1,234.56"
Ticket: BL-1667
Better preference handling when Java methods accept Object arguments:
// BoxLang DateTime objects now properly handled
dateTime = now();
javaFormatter = createObject( "java", "java.time.format.DateTimeFormatter" )
.ofPattern( "yyyy-MM-dd HH:mm:ss" );
// Now works correctly with BoxLang DateTime
formatted = javaFormatter.format( dateTime );
🏗️ CFML Compatibility Enhancements
Script Custom Tag Support
Ticket: BL-1679
Added support for Adobe ColdFusion script-based custom tags:
// CustomButton.cfc (custom tag)
component {
function onStart() {
if ( !structKeyExists( attributes, "text" ) ) {
attributes.text = "Click Me";
}
return true;
}
function onEnd() {
writeOutput( '<button class="btn btn-primary">' & attributes.text & '</button>' );
return true;
}
}
// Usage in template
bx:customButton text="Save Changes";
Encrypted Datasource Password Support
Ticket: BL-1127
Support for Lucee-style encrypted datasource passwords:
// BoxLang.json datasource configuration
{
"datasources": {
"myDB": {
"driver": "mysql",
"host": "localhost",
"database": "myapp",
"username": "dbuser",
"password": "encrypted:ABC123DEF456", // Encrypted password support
"port": 3306
}
}
}
Component Name Annotation Fix
Ticket: BL-1684
The name
annotation on components now correctly sets metadata without overwriting:
/**
* @name CustomService
* @description Provides custom business logic
*/
component {
// Component metadata.name is now correctly set to "CustomService"
function init() {
return this;
}
}
🛠️ Developer Experience Improvements
Enhanced List Functions
Ticket: BL-1660
List BIFs now preserve custom delimiters when reassembling:
// 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
Duration objects can now be compared with integers and other numeric values:
timeout = createTimeSpan( 0, 0, 5, 0 ); // 5 minutes
maxWait = 300; // 300 seconds
// Now works correctly
if ( timeout > maxWait ) {
writeOutput( "Timeout exceeds maximum wait time" );
}
// Duration arithmetic with numbers
newTimeout = timeout + 60; // Add 60 seconds
Class Metadata Enhancement
Ticket: BL-1686
Box Class metadata now includes "output" key for better introspection:
metadata = getMetadata( myComponent );
if ( metadata.output ) {
writeOutput( "Component generates output" );
}
🐛 Notable Bug Fixes
Query of Queries Parsing
Ticket: BL-1678 Fixed parsing errors in Query of Queries when using parentheses in expressions.
Super Reference Resolution
Ticket: BL-1674 Corrected super reference resolution for mixin UDFs in parent classes.
HTTP Header Handling
Ticket: BL-1676 Resolved HTTP errors when Accept-Encoding and TE headers are set as HTTP parameters.
Module Management
Ticket: BL-1705 Fixed module unload process to properly remove and unregister module resources.
Thread Context Handling
Ticket: BL-1696 Ensured threads consistently use the correct context classloader.
SQL Formatting
Ticket: BL-1683 Fixed the sqlPrettify
function for proper SQL formatting.
📊 Performance & Reliability
Memory Usage: Reduced memory footprint through better thread management
AWS Cold Starts: Significant improvement through lambda class caching
Database Operations: Enhanced reliability with better error handling and connection management
Java Interop: More efficient method resolution and argument handling
🔧 Configuration Updates
Docker Environment Variables
Ticket: BL-1673
Resolved collision between Docker env var BOXLANG_MODULES
and the config modules key.
Cache Settings
Ticket: BL-1709
Cache settings now properly replaced by environment variables:
# Environment variables now correctly override cache settings
BOXLANG_CACHE_DEFAULT_TIMEOUT=3600
BOXLANG_CACHE_MAX_ELEMENTS=1000
⚡ Migration Notes
Breaking Changes
None in this release
Deprecations
No new deprecations
Recommended Updates
AWS Users: Set
BOXLANG_LAMBDA_CONNECTION_POOL_SIZE
environment variable for optimal performanceFile Upload: Review code using
fileUpload()
to take advantage of newblockedExtensions
security featureModule Developers: Test module loading/unloading if you experienced issues in 1.4.x
Release Notes
Improvements
BL-1556 Bump org.semver4j:semver4j from 5.8.0 to 6.0.0.
BL-1664 fileUpload missing blockedExtensions argument
BL-1680 Better error if proxied UDF returns null where primitive is expected
BL-1686 add "output" key to Box Class Meta
BL-1687 Add `Virtual` Argument to BIF supporting parallel operations
BL-1688 DynamicObject not unwrapping arguments passed to method
BL-1693 Remove query column map from query metadata
BL-1697 Prevent memory leak with unbounded thread usage
BL-1700 Capture all generated keys
BL-1701 Capture update counts
BL-1712 AWS Runtime - Cache compiled lambda classes to avoid recompilations
BL-1716 AWS Runtime - Add aws runtime pool configuration via new ENV variable: BOXLANG_LAMBDA_CONNECTION_POOL_SIZE which defaults to 2
Bugs
BL-1186 queryExecute multiple statements
BL-1660 List BIFs which reassemble the list don't preserve delimiters
BL-1661 queryExecute - cannot execute query containing loose ':' and positional parameters
BL-1663 fileUpload: serverFileName, serverFile, clientFile, clientFileName are not correct per the spec
BL-1667 Interop service when dealing with methods with `Object` arguments, would give preference to coercionable arguments. Ex: Formatter.format( BoxLang DateTime ) would fail
BL-1668 Trying to load module class before module is registered errors
BL-1669 duration can't compare against an integer
BL-1670 Compare operator cannot cast Duration to Number
BL-1671 JDBC - "driver not registered" log on engine startup despite being installed
BL-1673 Miniserver: Docker env var BOXLANG_MODULES collides with modules key in config
BL-1674 super reference incorrect for mixin UDF in parent class
BL-1675 string caster not obeying fail flag when inputStream errors
BL-1676 HTTP Error When Accept-Encoding and TE Headers are being set as HTTP Params
BL-1678 Parsing error in QoQ with parentheses
BL-1679 Missing support for ACF script custom tags
BL-1681 Ignore extraneous return values from void proxies
BL-1682 Usage of quoted operators fails to compile.
BL-1683 sqlPrettify is broken
BL-1684 CFML Compat - `name` annotation on Component overwrites the metadata name
BL-1696 Threads not always using context classloader
BL-1699 JDBC not handling raised errors
BL-1705 Module unload fails to remove/unregister module resources
BL-1706 Issues with numberFormat masks
BL-1709 Cache settings do not get replaced by environment variables
BL-1715 Java interop matching in correct overloaded methods
New Features
BL-1127 Add support for Lucee's encrypted datasource passwords in compat
BL-1713 AWS Runtime - Log performance metrics when in debug mode
BL-1714 AWS Runtime - URI Routing by convention using PascalCase: /products -> Products.bx, /home-savings -> HomeSavings.bx
Last updated
Was this helpful?