Variable Scopes
They gotta exist somewhere!
In the BoxLang language, many persistence and visibility scopes exist for variables to be placed in. These are differentiated by context: in a class, function, component, thread, script or template. These scopes are Java maps but enhanced to provide case-insensitivity, member functions and more. There are also different scopes that become alive depending on the execution of certain constructs, such as queries, threads, and http calls.
📋 Table of Contents
When you declare variables in templates, classes, or functions, they’re stored within a structured scope. This design makes your code highly flexible, allowing you to fluently interact with the entire scope through a wide range of BIFs. You can even bind these variables directly to function calls, attributes, and more—highlighting the dynamic power at the core of BoxLang.
The only language keyword that can be used to tell the variable to store in a function's local scope is called var. However, you can also just use the localscope directly or none at all. However, we do recommend being explicit on some occasions to avoid ambiguity.
It's a good idea to scope variables to avoid scope lookups, which could in turn create issues or even leaks.
📄 Template/Scripts (bxm,bxs)
bxm,bxs)All scripts and templates have the following scopes available to them. Please note that the variablesscope can also be implicit. You don't have to declare it.
variables- The default or implicit scope to which all variables are assigned.
⚡Templates/Scripts Function Scopes
All user-defined functions declared in templates or scripts will have the following scopes available:
variables- Has access to private variables within a Class or Pagelocal- Function-scoped variables only exist within the function execution. Referred to asvarscoping. The default assignment scope in a function.arguments- Incoming variables to a function
🗳️ Classes (bx)
bx)All classes in BoxLang follow Object-oriented patterns and have the following scopes available. Another critical aspect of classes is that all declared functions will be placed in a visibility scope.
variables- Private scope, visible internally to the class onlythis- Public scope, visible from the outside world and a self-reference internallystatic- Store variables in the classes blueprint and not the instancesuper- Only available if you use inheritance
Function Scopes
Depending on a function’s visibility, BoxLang automatically places a reference (or pointer) to that function in different scopes, within the class ensuring that it can be discovered and invoked appropriately. Why does it do this? Because BoxLang is a dynamic language by design.
In practice, this means that functions in BoxLang are not locked down at compile time. Instead, they remain fully malleable at runtime—you can add new functions, remove existing ones, or even modify their behavior on the fly. This flexibility allows developers to build more adaptive and expressive applications, where behaviors can evolve based on context, configuration, or user interaction.
By managing function pointers across scopes, BoxLang ensures that these runtime changes are immediately reflected wherever the function is expected to live. Whether it’s within a local scope, a component, or a broader application context, the dynamic nature of BoxLang makes it possible to treat functions as living members of your application rather than static, unchangeable artifacts.
PrivateFunctionvariables
Public or RemoteFunctionsvariablesthis
⚡Closures
All closures in BoxLang are context-aware, which means they carry with them knowledge of the environment in which they were created. In other words, a closure isn’t just a function—it’s a function plus the scope it was born in. This allows closures to maintain access to variables, functions, and references that existed at the time they were defined, even if they are later executed in a completely different context.
For example, if you define a closure inside a function, it will continue to “remember” the local variables of that function, making it a powerful tool for encapsulating state and creating reusable logic without polluting the global or class-level scopes.
When closures are defined inside classes, they become even more useful. In this case, closures automatically capture the class’s variables scope (the private, per-instance data) as well as the this scope (the public interface of the instance). This means closures have seamless access to both the internal state of the class and its public methods, enabling elegant encapsulation of behavior that can directly interact with the object’s data.
This context-awareness is what makes closures in BoxLang so flexible. They’re not isolated pieces of code; they are “living” functions that carry their birthplace with them. This ensures that wherever you pass them—whether into a higher-order function, as an event handler, or across asynchronous execution—they still know exactly where they came from and what they can interact with.
variables- Has access to private variables from where they were created (Classes, scripts or templates)this- Has access to public variables from where they were created (Classes)local- Function-scoped variables only exist within the function execution. Referred to asvarscoping. The default assignment scope in a function.arguments- Incoming variables to a function
🪶 Lambdas
Lambdas in BoxLang are designed to be pure functions. Unlike closures, they do not capture or carry along the scope in which they were defined. In other words, lambdas don’t “remember” their birthplace or have access to surrounding variables. They exist independently of the context in which they were created.
This distinction has two major implications:
Simplicity – Because lambdas are context-free, they are lightweight and predictable. They only operate on the
argumentsexplicitly passed to them and any values they define internally. You don’t have to worry about hidden dependencies or external scope leaks. This makes them ideal for short, focused operations like transformations, mappings, or small inline computations.Performance – Without the overhead of capturing surrounding scopes, lambdas are faster to create and execute compared to closures. They don’t need to carry around extra baggage such as references to variables, this, or parent function contexts. This efficiency makes them an excellent choice in performance-sensitive scenarios, especially when used in large iterations, functional pipelines, or hot paths in your application.
In essence, lambdas in BoxLang provide a lean, functional style of programming: self-contained, efficient, and free of side effects. They shine when you need a quick function without any ties to the broader context—perfect for concise logic that should remain pure and context-independent.
local- Function-scoped variables only exist within the function execution. Referred to asvarscoping. The default assignment scope in a function.arguments- Incoming variables to a function
The following will throw an exception as it will try to reach outside of itself:
🏷️ Components
In BoxLang, you’re not limited to the built-in components—you can extend the language itself by creating your own custom components. These components can be invoked seamlessly in both script syntax and templating syntax, giving developers a consistent way to encapsulate and reuse functionality across different coding styles.
Custom components are powerful because they allow you to wrap up behavior into a self-contained unit that can handle input, manage its own internal state, and even communicate back to the calling template. This makes them excellent for building reusable UI constructs, workflow blocks, or domain-specific abstractions. They also do not affect the parser, but rather are invoked at runtime. This means, that you can create predictable, reusable components without worrying about breaking the syntax of your BoxLang code.
Every custom/core component automatically has access to a set of special scopes that give it flexibility and power:
• attributes – Holds the incoming arguments or attributes passed into the component. This is how you provide input to customize the component’s behavior. • variables – Acts as the default scope for variable assignments inside the component, ensuring that the component has its own sandboxed data environment. • caller – Provides a way for the component to interact with the template that invoked it, allowing you to set or read variables from the caller’s context. This enables two-way communication between the component and the outside world.
Example Usage
You can call a component using script syntax, where it looks and feels like a function call with a block of content:
Or you can invoke it using templating syntax, which is closer to traditional custom tags:
We highly discourage peeking out of your component using the callerscope, but it can sometimes be beneficial. Use with caution.
🧵 Thread
When you create threads with the threadcomponent, you will have these scopes available to you:
attributes- Passed variables via a threadthread- A thread-specific scope that can be used for storage and retrieval. Only the owning thread can write to this scope. All other threads and the main thread can read the variables.local- Variables local to the thread contextvariables- The surrounding declared template or classvariablesscopethis- The surrounding declared class scope
🧵 bxThread
The bxThread scope is a special BoxLang scope that provides access to thread metadata and variables from anywhere in your request. It contains a key for every thread that has been executed in the current request, making it easy to access thread data from outside the thread context.
bxThread- Global scope containing all threads executed in the current requestEach thread key contains metadata and variables set from within that thread
🌐 Runtime Scopes
BoxLang runs in different runtime contexts, and the available scopes depend on which runtime you're using. Understanding these differences is crucial for building portable applications.
🖥️ Core OS
When running BoxLang in CLI mode or core OS runtime, you have access to these scopes:
variables- Default scope for variable assignmentslocal- Function-scoped variablesarguments- Function argumentsapplication- Application-wide persistence (requires Application.bx)session- Session persistence (requires Application.bx)request- Request-scoped variablesserver- Server-wide persistence across all applicationsthread- Thread-specific variablesbxThread- Global thread metadata scope
🕸️ Web Runtimes
When running in web runtimes (Servlet, MiniServer, Lambda, Desktop), you get additional web-specific scopes:
All Core Scopes PLUS:
url- HTTP GET parameters from the URLform- HTTP POST form datacgi- Server and request environment variablescookie- Browser cookiesbxFile- File upload information (during file uploads)bxHttp- HTTP request/response data (during HTTP operations)
🔍 Unscoped Variables
If you use a variable name without a scope prefix, BoxLang checks the scopes in the following order to find the variable (When we say function it includes closures, UDFs and lambdas):
Local (Functions only)
Arguments (Functions only)
Attributes (Components only)
Thread local (inside threads only)
Query (variables in active query loops)
Thread
Variables
If the runtime is web-based, it will also check these scopes last:
CGI
URL
Form
Cookie
IMPORTANT: Because BoxLang must search for variables when you do not specify the scope, you can improve performance by specifying the scope for all variables. It can also help you avoid nasty lookups or unexpected results.
🔍 Query Loop Scope
When you iterate over a query using bx:loop or functional methods like queryEach(), BoxLang automatically registers the query with the current context and makes the column names available as unscoped variables for the duration of each iteration.
Query Loop Variables
During query iteration, these special variables and functions are available:
Column Names
All query column names are available as unscoped variables containing the current row's value
queryCurrentRow(query)
Returns the current row number (1-based)
currentRow
Alias for current row number (when using member function syntax)
columnArray
Array of column names in the query
columnList
Comma-separated list of column names
recordCount
Total number of rows in the query
Query Loop Behavior
Member Function Syntax
Try query loops on try.boxlang.io
⚠️ Catch Scope
When an exception is caught in a try/catch block, BoxLang creates a special catch context that makes the exception variable available. The exception variable contains detailed information about the error.
Exception Variable Structure
The exception variable (commonly named e, ex, or error) is a struct containing:
message
The error message
type
The exception type (e.g., "Application", "Database", "Expression")
detail
Detailed error information
stackTrace
Full stack trace as a string
tagContext
Array of stack frames with file/line information
cause
The underlying Java exception (if applicable)
errorCode
Error code (if applicable)
extendedInfo
Additional error information (if applicable)
Catch Scope Behavior
CFML Compatibility
In CFML compatibility mode (using the bx-compat-cfml module), the exception variable is also available as cfcatch:
Rethrowing Exceptions
Within a catch block, you can use the rethrow statement to re-throw the current exception:
Scope Visibility: The exception variable is only available within the catch block. Once execution exits the catch block, the variable is no longer in scope.
Try exception handling on try.boxlang.io
🔒 Final Variables
BoxLang supports the final modifier for variables in any scope, which prevents the variable from being reassigned after its initial assignment. This is useful for creating constants and preventing accidental modifications.
Important: Final variables must be assigned a value when declared. Attempting to reassign a final variable will result in a runtime error.
💾 Persistence Scopes
Can be used in any context, used for persisting variables for a period of time.
session- stored in server RAM or external storages tracked by unique web visitorapplication- stored in server RAM or external storage tracked by the running BoxLang applicationcookie- stored in a visitor's browserserver- stored in server RAM for ANY application for that BoxLang instancerequest- stored in RAM for a specific user request ONLYcgi- read only scope provided by the servlet container and BoxLangform- Variables submitted via HTTP postsURL- Variables incoming via HTTP GET operations or the incoming URL
Practical Persistence Examples
Scope Interaction Examples
Scope Debugging & Performance
🖥️ Server Scope
The server scope is a global scope that lives for the entire lifetime of the BoxLang runtime instance. It contains system information, BoxLang runtime details, and can store custom variables that need to persist across all applications and requests. It contains the following sub-scopes:
boxlang- BoxLang runtime informationcli- Command line execution detailsjava- Java runtime informationos- Operating system informationseparator- File system separatorssystem- System properties and environment
🏗️ Server Scope Structure
The server scope is automatically populated with several unmodifiable sub-structures:
🎯 BoxLang Information (server.boxlang)
server.boxlang)buildDate
string
Build date of the BoxLang runtime
boxlangId
string
Unique identifier for this BoxLang instance
codename
string
Release codename for this version
cliMode
boolean
Whether running in CLI mode
debugMode
boolean
Whether debug mode is enabled
jarMode
boolean
Whether running from JAR file
modules
struct
Information about loaded modules
runtimeHome
string
Path to BoxLang runtime directory
version
string
BoxLang version number
🏢 Operating System Information (server.os)
server.os)additionalinformation
string
Additional OS information
arch
string
System architecture (x86, x64, etc.)
archModel
string
Architecture model
hostname
string
Local machine hostname
ipAddress
string
Local machine IP address
macAddress
string
Local machine MAC address
name
string
Operating system name
version
string
Operating system version
☕ Java Runtime Information (server.java)
server.java)archModel
string
Architecture model
availableLocales
array
List of available locales
defaultLocale
string
Default system locale
executionPath
string
Java execution path
freeMemory
numeric
Available free memory in bytes
maxMemory
numeric
Maximum memory available in bytes
totalMemory
numeric
Total memory allocated in bytes
vendor
string
Java vendor name
version
string
Java version number
📁 File System Separators (server.separator)
server.separator)file
string
File separator character (/ or \)
line
string
Line separator character(s)
path
string
Path separator character (; or :)
💻 CLI Information (server.cli)
server.cli)args
array
Original command line arguments
command
string
Full command line used to start BoxLang
executionPath
string
Directory from which CLI was executed
parsed
struct
Parsed command line arguments
⚙️ System Properties and Environment (server.system)
server.system)environment
struct
System environment variables (if security allows)
properties
struct
Java system properties (if security allows)
Security Note: The server.system scope content depends on the populateServerSystemScope security setting. When disabled, both environment and properties will be empty structs.
🔧 Custom Server Variables
You can store your own variables in the server scope for cross-application persistence:
🔒 Unmodifiable Keys
The following keys cannot be modified once the server scope is initialized:
boxlang- BoxLang runtime informationos- Operating system informationjava- Java runtime informationseparator- File system separatorssystem- System properties and environment
🌐 CGI Scope
The CGI scope is a read-only scope available only in web runtimes that contains HTTP request information and server environment variables. It provides access to web server and request details following the Common Gateway Interface standard.
📡 Request Information
🖥️ Server Information
👤 Client Information
📂 File Path Information
🌐 HTTP Headers
The CGI scope automatically provides access to all HTTP headers using the http_ prefix:
🔍 CGI Scope Behavior
🔐 Security and SSL Information
📊 Available CGI Variables
The CGI scope provides access to these standard variables:
auth_password
HTTP authentication password
auth_type
HTTP authentication type
auth_user
HTTP authenticated username
bx_template_path
BoxLang template physical path
cf_template_path
CFML-compatible template path
content_length
Request content length
content_type
Request content type
context_path
Web application context path
gateway_interface
CGI version
http_*
All HTTP headers with http_ prefix
https
Whether request is secure
local_addr
Server IP address
local_host
Server hostname
path_info
Additional path information
path_translated
Physical path of template
query_string
URL query parameters
remote_addr
Client IP address
remote_host
Client hostname
remote_user
Authenticated remote user
request_method
HTTP method (GET, POST, etc.)
request_url
Complete request URL
script_name
Request URI
server_name
Server hostname
server_port
Server port number
server_port_secure
Secure server port
server_protocol
HTTP protocol version
🚫 Client Scope
The client scope is not supported in core BoxLang. This is a CFML legacy scope that is only available via our bx-compat-cfml module. If you would like to use it, please install the module.
Last updated
Was this helpful?
