Program Structure
This section covers the basics of the program structures of BoxLang
📁 File Types

BoxLang can be written in 3 types of files:
Scripts (*.bxs, or in compat mode *.cfs)
Templates (*.bxm, or in compat mode *.cfm)
Classes (*.bx or in compat mode *.cfc)
Each of these files follow the same program structure with different syntaxes. The only one of these that you will write using our templating language is the templates (*.bxm)
.
📜 Scripts/Templates
Scripts and templates in BoxLang do not require a class definition and can be executed via the CLI binary directly: boxlang {script|template}
or ran by the MiniServer/CommandBox/Servlet/Etc.
Scripts
Script files have a bxs
file extension and will use script notation, but you can also use the templating language by using opening and closing tag island notations: ```
a = [1,2,3,4]
user = { name : "boxlang", id : createUUID(), age : 3 }
today = now()
```
<!--- Now I can do templating --->
<bx:output>
Today is #today#<br>
#a.toString()#<br>
#user.toString()#<br>
</bx:output>
```
// Now I am back in scripts
echo( "scripts again" )
Templates
Templates have a bxm
file extension and will use the templating language but can also use scripts via opening and closing <bx:script></bx:script>
tags.
<bx:set a = [1,2,3,4]>
<bx:set user = { name : "boxlang", id : createUUID(), age : 3 }>
<bx:script>
today = now();
</bx:script>
<bx:output>
Today is #today#<br>
#a.toString()#<br>
#user.toString()#<br>
</bx:output>
⚡ Classes
Classes have a .bx
extension and can be executed via the CLI if they have a main()
method by convention. Unlike Java or other languages, the main()
method does NOT have to be static, it can be an instance method or a static method, you chose.
class{
function main( args = [] ){
println( "BoxLang Rulez!" )
}
}
📦 Package Names
Package names are not necessary for these types of files as BoxLang will automatically create them for you. You will refer to these scripts or templates by path location or via mappings.
🗂️ Path Imports
BoxLang allows you to access any BoxLang class or script/template by location convention first with no need of imports explicitly. The following approaches can be used via path imports:
new class_path()
createObject( "class", path )
include template="path"
Any BIF that requires a path
{% hint style="info" %} The discovery is done by looking at your global, application mappings and then relative pathing. {% endhint %}
script.bxs
+ models
+ User.bx
+ scripts
+ data.bxs
Then we can do so by location reference:
// Create a new user
user = new models.User( "luis", "majano" )
println( user.getFullName() )
// Now I need to include another script here
include template="scripts/data/bxs"
These work great but the caveat is that when searching for those files and templates, BoxLang will try to discover them:
Is there a location mapping (globally or in the application)
does the file exist
use it
Works great, but yes, some lookup is done, but cached.
📁 Simple Imports
Another approach in BoxLang is to use the import
statement or the <bx:import>
template statement if you are in templates. This allows you to fully define the location of a class or template explicitly. This is also used not only for BoxLang classes but for any Java class:
import java.time.Instant;
import models.User;
import ortus.boxlang.runtime.scopes.Key;
today = Instant.now();
println( today );
myUser = new User();
caseInsensitiveKey = new Key( "luis" );
From the example above I made no distinction on what was a Java class or what was a Boxlang class. By convention BoxLang will auto-discover the class for you according to it's package path. However, you can also use object resolver notation to disambiguiate the location and define it explicitly.
{% hint style="info" %} The implicit resolver is bx
meaning a Boxlang class. You don't need to use it if you don't want to. {% endhint %}
🎯 Object Resolver Imports
BoxLang ships with two object resolver prefixes:
java:
- To demarcate a Java class pathbx:
- To demarcate a BoxLang class path
This is useful to disambiguiate paths and make them explicit. You can use it in the import or in the new() or createObject()
syntax.
import java:java.time.Instant;
import java:ortus.boxlang.runtime.scopes.Key;
import models.User;
a = Instant.now()
myUser = new User()
caseInsensitiveKey = new java:Key( "luis" )
📍 Location of Imports
In box templates and scripts you can add the import/<bx:import>
statements ANYWHERE in the file. We will collect them internally for you.
import java:java.time.Instant;
a = Instant.now()
import models.User;
myUser = new User()
import java:ortus.boxlang.runtime.scopes.Key;
caseInsensitiveKey = new java:Key( "luis" )
⭐ Star Imports
Boxlang, like Java, allows you to import all classes from a package using the *
after the last package path. All classes within that package/folder will be available for shorthand usage and reserved.
// Without star imports
import java.util.ArrayList;
import java.util.HashMap;
myList = new ArrayList()
myList.add( "apple" )
myList.add( "pear" )
myJavaMap = new HashMap()
myJavaMap.put( "name", "boxlang" )
Now let's use start imports
// Without star imports
import java.util.*;
myList = new ArrayList()
myList.add( "apple" )
myList.add( "pear" )
myJavaMap = new HashMap()
myJavaMap.put( "name", "boxlang" )
This can be for both Java and BoxLang class paths.
🏷️ Import Aliases
BoxLang allows you to alias your imports in order to break ambiguity and to be able to import classes with the same name but with different aliases.
import java.time.Instant as jInstant;
import models.User as BXUser;
import models.util.Key;
import ortus.boxlang.runtime.scopes.Key as jKey;
result = jInstant.now()
user = new BXUser()
caseInsensitiveKey = new Key( "luis" )
javaKey = new jKey( "java" )
Here is another example:
import java.util.Date;
import java.sql.Date as SQLDate;
d1 = new Date( 1000 )
d2 = new SQLDate( 1000 )
assert d1 instanceof "java.util.Date"
assert d2 instanceof "java.sql.Date"
🎮 Execution Examples
Running Scripts
# Execute a script directly
boxlang script.bxs
# Execute with arguments
boxlang script.bxs arg1 arg2 arg3
Running Templates
# Execute a template
boxlang template.bxm
# Templates can also be served via web server
# http://localhost:8080/template.bxm
Running Classes with Main Method
# Execute a class with main() method
boxlang MyClass.bx
# With arguments
boxlang MyClass.bx arg1 arg2
⚙️ Best Practices
🎯 Import Strategy
Use explicit imports for clarity and IDE support
Group imports logically (Java classes, BoxLang classes, third-party)
Use aliases to resolve naming conflicts and reduce ambiguity
Prefer specific imports over star imports for better performance
💡 Naming Conventions
Scripts:
CamelCase.bxs
(e.g.,DataProcessor.bxs
)Classes:
PascalCase.bx
(e.g.,UserService.bx
)Templates:
camelCase.bxm
(e.g.,userProfile.bxm
)
🔗 Cross-File Dependencies
// Good: Explicit and clear
import models.User;
import services.EmailService;
// Better: With aliases for clarity
import models.User as UserModel;
import external.User as ExternalUser;
🚨 Common Pitfalls
❌ Avoid These Patterns
// Don't: Ambiguous star imports
import java.util.*;
import java.sql.*;
// This can cause conflicts with Date, List, etc.
// Don't: Missing file extensions in includes
include template="scripts/helper" // Wrong
include template="scripts/helper.bxs" // Correct
✅ Preferred Patterns
// Do: Specific imports
import java.util.ArrayList;
import java.util.HashMap;
// Do: Clear aliases
import java.util.Date as JavaDate;
import java.sql.Date as SQLDate;
🔍 File Discovery Process
BoxLang follows this discovery order when resolving files:
Relative paths (from current file location)
Application mappings (defined in Application.bx)
Global mappings (server-wide configurations)
Classpath resolution (for imported classes)
📋 Mapping Example
// In Application.bx
class {
this.mappings = {
"/models": expandPath("./app/models"),
"/utils": expandPath("./shared/utilities")
};
}
// Now you can use:
import models.User; // Resolves to ./app/models/User.bx
import utils.Helper; // Resolves to ./shared/utilities/Helper.bx
Last updated
Was this helpful?