Google Cloud Functions
Run BoxLang on Google Cloud Functions with the official starter and runtime
Run BoxLang handlers on Google Cloud Functions Gen 2 using the Java 21 runtime and the BoxLang GCF bridge entry point: ortus.boxlang.runtime.gcp.FunctionRunner.
This page matches the current starter project and runtime behavior.
🚀 What You Get
BoxLang handler files in
src/main/bxConvention-based routing from URI to handler class
Local HTTP server via the Google Functions Java Invoker
Deployable ZIP with handlers, config, modules, and runtime JAR
🏛️ Runtime + Starter Architecture
This experience is intentionally a combination of two projects:
Starter project (
boxlang-starter-google-functions): your app shell, handlers, tests, and Gradle tasksRuntime project (
boxlang-google-functions): the Java bridge that adapts GCF HTTP requests to BoxLang execution
The runtime entry point is:
ortus.boxlang.runtime.gcp.FunctionRunner
At execution time, the runtime handles:
HTTP request mapping into a BoxLang-friendly
eventstructroute resolution from URI to
.bxhandler fileclass compilation/loading and warm-invocation class caching
method dispatch (default
run()orx-bx-functionoverride)response mapping from BoxLang
responsestruct to GCF HTTP output
This split lets you keep all business logic in BoxLang files while using Java only as the serverless runtime bridge.
🔬 Runtime Execution Flow
⚡ Cold Start, Warm Start, and Debug Mode
Cold start: runtime initializes in the container before first request handling.
Warm invocations: compiled handler classes are reused to avoid repeated compilation work.
Debug mode (
BOXLANG_GCP_DEBUGMODE=true): class caching is disabled so handler edits are picked up quickly during development.Production guidance: keep debug mode off for best performance.
🔁 Portability Notes
The runtime keeps the handler contract familiar across serverless targets. In practice, many handler patterns can be shared between BoxLang AWS Lambda and BoxLang GCF with minimal changes.
✅ Requirements
Java
21
Google Cloud SDK (gcloud)
Latest
Gradle
Wrapper included
📦 Starter Project Setup
Use the official starter:
Run tests once to verify your environment:
🧪 Launch Locally
Start the local function server:
By default it runs on port 9099 and uses src/main/bx as the function root.
Try a request:
Call a specific method via header:
Send JSON payload:
Local overrides
Local runFunction Runner Details
runFunction Runner DetailsThe starter's runFunction Gradle task uses the official Google Functions Java Invoker and wires it to the BoxLang runtime entry point.
What it does:
launches
com.google.cloud.functions.invoker.runner.Invokerpasses
ortus.boxlang.runtime.gcp.FunctionRunneras the targetsets
BOXLANG_GCP_ROOTto your function root (default:src/main/bx)sets
BOXLANG_GCP_DEBUGMODEfrom-PdebugModeor defaultsruns on
-PtestPort(default9099)
Expected startup banner:
Runner troubleshooting:
Port in use: start with
-PtestPort=8080Wrong handlers loaded: point to the right folder with
-PfunctionRoot=...Code changes not reflected: use
-PdebugMode=trueduring developmentMissing default route: ensure
Lambda.bxexists in the configured function root
🧩 Handler Contract
Each handler method receives:
event: HTTP request data mapped into a structcontext: function metadata (name, revision, project, request id)response: mutable response struct (statusCode,headers,body,cookies)
Default method is run().
Event Struct Shape
The runtime maps each incoming HTTP request into an event struct designed for serverless portability.
Context Struct Shape
The context struct contains runtime metadata:
functionNamefunctionVersionprojectIdrequestId
Response Struct Shape
The runtime provides a mutable response struct:
Response behavior:
Returning a struct or array from your method will be JSON serialized.
Returning a plain string writes that string as the response body.
Writing to
response.bodygives explicit control over output.
Example handler
🛣️ Convention-Based Routing
The runtime supports multi-routing by resolving the first URI path segment into a PascalCase .bx handler file.
Routing algorithm:
Read the first path segment from the request URI.
Convert it to PascalCase.
Look for
<Segment>.bxunderBOXLANG_GCP_ROOT.Fall back to
Lambda.bxif no file is found.
URI to Handler Mapping
/
Lambda.bx
/customers
Customers.bx
/customers/123
Customers.bx
/products
Products.bx
/user-profiles
UserProfiles.bx
/api_endpoints
ApiEndpoints.bx
/unknown
Lambda.bx
Multi-Handler Layout
The first segment selects the class. Remaining URI segments are still available via event.path for your own parsing.
Multi-Routing Handler Example
🔀 Method Routing with x-bx-function
After URI routing resolves the handler class, method routing can choose which function to invoke.
Without header, runtime calls
run().With header, runtime attempts the named method.
This gives you two dispatch layers:
URI path selects the handler class
x-bx-functionselects the method in that class
⚙️ Runtime Environment Variables
BOXLANG_GCP_ROOT
Root directory for .bx handlers
BOXLANG_GCP_CLASS
Override default handler path
BOXLANG_GCP_DEBUGMODE
Enable verbose logging and disable class caching
BOXLANG_GCP_CONFIG
Custom boxlang.json path
K_SERVICE
Function name (set by GCF)
K_REVISION
Function revision (set by GCF)
GOOGLE_CLOUD_PROJECT
Project ID (set by GCF)
🏗️ Build Deployable Artifacts
Build the GCF package:
Output ZIP:
build/distributions/boxlang-google-function-project-<version>.zip
The ZIP includes:
.bxhandlers at ZIP rootboxlang.jsonboxlang_modules/lib/with runtime and dependencies
☁️ Deploy to Google Cloud Functions Gen 2
Authenticate and select project:
Deploy:
If you changed version in gradle.properties, update the ZIP filename in --source.
🧪 Testing
Run tests:
Run the integration test class:
Open report:
build/reports/tests/test/index.html
Unit and Integration Tests Shipped in the Starter
The starter currently ships one primary integration test class and two GCF HTTP mock classes:
src/test/java/com/myproject/FunctionRunnerTest.java
End-to-end tests of request -> BoxLang handler -> HTTP response
src/test/java/com/myproject/mocks/MockHttpRequest.java
Fluent test request builder implementing GCF HttpRequest
src/test/java/com/myproject/mocks/MockHttpResponse.java
Captures status/body/headers implementing GCF HttpResponse
FunctionRunnerTest validates:
missing handler path error behavior
default
run()execution and JSON response assertionsx-bx-functionmethod routing (anotherLambda)response headers (
Content-Type)empty headers and large-body handling
query parameter handling
concurrent invocation behavior
core accessor behavior (
getDefaultFunctionPath,inDebugMode,getRuntime)
Run only the shipped integration test:
📝 Notes
The starter currently keeps handlers in
src/main/bx, notsrc/main/resources.Local launch uses
-PtestPortand-PdebugModeflags.For this starter, deployment source is the generated ZIP in
build/distributions.
Last updated
Was this helpful?
