Integration is development. Why make life harder for developers to write integrations by giving them restricted drag-and-drop tools / DSLs or generic languages?

Just write the code using the only language with integration-friendly abstractions.

Download Ballerina

Position Ballerina

Solve any integration challenge

Automate anything

Automation is just code after all - write a main() and do whatever you want.

Use Ballerina's extended standard library to connect to any system, speak any protocol, process any data, and run it anywhere (on a VM, in Kubernetes, or just as a script).

Powerful data transformations that can be simultaneously programmed graphically and as code makes data integration a breeze.

Event-driven integrations

Events are core to the responsive enterprise. Ballerina makes it simple to consume or produce events.

Subscribe to any kind of event source, including WebHooks, Kafka, GraphQL, gRPC, AMQP, email, or react to system events such as file upload and do whatever you want in a type-safe development model with subscription, data binding, and error handling is already taken care of for you.

Be an event producer in any protocol you like.

Integrations as APIs

Ballerina's service creation abstractions make it simple to take any integration and make it reusable as an API.

Use Ballerina service types for HTTP services, WebSockets, GraphQL, gRPC, and more to take your integration code, parameterize it and make it a reusable integration.

APIs are the new DLLs. Exposing your integrations as APIs is how your integrated capability adds new value to your business.

Edit, debug, and run in VSCode

Tired of disjointed toolchains disrupting your workflow? Take control of your integration development with Ballerina. Realize your ideas in VSCode, use your favorite tools, and store them in Git.

Edit, debug, and run in VSCode

Network data == program data

Processing data coming or going over the wire is a no-brainer with Ballerina. Seamlessly and selectively map network data into domain types for a range of formats, including JSON, EDI, and XML.

configurable string githubPAT = ?;

