- Write a RESTful API with Ballerina
- Write a gRPC service with Ballerina
- Write a GraphQL API with Ballerina
- Work with data using queries in Ballerina
- Build a data service in Ballerina
- Build a Change Data Capture (CDC) service in Ballerina
- Work with Large Language Models (LLMs) using natural expressions
- Deploy Ballerina on Kubernetes
- Manage data persistence with bal persist
- Create your first connector with Ballerina
This Ballerina Style Guide aims at maintaining a standard coding style among the Ballerina community. Therefore, the Ballerina code formatting tools are based on this guide.
Indentation and line length
-
Use four spaces (not tabs) for each level of indentation.
-
Keep the maximum length of a line to 120 characters.
Note: You can configure tools and plugins to use spaces when indenting and to change the maximum number of characters in a line.
Line spacing
-
Use only a single space to separate keywords, types, and identifiers.
Do's
public function getFullName() returns string { string fullName = "john doe"; return fullName; }Don'ts
public function getFullName() returns string { string fullName = "john doe"; return fullName; }Few exceptions for this rule are:
-
Do not keep spaces around a type when it is enclosed using angle brackets
<string>.Example,
map<string> names = {}; -
Do not keep spaces between the type and the opening bracket in the array definition
string[].Example,
string[] names = [];
-
If it is a list of values separated by commas, add only a single space after each comma and don't add spaces before the comma.
Example,
[string, int, boolean] tupleVar = ["", 0, false]; int[] arrayOfInteger = [1, 2, 3, 4]; map<string> stringMap = {one: st1, two: st2, three: st3}; Person personRecord = {name: "marcus", id: 0}; function foo(string name, int id) { } service / on ep1, ep2 { ... }
Blank lines
-
Separate both statements and top-level definitions by zero or one blank lines.
Example,
import ballerina/http; import ballerina/io; const string CITY = "Colombo"; const int CITY_NO = 1; function getName() returns string { string firstName = "john"; string lastName = "doe"; return firstName + lastName; } function setName(string name) { } function setAge(int age) { }
Blocks
-
Opening curly braces of a block should be placed inline.
Do's
if valid { } function setName(string name) { ... }Don'ts
if valid { } function setName(string name) { } -
Add a single space before the opening curly braces.
Example,
function func1() { if valid { } } -
If an inline block is empty, do not keep spaces in between the opening and closing braces.
Example,
function func1() { } -
Indent all the statements inside a block to be at the same level.
-
Indent the closing brace of a block to align it with the starting position of the block statement.
Example,
if valid { int x = 2; string a = "hello"; } match a { ... }
Parentheses and brackets
-
Do not have spaces after opening parenthesis/bracket and before closing parenthesis/bracket.
Example,
[string, int] tupleVar = ["", 0]; function setValue(string value) { ... } public function main() { setValue("value"); } -
To define empty parentheses/brackets, do not keep spaces between the opening and closing parentheses/brackets. i.e.
(),[].Example,
int[] a = []; int|() result = getResult();
Line breaks
-
Have only one statement in a line.
-
When splitting lines, which contain operator(s), split them right before an operator.
Example,
// Binary operations. string s = "added " + People.name + " in to database."; // Function invocation. string s = person .getName(); // Binary operations in if condition if isNameAvailable && i == 1 { ... } -
When splitting lines, which contains separator(s), split them right after a separator.
Example,
// Function parameters. function getName(int id, int age, string searchValue) returns string { ... } -
If there isn't any operator or separator to break the line from, move the whole expression to a new line.
Example,
// String literal. string s1 = "My name is not in this description"; // Function invocation. string s2 = getPersonNameWithUpperCaseLetters(); -
If a line exceeds the maximum line length, start from the end of the line and come towards the start of the line until you find a point, which matches the above rules to break the line.
-
Indent split lines with relation to the starting position of the statement or definition.
Example,
if isNameAvailable && i == 1 { ... } // Function parameters. function getName(int id, int age, string searchValue) returns string { ... } -
However, if you cannot add the type-casting expression or statement with the constrained type in a single line due to it exceeding the max line length,
-
move the casting type with the operators to a new line.
Example,
string name = <string>person.name; -
keep the constrained type on the same line by splitting the statement from a point before the constraint type.
Example,
map<int|string> registry = { name: "marcus" };
-
Logging conventions
-
The Ballerina log module has four log levels with their priority in descending order:
- ERROR: For critical issues that need immediate attention
- WARN: For potentially harmful situations
- INFO: For general information about system operation
- DEBUG: For detailed information useful during development (By default, all logs of INFO level and above are logged)
-
Choose between logging and printing:
- Use
io:printlnwhen displaying help/usage information for CLI applications - Use logging when you need:
- Diagnostic information (timestamp, module name, etc.)
- Selective silencing through log levels
- Log analytics capabilities
- Use
-
Set proper log levels based on application requirements:
// Configure different log levels for modules in Config.toml [ballerina.log] level = "WARN" [[ballerina.log.modules]] name = "myorg/mypackagename.foo" level = "DEBUG" [[ballerina.log.modules]] name = "myorg/mypackagename.bar" level = "ERROR" -
Use log raw templates for log messages that need concatenation:
// Bad practice int delay = 15; int timeout = 30; log:printInfo("Application started with delay " + delay.toString() + " seconds and timeout " + timeout.toString()); // Good practice log:printInfo(`Application started with delay ${delay} seconds and timeout ${timeout}`); -
Use key-value pairs for contextual logging:
// Good practice log:printInfo("Application started", Delay = delay, Timeout = timeout); -
Use function pointers to improve performance:
isolated function getDuration() returns float { log:printInfo("Calculating duration optimally"); return random:createDecimal() * 100.0; } // Bad practice - function executes even if debug log is disabled float duration = getDuration(); log:printDebug("Checking the duration", duration = duration); // Good practice - function executes only if debug log is enabled log:printDebug("Checking the duration", duration = getDuration); -
Avoid logging sensitive information like passwords, tokens, or personal data