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.

All BoxLang scopes are implemented as BoxLang structures, basically case-insensitive maps behind the scenes.

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.

// Examples

/**
 * Get the state representation of the scheduler task
 */
function getMemento(){
	// I can do a filter on an entire scope
	return variables.filter( ( key, value ) => {
		return isCustomFunction( value ) || listFindNoCase( "this", key ) ? false : true;
	} );
}


// Argument binding
results = matchClassRules( argumentCollection = arguments );
results = matchClassRules( argumentCollection = myMap );

// I can dump entire scopes
writedump( variables )

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.

function getData(){
	// Placed in the function's local scope
	var data = "luis"
	// Also placed in the function's local scope
	data = "luis"
	// Also placed in the function's local scope
	local.data = "luis"
}

📄 Template/Scripts (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.

a = "hello"
writeOutput( a )

// Is the same as
variables.a = "hello"
writeOutput( variables.a )

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

  • local - Function-scoped variables only exist within the function execution. Referred to as var scoping. The default assignment scope in a function.

  • arguments - Incoming variables to a function

function sayHello( required name ){
    var fullName = "Hello #arguments.name#"
    // case insensitive
    return FULLNAME
}

writeOutput( sayHello( "luis" ) )

🗳️ Classes (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 only

  • this - Public scope, visible from the outside world and a self-reference internally

  • static - Store variables in the classes blueprint and not the instance

  • super- Only available if you use inheritance

class extends="MyParent"{

    static {
        className = "MyClass"
    }

    variables.created = now()
    this.PUBLIC = "Hola"

    function init(){
        super.init()
    }

    function main(){
        println( "hello #static.className#" )
    }

}

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.

  • Private Function

    • variables

  • Public or Remote Functions

    • variables

    • this

// Try it out
class {

    function main(){
        writedump( var: this, label: "public" );
        writedump( var: variables, label: "private" );
    }

    private function test(){}
    public function hello(){}

}

⚡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 as var scoping. The default assignment scope in a function.

  • arguments - Incoming variables to a function

variables.CONSTANT = 1.4

// Define a closure that returns another function
function makeMultiplier( factor ) {
    return ( number ) => number * factor * variables.CONSTANT;
}

// Create multiplier functions using closures
double = makeMultiplier( 2 )
triple = makeMultiplier( 3 )

// Call the closure functions
println( double( 5 ) )  // Output: 10
println( triple( 5 ) )  // Output: 15

// Closures can also capture outer variables
function counter() {
    var count = 0;
    return () => {
        count++
        return count
    };
}

increment = counter()
println( increment() )  // Output: 1
println( increment() )  // Output: 2
println( increment() )  // Output: 3

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

  1. Simplicity – Because lambdas are context-free, they are lightweight and predictable. They only operate on the arguments explicitly 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.

  2. 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 as var scoping. The default assignment scope in a function.

  • arguments - Incoming variables to a function

// Define a simple lambda that squares a number
square = (x) -> x * x

println( square( 4 ) ) // Output: 16
println( square( 5 ) ) // Output: 25

// Lambda that adds two numbers
add = (a, b) -> a + b

println( add( 10, 20 ) ) // Output: 30

// Using a lambda to filter even numbers
numbers = [1, 2, 3, 4, 5, 6]
evens = numbers.filter( (n) -> n % 2 == 0 )

println( evens ) // Output: [2, 4, 6]


// Sorting a list in descending order
numbers = [3, 1, 4, 1, 5, 9]
numbers.sort( (a, b) -> b - a )

println( numbers ) // Output: [9, 5, 4, 3, 1, 1]

The following will throw an exception as it will try to reach outside of itself:

function testLambdaScope() {
    localVar = "I am local"

    // This lambda will fail because it tries to access localVar
    brokenLambda = () -> localVar

    println( brokenLambda() ) // This will cause an error
}

testLambdaScope()

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

// Call a component using script
bx:component template="path/MyComponent.bxm" name="luis"{
    // Content here or more component calls or whatever
}

Or you can invoke it using templating syntax, which is closer to traditional custom tags:

<!-- Templating syntax: call a component -->
<bx:component template="path/MyComponent.bxm" name="luis">
    Inner content, text, or other nested components
</bx:component>

🧵 Thread

When you create threads with the threadcomponent, you will have these scopes available to you:

  • attributes - Passed variables via a thread

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

  • variables - The surrounding declared template or class variablesscope

  • this- The surrounding declared class scope

bx:thread
    name="exampleThread"
    message="Hello from the thread!"
{

    // You can use var, local or none
    var incomingMessage = attributes.message

    // Defining local variables inside the thread
    local.threadLocalVar = "This is a local thread variable"
    threadLocalVar2 = "Another local var"

    // Setting variables in the thread scope (can be accessed after completion)
    // Only this thread can write to it.
    thread.finalMessage = "Thread has completed execution!"
    thread.calculationResult = 42

    println( "Thread is running..." )
    println( "Incoming Message: " & incomingMessage )
    println( "Local Variable in Thread: " & threadLocalVar )
}

// Wait for the thread to finish before accessing thread scope variables
threadJoin( "exampleThread" )

// Accessing thread scope variables after execution
println( "Thread Final Message: " & bxthread.exampleThread.finalMessage )
println( "Thread Calculation Result: " & exampleThread.calculationResult )

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

  • Each thread key contains metadata and variables set from within that thread

// Creating multiple threads
bx:thread name="dataProcessor" id="123" {
    thread.processedData = "Data processed for ID: #attributes.id#"
    thread.timestamp = now()
}

bx:thread name="emailSender" recipient="[email protected]" {
    thread.emailSent = true
    thread.recipient = attributes.recipient
    thread.sentAt = now()
}

// Wait for threads to complete
threadJoin( "dataProcessor,emailSender" )

// Access thread data from anywhere using bxThread scope
println( "Data Processor Result: " & bxThread.dataProcessor.processedData )
println( "Email Status: " & bxThread.emailSender.emailSent )
println( "Email Recipient: " & bxThread.emailSender.recipient )

// You can also iterate over all threads in the current request
for( threadName in bxThread ) {
    println( "Thread: #threadName# completed at #bxThread[threadName].timestamp#" )
}

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

  • local - Function-scoped variables

  • arguments - Function arguments

  • application - Application-wide persistence (requires Application.bx)

  • session - Session persistence (requires Application.bx)

  • request - Request-scoped variables

  • server - Server-wide persistence across all applications

  • thread - Thread-specific variables

  • bxThread - Global thread metadata scope

// CLI Example - Only core scopes available
server.appName = "My CLI App"
request.startTime = now()
application.version = "1.0.0" // Requires Application.bx

println( "Running in CLI mode with core scopes only" )

🕸️ 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 URL

  • form - HTTP POST form data

  • cgi - Server and request environment variables

  • cookie - Browser cookies

  • bxFile - File upload information (during file uploads)

  • bxHttp - HTTP request/response data (during HTTP operations)

// Web Example - Full scope access
url.debug = "true"  // From: myapp.com?debug=true
form.username = "john.doe"  // From POST form
cookie.preferences = "dark-mode"  // Browser cookie
cgi.remote_addr = "192.168.1.1"  // Client IP address

println( "Running in web mode with full scope access" )
println( "Client IP: #cgi.remote_addr#" )
println( "Debug Mode: #url.debug#" )

Runtime Detection: You can check your runtime context using server.boxlang.runtime.name to conditionally access web scopes.

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

  1. Local (Functions only)

  2. Arguments (Functions only)

  3. Attributes (Components only)

  4. Thread local (inside threads only)

  5. Query (variables in active query loops)

  6. Thread

  7. Variables

If the runtime is web-based, it will also check these scopes last:

  1. CGI

  2. URL

  3. Form

  4. Cookie

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

// Class scope with final variables
class {
    final variables.API_VERSION = "1.0"
    final this.MAX_RETRIES = 3
    final static.COMPANY_NAME = "Ortus Solutions"

    function init() {
        final local.instanceId = createUUID()

        // This would throw an error:
        // API_VERSION = "2.0"  // Cannot reassign final variable

        return this
    }
}

// Function scope with final variables
function processData( required data ) {
    final var startTime = now()
    final local.processId = createUUID()

    // Process data here...

    // These would throw errors:
    // startTime = now()  // Cannot reassign final variable
    // processId = "new-id"  // Cannot reassign final variable

    return {
        "processId" : processId,
        "duration" : dateDiff( "s", startTime, now() )
    }
}

// Persistence scopes with final variables
final application.appVersion = "1.0.0"
final session.userType = "premium"
final request.requestId = createUUID()

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

  • application - stored in server RAM or external storage tracked by the running BoxLang application

  • cookie - stored in a visitor's browser

  • server - stored in server RAM for ANY application for that BoxLang instance

  • request - stored in RAM for a specific user request ONLY

  • cgi - read only scope provided by the servlet container and BoxLang

  • form - Variables submitted via HTTP posts

  • URL - Variables incoming via HTTP GET operations or the incoming URL

Practical Persistence Examples

// 🔧 Server Scope - Cross-application persistence
server.startupTime = now()
server.totalRequests = ( server.totalRequests ?: 0 ) + 1
server.sharedCache = {}

// 📱 Application Scope - Application-wide data
application.version = "2.1.0"
application.userCount = 0
application.settings = {
    "debugMode" : false,
    "maxUsers" : 1000
}

// 👤 Session Scope - User-specific data (Web only)
session.userId = "user123"
session.preferences = {
    "theme" : "dark",
    "language" : "en"
}
session.shoppingCart = []

// 🍪 Cookie Scope - Browser-stored data (Web only)
cookie.lastVisit = now()
cookie.userPrefs = "theme=dark;lang=en"
// Set cookie with options
bx:cookie name="sessionToken" value="abc123" expires="30" secure="true"

// 📨 Request Scope - Single request data
request.startTime = now()
request.userAgent = cgi.http_user_agent
request.processingSteps = []

// 📊 CGI Scope - Read-only server/request info (Web only)
println( "Client IP: #cgi.remote_addr#" )
println( "Request Method: #cgi.request_method#" )
println( "User Agent: #cgi.http_user_agent#" )
println( "Server Name: #cgi.server_name#" )

// 📝 Form Scope - POST data (Web only)
if( structKeyExists( form, "username" ) ) {
    println( "Username submitted: #form.username#" )
    println( "Email: #form.email#" )
}

// 🔗 URL Scope - GET parameters (Web only)
if( structKeyExists( url, "action" ) ) {
    switch( url.action ) {
        case "login":
            // Handle login
            break
        case "logout":
            // Handle logout
            break
    }
}

Scope Interaction Examples

// Copy data between scopes
session.userPreferences = duplicate( form )

// Merge scopes
request.allData = {}
structAppend( request.allData, url )
structAppend( request.allData, form )

Scope Debugging & Performance

// Debugging scopes - dump entire scopes
writeDump( var=variables, label="Variables Scope" )
writeDump( var=session, label="Session Data", top=10 )
writeDump( var=application, label="App Settings" )

// Check scope contents
if( structIsEmpty( session ) ) {
    println( "No session data found" )
}

// Performance - scope size monitoring
function getScopeInfo() {
    return {
        "variablesCount" : structCount( variables ),
        "sessionSize" : structCount( session ),
        "applicationKeys" : structKeyArray( application ),
        "requestMemory" : structCount( request )
    }
}

// Scope iteration for debugging
for( key in variables ) {
    if( isCustomFunction( variables[key] ) ) {
        println( "Function found: #key#" )
    }
}

// Performance best practices
function efficientScopeUsage() {
    // ✅ Good - explicit scoping
    local.result = variables.data.process()

    // ❌ Bad - unscoped variable (scope hunting)
    result = data.process()  // BoxLang must search scopes

    // ✅ Good - cache scope references
    local.mySession = session
    local.mySession.lastAction = now()
    local.mySession.pageViews++

    // ❌ Bad - repeated scope access
    session.lastAction = now()
    session.pageViews++
}

Performance Tip: Always scope your variables explicitly. Unscoped variables trigger scope hunting, which impacts performance, especially in complex applications.

🖥️ 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 information

  • cli - Command line execution details

  • java - Java runtime information

  • os - Operating system information

  • separator - File system separators

  • system - System properties and environment

🏗️ Server Scope Structure

The server scope is automatically populated with several unmodifiable sub-structures:

🎯 BoxLang Information (server.boxlang)

Key
Type
Description

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

// BoxLang runtime information
println( "BoxLang Version: #server.boxlang.version#" )
println( "Codename: #server.boxlang.codename#" )
println( "Build Date: #server.boxlang.buildDate#" )
println( "Runtime Home: #server.boxlang.runtimeHome#" )
println( "CLI Mode: #server.boxlang.cliMode#" )
println( "Debug Mode: #server.boxlang.debugMode#" )
println( "JAR Mode: #server.boxlang.jarMode#" )

// Access loaded modules
writeDump( server.boxlang.modules )

🏢 Operating System Information (server.os)

Key
Type
Description

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

// Operating system details
println( "OS Name: #server.os.name#" )
println( "OS Version: #server.os.version#" )
println( "Architecture: #server.os.arch#" )
println( "Hostname: #server.os.hostname#" )
println( "IP Address: #server.os.ipAddress#" )
println( "MAC Address: #server.os.macAddress#" )

☕ Java Runtime Information (server.java)

Key
Type
Description

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

// Java environment details
println( "Java Version: #server.java.version#" )
println( "Java Vendor: #server.java.vendor#" )
println( "Available Memory: #server.java.freeMemory# bytes" )
println( "Max Memory: #server.java.maxMemory# bytes" )
println( "Total Memory: #server.java.totalMemory# bytes" )
println( "Default Locale: #server.java.defaultLocale#" )

// Available locales
for( locale in server.java.availableLocales ) {
    println( "Locale: #locale#" )
}

📁 File System Separators (server.separator)

Key
Type
Description

file

string

File separator character (/ or \)

line

string

Line separator character(s)

path

string

Path separator character (; or :)

// File system separators
println( "Path Separator: #server.separator.path#" )
println( "File Separator: #server.separator.file#" )
println( "Line Separator: #server.separator.line#" )

💻 CLI Information (server.cli)

Key
Type
Description

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

// CLI execution details (only available in CLI mode)
if( server.boxlang.cliMode ) {
    println( "Execution Path: #server.cli.executionPath#" )
    println( "Command: #server.cli.command#" )
    writeDump( server.cli.args )
    writeDump( server.cli.parsed )
}

⚙️ System Properties and Environment (server.system)

Key
Type
Description

environment

struct

System environment variables (if security allows)

properties

struct

Java system properties (if security allows)

// System environment and properties (if security allows)
// Check security setting: populateServerSystemScope
if( !structIsEmpty( server.system.environment ) ) {
    println( "Environment Variables Available" )
    println( "PATH: #server.system.environment.PATH#" )
}

if( !structIsEmpty( server.system.properties ) ) {
    println( "System Properties Available" )
    println( "Java Home: #server.system.properties['java.home']#" )
}

🔧 Custom Server Variables

You can store your own variables in the server scope for cross-application persistence:

// Store custom server-wide data
server.appStartTime = now()
server.requestCounter = 0
server.globalSettings = {
    "maintenance" : false,
    "debugEnabled" : true
}

// Increment request counter
server.requestCounter++

// Check maintenance mode across applications
if( server.globalSettings.maintenance ) {
    abort "System is under maintenance"
}

🔒 Unmodifiable Keys

The following keys cannot be modified once the server scope is initialized:

  • boxlang - BoxLang runtime information

  • os - Operating system information

  • java - Java runtime information

  • separator - File system separators

  • system - System properties and environment

// These will throw errors after initialization:
// server.boxlang = "modified"  // ❌ Cannot modify
// server.os.name = "custom"    // ❌ Cannot modify

// But this is allowed:
server.customData = "allowed"  // ✅ Custom keys are allowed

🌐 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

// Basic request details
println( "Request Method: #cgi.request_method#" )     // GET, POST, PUT, etc.
println( "Request URL: #cgi.request_url#" )           // Full request URL
println( "Script Name: #cgi.script_name#" )           // Request URI
println( "Query String: #cgi.query_string#" )         // URL parameters
println( "Path Info: #cgi.path_info#" )               // Additional path info

// Content information
println( "Content Type: #cgi.content_type#" )         // Request content type
println( "Content Length: #cgi.content_length#" )     // Request body size

🖥️ Server Information

// Server details
println( "Server Name: #cgi.server_name#" )           // Server hostname
println( "Server Port: #cgi.server_port#" )           // Server port
println( "Server Protocol: #cgi.server_protocol#" )   // HTTP/1.1, HTTP/2, etc.
println( "Server Port Secure: #cgi.server_port_secure#" ) // Secure port if HTTPS

// Local server information
println( "Local Address: #cgi.local_addr#" )          // Server IP address
println( "Local Host: #cgi.local_host#" )             // Server hostname

👤 Client Information

// Client/remote details
println( "Remote Address: #cgi.remote_addr#" )        // Client IP address
println( "Remote Host: #cgi.remote_host#" )           // Client hostname
println( "Remote User: #cgi.remote_user#" )           // Authenticated user

// Request security
println( "HTTPS: #cgi.https#" )                       // Boolean - is secure
println( "HTTP Host: #cgi.http_host#" )               // Host header with port

📂 File Path Information

// Template and path information
println( "Template Path: #cgi.cf_template_path#" )    // Absolute template path
println( "BX Template Path: #cgi.bx_template_path#" ) // BoxLang template path
println( "Path Translated: #cgi.path_translated#" )   // Physical path

🌐 HTTP Headers

The CGI scope automatically provides access to all HTTP headers using the http_ prefix:

// Common HTTP headers
println( "User Agent: #cgi.http_user_agent#" )        // Browser/client info
println( "Accept: #cgi.http_accept#" )                 // Accepted content types
println( "Accept Language: #cgi.http_accept_language#" ) // Language preferences
println( "Accept Encoding: #cgi.http_accept_encoding#" ) // Compression support
println( "Connection: #cgi.http_connection#" )         // Connection type
println( "Referer: #cgi.http_referer#" )              // Referring page
println( "Cookie: #cgi.http_cookie#" )                // Cookie header

// Custom headers are also accessible
println( "Authorization: #cgi.http_authorization#" )   // Auth header
println( "X-Forwarded-For: #cgi.http_x_forwarded_for#" ) // Proxy headers

🔍 CGI Scope Behavior

// CGI scope never throws errors - returns empty string for missing keys
println( "Non-existent key: '#cgi.nonexistent#'" )    // Returns: ""

// Check if keys exist
if( len( cgi.http_user_agent ) ) {
    println( "User agent is available" )
}

// Iterate over all CGI variables
for( key in cgi ) {
    println( "#key#: #cgi[key]#" )
}

// Dump all CGI information
writeDump( var=cgi, label="CGI Scope" )

🔐 Security and SSL Information

// SSL/TLS certificate information (when available)
println( "Auth Type: #cgi.auth_type#" )               // Authentication method
println( "Auth User: #cgi.auth_user#" )               // Authenticated username
println( "Cert Issuer: #cgi.cert_issuer#" )           // Certificate issuer
println( "Cert Subject: #cgi.cert_subject#" )         // Certificate subject
println( "Cert Key Size: #cgi.cert_keysize#" )        // Certificate key size

// HTTPS specific information
if( cgi.https == "on" ) {
    println( "HTTPS Key Size: #cgi.https_keysize#" )
    println( "HTTPS Secret Key Size: #cgi.https_secretkeysize#" )
}

📊 Available CGI Variables

The CGI scope provides access to these standard variables:

Variable
Description

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.

# Using OS CLI
install-bx-module bx-compat-cfml

# Using CommandBox
box bx-compat-cfml

Last updated

Was this helpful?