type PR record {
    string url;
    string title;
    string state;
    string created_at;
    string updated_at;

public function main() returns error? {
    http:Client github = check new ("");
    map<string> headers = {
        "Accept": "application/vnd.github.v3+json",
        "Authorization": "token " + githubPAT
    // Network data == program data
    PR[] prs = check github->/octocat/Hello\-World/pulls(headers);

Incredible data transformations

Ballerina has cracked the challenge of mapping one kind of data value to another kind of data value, simultaneously as code and picture, so that both are simple, powerful, and boundless.

Incredible data transformations

GitHub Copilot, your artificially intelligent pair programmer

GitHub Copilot knows Ballerina. Why do all the work? Let Copilot do at least half of it.

GitHub Copilot, your artificially intelligent pair programmer

Resilience engineering, built-in

Ballerina’s built-in language and standard library features make programming in the failure-is-normal world of distributed systems as easy for every developer.

http:RetryConfig retryConfig = {
    interval: 3,
    count: 3,
    backOffFactor: 2.0,
    maxWaitInterval: 20
final trello:Client trello = check new (apiKeyConfig, {retryConfig});

service calendar:CalendarService on calendarListener {
    remote function onNewEvent(calendar:Event payload) returns error? {
        // Mapping from Google Calendar Event to Trello Card
        trello:Cards card = transform(payload);

        // Add the card to the Trello list
        var _ = check trello->addCards(card);

    remote function onEventDelete(calendar:Event payload) returns error? {

    remote function onEventUpdate(calendar:Event payload) returns error? {

Built-in transactions

Eventual consistency in Data integration is nice and all, but if you really need to make sure your distributed data integrations run transactionally, then Ballerina makes that effortless and mistake-free for developers with compile-time support.

type Order record {|
    string id;
    string orderDate;
    string productId;
    int quantity;

final mysql:Client db = check new (host, user, password, database, port);

function createOrder(Order 'order) returns error? {
    // Start a transaction.
    transaction {
        // Insert into `sales_order` table.
        _ = check db->execute(`INSERT INTO sales_orders VALUES (${'}, 
                ${'order.orderDate}, ${'order.productId}, ${'order.quantity})`);

        // Update product quantity as per the order.
        sql:ExecutionResult inventoryUpdate = check db->execute(`UPDATE inventory SET 
                quantity = quantity - ${'order.quantity} WHERE id = ${'order.productId}`);

        // If the product is not found, rollback or else commit the transaction.
        if inventoryUpdate.affectedRowCount == 0 {
            return error(string `Product ${'order.productId} not found.`);
        } else {
            check commit;
    } on fail error e {
        // In case of error, the transaction block is rolled back automatically.
        return error(string `Error occurred while processing the order: ${'}.`, e);

Concurrent programming made simple

Sequence diagrams have been used to model concurrency for decades. Ballerina’s concurrent programming model is sequence diagrams along with various concurrency control capabilities that make concurrent programming visual and accessible to all.

type Quote record {
    string customerName;
    string product;
    int quantity;
    decimal price;

function findBestQuote(QuoteRequest quoteReq) returns Quote {
    // The fork statement starts with one or more named workers, 
    //  which run in parallel with each other 
    fork {
        worker venderA returns Quote|error {
            http:Client venderAEP = check new (venderAURL);
            return venderAEP -> /quote.get(p = quoteReq.product, q = quoteReq.quantity);

        worker venderB returns Quote|error {
            http:Client venderBEP = check new (venderBURL);
            return venderBEP -> /quote.get(p = quoteReq.product, q = quoteReq.quantity);

        worker venderC returns Quote|error {
            http:Client venderCEP = check new (venderCURL);
            return venderCEP -> /quote.get(p = quoteReq.product, q = quoteReq.quantity);

    // Wait for all the workers to finish and collect the results.
    map<Quote|error> quotes = wait {venderA, venderB, venderC};
    return bestQuote(quotes);

Code is the picture / picture is the code

Instead of deciphering lines of code, Ballerina programs can be viewed and edited as sequence diagrams with flow charts. This makes maintaining and understanding integration applications a breeze. Code never goes out of sync with the picture and vice versa.

Code is the picture / picture is the code

Built-in observability

Every Ballerina program is automatically observable by any Open Telemetry tool, giving you complete control and visibility into the code’s behavior and performance.

Built-in observability

GraphQL? Ballerina is GraphQL

When you go beyond just toy GraphQL applications where you simply map GraphQL queries to database queries, Ballerina gives you first-class concepts to write any code that executes as part of the GraphQL query.

No GraphQL service is out of reach with Ballerina. It can create a custom-tailored, typed GraphQL client for your unique queries with ease.

final http:Client bookEp = check new ("");

service class Book {
    private final readonly & BookData bookData;

    function init(BookData bookData) {
        self.bookData = bookData.cloneReadOnly();

    resource function get isbn() returns string {
        return self.bookData.isbn;

    resource function get title() returns string {
        return self.bookData.title;

    resource function get reviews() returns Review|error {
        string isbn = self.bookData.isbn;
        GoogleBook googleBook = check bookEp->/books/v1/volumes.get(q=string `isbn:${isbn}`);
        return let var volInfo = googleBook.items[0].volumeInfo in {
                averageRating: volInfo.averageRating,
                ratingsCount: volInfo.ratingsCount,
                maturityRating: volInfo.maturityRating

service /graphql on new graphql:Listener(9090) {
    resource function get book(string isbn) returns Book? {
        BookData? data = books[isbn];
        return data is BookData ? new Book(data) : ();

    resource function get allBooks() returns Book[] {
        return from var bookData in books
            select new Book(bookData);

    remote function addBook(BookData bookData) returns Book|error {
        return new Book(bookData);

HTTP? Ballerina is HTTP

“Ballerina is HTTP on steroids.” Network abstractions in Ballerina provide a natural way to describe and consume HTTP services, allowing developers to focus on a business logic instead of boilerplate code.

configurable int port = 8080;

type Album readonly & record {|
    string id;
    string title;
    string artist;
    decimal price;

service / on new http:Listener(port) {
    resource function get albums() returns Album[] {
        return albums.toArray();

    resource function get albums/[string id]() returns Album|http:NotFound {
        Album? album = albums[id];
        if album is () {
            return http:NOT_FOUND;
        } else {
            return album;

    resource function post albums(@http:Payload Album album) returns Album {
        return album;

JSON? Ballerina is JSON

Javascript is JSON, and so is Ballerina. Plain data in Ballerina bear a natural resemblance to JSON values, simplifying the manipulation of JSON data. You can use the in-built json type if that’s your thing! Otherwise, convert to domain types for type-safe handling.

type InvoiceItem record {
    string id;
    decimal price;
    boolean taxable;

type Customer record {
    string id;
    string name;

type Invoice record {
    string id;
    Customer customer;
    InvoiceItem[] items;

public function main() returns error?{
    json invoiceData = check io:fileReadJson("./invoice.json");

    // Enjoy lax static typing here!
    // Fails at runtime if the key is not present or the value is not a string.
    string id = check;

    // Fails at runtime if the key is not present.
    json items = check invoiceData.items;

    // Converts to the domain type.
    // Fails at runtime if the json value does not match the type.
    Invoice invoice = check invoiceData.fromJsonWithType();

    // Enjoy type-safe handling of json values.
    id =;
    InvoiceItem[] invoiceItems = invoice.items;

Connect with Anything

Access thousands of connectors for HTTP APIs (OpenAPI), event APIs (AsyncAPI), GraphQL services, legacy systems, and data stores, allowing seamless data transfer to and from any system, anywhere.

Connect with Anything

12 Factor Apps for Integration Problems

Just write integration applications like any other code. Do all 12 factors (and 3 more if you like) with all your usual tools, and don’t fear.

12 Factor Apps for Integration Problems

Open Source, Zero Lock-In

Being an open-source programming language, Ballerina offers the flexibility to view, modify, and run code in any environment, thus enabling seamless migration of integration code across platforms without the need for re-implementation.

Why get stuck with lock-in integration platforms?

Open Source, Zero Lock-In

(Extra!) Trivial hosting in WSO2 Choreo iPaaS

Manual integrations? Scheduled integrations (cron jobs)? Triggered integrations? Integrations as APIs? No problem! Write the code, attach the repo to WSO2 Choreo, and let it do the rest.

(Extra!) Trivial hosting in WSO2 Choreo iPaaS