Written by

IRIS Developer Advocate, Software developer at CaretDev, Tabcorp
Article Dmitry Maslennikov · Oct 5 5m read

The Wait Is Over: Welcome GoLang Support for InterSystems IRIS

Introduction

The InterSystems IRIS Data Platform has long been known for its performance, interoperability, and flexibility across programming languages. For years, developers could use IRIS with Python, Java, JavaScript, and .NET — but Go (or Golang) developers were left waiting.

Golang Logo

That wait is finally over.

The new go-irisnative driver brings GoLang support to InterSystems IRIS, implementing the standard database/sql API. This means Go developers can now use familiar database tooling, connection pooling, and query interfaces to build applications powered by IRIS.


Why GoLang Support Matters

GoLang is a language designed for simplicity, concurrency, and performance — ideal for cloud-native and microservices-based architectures. It powers some of the world’s most scalable systems, including Kubernetes, Docker, and Terraform.

Bringing IRIS into the Go ecosystem enables:

  • Lightweight, high-performance services using IRIS as the backend.
  • Native concurrency for parallel query execution or background processing.
  • Seamless integration with containerized and distributed systems.
  • Idiomatic database access through Go’s database/sql interface.

This integration makes IRIS a perfect fit for modern, cloud-ready Go applications.


Getting Started

1. Installation

go get github.com/caretdev/go-irisnative

2. Connecting to IRIS

Here’s how to connect using the standard database/sql API:

import (
    "database/sql""fmt""log"
    _ "github.com/caretdev/go-irisnative"
)

funcmain() {
    db, err := sql.Open("iris", "iris://_SYSTEM:SYS@localhost:1972/USER")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    // Simple ping to test connectionif err := db.Ping(); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    fmt.Println("Connected to InterSystems IRIS!")
}

3. Creating a Table

Let’s create a simple demo table:

_, err = db.Exec(`CREATE TABLE IF NOT EXISTS demo (
    id INT PRIMARY KEY,
    name VARCHAR(50)
)`)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Table created.")

4. Inserting Data

At this time, multi-row inserts are not supported — insert one row per call:

_, err = db.Exec(`INSERT INTO demo (id, name) VALUES (?, ?)`, 1, "Alice")
if err != nil {
    log.Fatal(err)
}

_, err = db.Exec(`INSERT INTO demo (id, name) VALUES (?, ?)`, 2, "Bob")
if err != nil {
    log.Fatal(err)
}

fmt.Println("Data inserted.")

5. Querying Data

Querying is straightforward using the database/sql interface:

rows, err := db.Query(`SELECT id, name FROM demo`)
if err != nil {
    log.Fatal(err)
}
defer rows.Close()

for rows.Next() {
    var id intvar name stringif err := rows.Scan(&id, &name); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("ID: %d, Name: %s\n", id, name)
}

That’s all you need to perform basic SQL operations from Go.


How It Works

Under the hood, the go-irisnative driver uses the IRIS Native API for efficient, low-level communication with the database. The driver implements Go’s standard database/sql/driver interfaces, making it compatible with existing Go tools such as:

  • sqlx
  • gorm (with a custom dialect)
  • Standard Go migration tools

This gives developers a familiar API with the power and performance of native IRIS access.


Example Use Cases

  • Microservices — lightweight Go services connecting directly to IRIS.
  • Data APIs — expose REST or gRPC endpoints backed by IRIS.
  • Integration tools — bridge IRIS data with other systems in Go-based pipelines.
  • Cloud-native IRIS apps — deploy IRIS-backed Go apps on Kubernetes or Docker.

Testing with Testcontainers

If you want to run automated tests without managing a live IRIS instance, you can use testcontainers-iris-go.
It launches a temporary IRIS container for integration testing.

Example test setup:

import (
    "context""database/sql""flag""log""os""testing"
    iriscontainer "github.com/caretdev/testcontainers-iris-go""github.com/stretchr/testify/require""github.com/testcontainers/testcontainers-go"
)

var connectionString string = "iris://_SYSTEM:SYS@localhost:1972/USER"var container *iriscontainer.IRISContainer = nilfuncTestMain(m *testing.M) {
    var (
        useContainer   bool
        containerImage string
    )
    flag.BoolVar(&useContainer, "container", true, "Use container image.")
    flag.StringVar(&containerImage, "container-image", "", "Container image.")
    flag.Parse()
    var err error
    ctx := context.Background()
    if useContainer || containerImage != "" {
        options := []testcontainers.ContainerCustomizer{
            iriscontainer.WithNamespace("TEST"),
            iriscontainer.WithUsername("testuser"),
            iriscontainer.WithPassword("testpassword"),
        }
        if containerImage != "" {
            container, err = iriscontainer.Run(ctx, containerImage, options...)
        } else {
            // or use default docker image
            container, err = iriscontainer.RunContainer(ctx, options...)
        }
        if err != nil {
            log.Println("Failed to start container:", err)
            os.Exit(1)
        }
        defer container.Terminate(ctx)
        connectionString = container.MustConnectionString(ctx)
        log.Println("Container started successfully", connectionString)
    }

    var exitCode int = 0
    exitCode = m.Run()

    if container != nil {
        container.Terminate(ctx)
    }
    os.Exit(exitCode)
}

funcopenDbWrapper[Trequire.TestingT](t T, dsn string) *sql.DB {
    db, err := sql.Open(`intersystems`, dsn)
    require.NoError(t, err)
    require.NoError(t, db.Ping())
    return db
}

funccloseDbWrapper[Trequire.TestingT](t T, db *sql.DB) {
    if db == nil {
        return
    }
    require.NoError(t, db.Close())
}

funcTestConnect(t *testing.T) {
    db := openDbWrapper(t, connectionString)
    defer closeDbWrapper(t, db)

    var (
        namespace string
        username  string
    )
    res := db.QueryRow(`SELECT $namespace, $username`)
    require.NoError(t, res.Scan(&namespace, &username))
    require.Equal(t, "TEST", namespace)
    require.Equal(t, "testuser", username)
}

This is ideal for CI/CD pipelines or unit tests, ensuring your Go application works seamlessly with IRIS in isolation.


Conclusion

GoLang support for InterSystems IRIS is here — and it’s a game-changer.
With go-irisnative, you can now build scalable, concurrent, and cloud-native applications that tap directly into the power of IRIS.

Whether you’re building microservices, APIs, or integration tools, Go gives you simplicity and performance, while IRIS gives you reliability and rich data capabilities.

👉 Try it out:

Comments

Lukas Svoboda · Oct 6

You have no idea, how happy this makes me. This is going to simplify and speed up my IRIS Architecture dramatically. THIS IS A GAME CHANGER! Yay! 

0
Rob Tweed · Oct 12

Just to set the record straight: we've had a GoLang adapter for Cache/IRIS available since 2019:

https://github.com/chrisemunt/mg_go

Also for Node.js and Bun.js, PHP, Ruby and others.  Check Chris's repository on Github.

0
John Murray · Oct 12

I am curious to know which of the published and supported IRIS Native APIs this (the go-irisnative package) leverages.

0
Dmitry Maslennikov  Oct 12 to John Murray

It does not use any already published, it adds a new one for Go, works directly with port 1972

0
John Murray  Oct 12 to Dmitry Maslennikov

Ah, so I assume you reverse engineered the unpublished TCP protocol that the published Native API packages use, right? 

0
Dmitry Maslennikov  Nov 5 to Lukas Svoboda

I closed it. My contest app was removed for no reason, even after I won, so there's no reason to keep it open.

0
Lukas Svoboda  Nov 5 to Dmitry Maslennikov

I'm confused, does that mean your not supporting the driver anymore? 

0
Lukas Svoboda  Nov 5 to Lukas Svoboda

I've been using it a fair bit and go a bit of feedback on it and would like to help support the native go driver. I see GORM is still open though so I'm confused the goirisnative repo disappeared

0
Dmitry Maslennikov  Nov 5 to Lukas Svoboda

That's great to hear, I hope we can resolve this soon.

0
Dmitry Maslennikov  Nov 5 to Lukas Svoboda

Still support, for sure, contact me directly, i.can help with implementing it. 

0
Guillaume Rongier  Nov 6 to Rob Tweed

Hi @Rob Tweed,

I actually prefer @Dmitry Maslennikov ’s approach. His method uses the official server port, which provides a more secure setup (can't do thing that are not plan).

Relying on a third-party server that opens remote connections to the IRIS server could be risky, since it’s harder to control ( can permit things that should not be able to do remotely without the right permissions ) and could effectively act like a back door.

0
Rob Tweed  Nov 6 to Guillaume Rongier

The problem is that the official superserver API is proprietary and unpublished - Dmitry reverse-engineered it which is not advisable for production use (and I doubt if it get's InterSystems' blessing): that's why Chris didn't take that approach and built his own.  You should note that Chris's interfaces have been used extensively in production systems without any security issues: there's no reason his approach should be any less secure.  It would, however, be good if InterSystems published their superserver API for third-party use: I am sure Chris would then adopt that instead.

0
Dmitry Maslennikov  Nov 6 to Rob Tweed

What I did is just copied the logic from Python to Go, nothing else. It does not require reverse engineering, because it's written in pure python. I did not decompile anything.

Nothing is actually close, undocumented yes. Anyone can read that code and repeat what I did.

0
Chris Munt  Nov 8 to Guillaume Rongier

Any server fronting access to a database can be abused and to say one is better/worse than the other with regards security is a specious argument to say the least.  For example, Dmitry has been able to easily get third-party access to the IRIS server by using an easily observable, though unpublished, protocol offered by InterSystems own server.  Presumably, a malicious developer would be able to do the same.  Of course, the same would be true of our server.

As Rob has mentioned, the reason why we don't use the InterSystems superserver is that the protocol is unpublished and, as far as I know, permission for third party products to use it has not been granted.  That, in itself, would be enough to ring alarm bells with the customers that we deal with.  Also, InterSystems have the right to change their protocol, or restrict access to it downstream - and without notice.

0
Dmitry Maslennikov  Nov 7 to Rob Tweed

Aside already mentioned above. This implementation does not work with SQL in IRIS, it was made to work the same for IRIS and for YottaDB and co.

But in most cases what's needed for new developers is SQL

0
Chris Munt  Nov 8 to Dmitry Maslennikov

Our mg_go interface (in common with all our other language bindings) can invoke M functions and Cache/IRIS class methods - the latter being only available for InterSystems platforms of course.  SQL statements can be embedded in those functions/methods.  So mg_go can work with SQL, albeit indirectly through functions/class methods.  Those wanting a purist SQL interface would probably be more comfortable with a JDBC/ODBC solution.

0
Zion Amsalem · Nov 5

Amazing!

Go support can really leveraged Iris DB

0
Lukas Svoboda  Nov 5 to Zion Amsalem

I've been working with since he released it go and it's excellent. 

0